<commit_before>var XiangqiViewer = {}
window.XiangqiViewer = XiangqiViewer;

XiangqiViewer.BoardRenderer = function(element, cellSize, strokeWidth) {
  var BOARD_WIDTH = 8;
  var BOARD_HEIGHT = 9;
  var BOARD_COLOR = 'rgb(6, 120, 155)';
  var MARGIN = cellSize * 0.70;
  var XSIZE = 2;
  var PIECE_SIZE = 0.85 * cellSize;

  var width = BOARD_WIDTH * cellSize + 2*MARGIN;
  var height = BOARD_HEIGHT * cellSize + 2*MARGIN;

  var leftBorder = MARGIN;
  var rightBorder = BOARD_WIDTH * cellSize + MARGIN;
  var topBorder = MARGIN;
  var botBorder = BOARD_HEIGHT * cellSize + MARGIN;
  var riverTop = Math.floor(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var riverBot = Math.ceil(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var dotDistance = 2 * strokeWidth;

  var root = SVG('xiangqi-example').width(width).height(height);

  this.draw = function(selector) {
    // horizontal
    drawHorizontalLines();
    drawVerticalLines(topBorder, riverTop);
    drawVerticalLines(riverBot, botBorder);
    drawBorder(leftBorder);
    drawBorder(rightBorder);
    drawX(topBorder);
    drawX(botBorder - XSIZE * cellSize);

    for (var i = 2; i < 10; i += 2) {
      drawDots(i, 3, false);
      drawDots(i, 6, false);
    }

    for (var i = 0; i < 8; i += 2) {
      drawDots(i, 3, true);
      drawDots(i, 6, true);
    }
  };

  var drawBoardLine = function(x1, y1, x2, y2) {
    root.line(x1, y1, x2, y2).stroke({
      color: BOARD_COLOR,
      width: strokeWidth
    });
  };

  var drawHorizontalLines = function() {
    for (var j = 0; j < BOARD_HEIGHT + 1; j++) {
      var height = MARGIN + j * cellSize;

      drawBoardLine(leftBorder, height, rightBorder, height);
    };
  }

  var drawVerticalLines = function(top, bottom) {
    for (var j = 1; j < BOARD_WIDTH; j++) {
      var offset = MARGIN + j * cellSize;

      drawBoardLine(offset, top, offset, bottom);
    };
  }

  var drawBorder = function(x) {
    drawBoardLine(x, topBorder - strokeWidth/2, x, botBorder + strokeWidth/2);
  };

  var drawX = function(top) {
    var leftEdge = leftBorder + 3 * cellSize;
    var rightEdge = leftBorder + (3 + XSIZE) * cellSize;
    var bot = top + XSIZE * cellSize;
    drawBoardLine(leftEdge, top, rightEdge, bot);
    drawBoardLine(leftEdge, bot, rightEdge, top);
  };

  // x and y are from 0 to (n - 1)
  var drawDots = function(x, y, isRight) {
    var directionMultipler = isRight ? -1 : 1;
    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize - dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});

    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize + dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});
  };

  this.putPiece = function(x, y, piece) {
    var renderedX = MARGIN + cellSize * x - (PIECE_SIZE / 2);
    var renderedY = MARGIN + cellSize * y - (PIECE_SIZE / 2);
    root.image(piece.spriteUrl())
      .move(renderedX, renderedY)
      .attr({
        width: PIECE_SIZE,
        height: PIECE_SIZE
      });
  }

  return this;
};

XiangqiViewer.Board = function(selector, cellSize, strokeWidth) {
  var renderer = new XiangqiViewer.BoardRenderer(selector, cellSize, strokeWidth);
  renderer.draw();

  var WIDTH = 9
  var HEIGHT = 10
  var matrix;

  var initialize = function() {
    matrix = []; // rank, file; x, y

    for(var i = 0; i < WIDTH; i++) {
      matrix[i] = [];
      for(var j = 0; j < HEIGHT; j++) {
        matrix[i][j] = null;
      }
    }
  };

  var get = function(file, rank) {
    return matrix[file][rank];
  };

  var place = function(x, y, piece) {
    if (x < 0 || y < 0 || x >= WIDTH || y >= HEIGHT) {
      throw "x, y coords are out of bounds";
    }

    matrix[x][y] = piece;
    renderer.putPiece(x, y, piece);
  };

  var getPositionedPiece(instruction, red) {
    if (instruction[0] == 'f') {
    } else if (instruction[0] == 'b') {
    } else {
      var instructionPiece = instruction[0];
      var file = instruction[1];

      for (var i = 0; i < HEIGHT; i++) {
        var piece = get(file, i);
        if (piece && piece.code == instructionPiece) {
          return piece;
        }
      }

      throw "no piece on this file";
    }
  }

  this.runMove = function(instruction) {
    if (instruction.length != 4) {
      throw "illegal instruction format";
    }
    instruction = instruction.toLowerCase();

    var positionedPiece = getPositionedPiece(instruction);
    var move = positionedPiece.piece.getMove(positionedPiece.position, instruction);
    var from = move.from;
    var to = move.to;
  }

  this.defaultSetup = function() {
    place(0, 0, new XiangqiViewer.Chariot(false));
    place(1, 0, new XiangqiViewer.Horse(false));
    place(2, 0, new XiangqiViewer.Elephant(false));
    place(3, 0, new XiangqiViewer.Advisor(false));
    place(4, 0, new XiangqiViewer.General(false));
    place(5, 0, new XiangqiViewer.Advisor(false));
    place(6, 0, new XiangqiViewer.Elephant(false));
    place(7, 0, new XiangqiViewer.Horse(false));
    place(8, 0, new XiangqiViewer.Chariot(false));
    place(0, 3, new XiangqiViewer.Pawn(false));
    place(2, 3, new XiangqiViewer.Pawn(false));
    place(4, 3, new XiangqiViewer.Pawn(false));
    place(6, 3, new XiangqiViewer.Pawn(false));
    place(8, 3, new XiangqiViewer.Pawn(false));
    place(1, 2, new XiangqiViewer.Cannon(false));
    place(7, 2, new XiangqiViewer.Cannon(false));

    place(0, 9, new XiangqiViewer.Chariot(true));
    place(1, 9, new XiangqiViewer.Horse(true));
    place(2, 9, new XiangqiViewer.Elephant(true));
    place(3, 9, new XiangqiViewer.Advisor(true));
    place(4, 9, new XiangqiViewer.General(true));
    place(5, 9, new XiangqiViewer.Advisor(true));
    place(6, 9, new XiangqiViewer.Elephant(true));
    place(7, 9, new XiangqiViewer.Horse(true));
    place(8, 9, new XiangqiViewer.Chariot(true));
    place(0, 6, new XiangqiViewer.Pawn(true));
    place(2, 6, new XiangqiViewer.Pawn(true));
    place(4, 6, new XiangqiViewer.Pawn(true));
    place(6, 6, new XiangqiViewer.Pawn(true));
    place(8, 6, new XiangqiViewer.Pawn(true));
    place(1, 7, new XiangqiViewer.Cannon(true));
    place(7, 7, new XiangqiViewer.Cannon(true));
  };

  initialize();
}

XiangqiViewer.Chariot = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/chariot_red.svg";
    } else {
      return "images/chariot_black.svg";
    }
  };
};

XiangqiViewer.Horse = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/horse_red.svg";
    } else {
      return "images/horse_black.svg";
    }
  };
};

XiangqiViewer.Elephant = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/elephant_red.svg";
    } else {
      return "images/elephant_black.svg";
    }
  };
};

XiangqiViewer.Advisor = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/adviser_red.svg";
    } else {
      return "images/adviser_black.svg";
    }
  };
};

XiangqiViewer.General = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/general_red.svg";
    } else {
      return "images/general_black.svg";
    }
  };
};

XiangqiViewer.Pawn = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/pawn_red.svg";
    } else {
      return "images/pawn_black.svg";
    }
  };
};

XiangqiViewer.Cannon = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/cannon_red.svg";
    } else {
      return "images/cannon_black.svg";
    }
  };
};
<commit_msg>finish getPositionedPiece dependencies<commit_after>var XiangqiViewer = {}
window.XiangqiViewer = XiangqiViewer;

XiangqiViewer.BoardRenderer = function(element, cellSize, strokeWidth) {
  var BOARD_WIDTH = 8;
  var BOARD_HEIGHT = 9;
  var BOARD_COLOR = 'rgb(6, 120, 155)';
  var MARGIN = cellSize * 0.70;
  var XSIZE = 2;
  var PIECE_SIZE = 0.85 * cellSize;

  var width = BOARD_WIDTH * cellSize + 2*MARGIN;
  var height = BOARD_HEIGHT * cellSize + 2*MARGIN;

  var leftBorder = MARGIN;
  var rightBorder = BOARD_WIDTH * cellSize + MARGIN;
  var topBorder = MARGIN;
  var botBorder = BOARD_HEIGHT * cellSize + MARGIN;
  var riverTop = Math.floor(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var riverBot = Math.ceil(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var dotDistance = 2 * strokeWidth;

  var root = SVG('xiangqi-example').width(width).height(height);

  this.draw = function(selector) {
    // horizontal
    drawHorizontalLines();
    drawVerticalLines(topBorder, riverTop);
    drawVerticalLines(riverBot, botBorder);
    drawBorder(leftBorder);
    drawBorder(rightBorder);
    drawX(topBorder);
    drawX(botBorder - XSIZE * cellSize);

    for (var i = 2; i < 10; i += 2) {
      drawDots(i, 3, false);
      drawDots(i, 6, false);
    }

    for (var i = 0; i < 8; i += 2) {
      drawDots(i, 3, true);
      drawDots(i, 6, true);
    }
  };

  var drawBoardLine = function(x1, y1, x2, y2) {
    root.line(x1, y1, x2, y2).stroke({
      color: BOARD_COLOR,
      width: strokeWidth
    });
  };

  var drawHorizontalLines = function() {
    for (var j = 0; j < BOARD_HEIGHT + 1; j++) {
      var height = MARGIN + j * cellSize;

      drawBoardLine(leftBorder, height, rightBorder, height);
    };
  }

  var drawVerticalLines = function(top, bottom) {
    for (var j = 1; j < BOARD_WIDTH; j++) {
      var offset = MARGIN + j * cellSize;

      drawBoardLine(offset, top, offset, bottom);
    };
  }

  var drawBorder = function(x) {
    drawBoardLine(x, topBorder - strokeWidth/2, x, botBorder + strokeWidth/2);
  };

  var drawX = function(top) {
    var leftEdge = leftBorder + 3 * cellSize;
    var rightEdge = leftBorder + (3 + XSIZE) * cellSize;
    var bot = top + XSIZE * cellSize;
    drawBoardLine(leftEdge, top, rightEdge, bot);
    drawBoardLine(leftEdge, bot, rightEdge, top);
  };

  // x and y are from 0 to (n - 1)
  var drawDots = function(x, y, isRight) {
    var directionMultipler = isRight ? -1 : 1;
    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize - dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});

    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize + dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});
  };

  this.putPiece = function(x, y, piece) {
    var renderedX = MARGIN + cellSize * x - (PIECE_SIZE / 2);
    var renderedY = MARGIN + cellSize * y - (PIECE_SIZE / 2);
    root.image(piece.spriteUrl())
      .move(renderedX, renderedY)
      .attr({
        width: PIECE_SIZE,
        height: PIECE_SIZE
      });
  }

  return this;
};

XiangqiViewer.Board = function(selector, cellSize, strokeWidth) {
  var renderer = new XiangqiViewer.BoardRenderer(selector, cellSize, strokeWidth);
  renderer.draw();

  var WIDTH = 9
  var HEIGHT = 10
  var matrix;

  var initialize = function() {
    matrix = []; // rank, file; x, y

    for(var i = 0; i < WIDTH; i++) {
      matrix[i] = [];
      for(var j = 0; j < HEIGHT; j++) {
        matrix[i][j] = null;
      }
    }
  };

  var get = function(file, rank) {
    return matrix[file][rank];
  };

  var place = function(x, y, piece) {
    if (x < 0 || y < 0 || x >= WIDTH || y >= HEIGHT) {
      throw "x, y coords are out of bounds";
    }

    matrix[x][y] = piece;
    renderer.putPiece(x, y, piece);
  };

  var searchForward = function(pieceCode) {
    for (var i = 0; i < WIDTH; i++) {
      for (var j = 0; j < HEIGHT; j++) {
        var piece = get(i, j);
        if (piece && piece.code == pieceCode) {
          return {piece: piece, position: {x: i, y: j}};
        }
      }
    }
  };

  var searchBackward = function(pieceCode) {
    for (var i = 0; i < WIDTH; i++) {
      for (var j = HEIGHT - 1; j >= 0; j--) {
        var piece = get(i, j);
        if (piece && piece.code == pieceCode) {
          return {piece: piece, position: {x: i, y: j}};
        }
      }
    }
  };

  var getPositionedPiece(instruction, red) {
    if (instruction[0] == 'f' && red) {
      return searchBackward(instruction[1]);
    } else if (instruction[0] == 'b' && red) {
      return searchForward(instruction[1]);
    } else if (instruction[0] == 'f' && !red) {
      return searchBackward(instruction[1]);
    } else if (instruction[0] == 'b' && !red) {
      return searchForward(instruction[1]);
    } else {
      var instructionPiece = instruction[0];
      var file = instruction[1];

      for (var i = 0; i < HEIGHT; i++) {
        var piece = get(file, i);
        if (piece && piece.code == instructionPiece) {
          return {piece: piece, position: {x: file, y: i}};
        }
      }

      throw "no piece on this file";
    }
  }

  this.runMove = function(instruction) {
    if (instruction.length != 4) {
      throw "illegal instruction format";
    }
    instruction = instruction.toLowerCase();

    var positionedPiece = getPositionedPiece(instruction);
    var move = positionedPiece.piece.getMove(positionedPiece.position, instruction);
    var from = move.from;
    var to = move.to;
  }

  this.defaultSetup = function() {
    place(0, 0, new XiangqiViewer.Chariot(false));
    place(1, 0, new XiangqiViewer.Horse(false));
    place(2, 0, new XiangqiViewer.Elephant(false));
    place(3, 0, new XiangqiViewer.Advisor(false));
    place(4, 0, new XiangqiViewer.General(false));
    place(5, 0, new XiangqiViewer.Advisor(false));
    place(6, 0, new XiangqiViewer.Elephant(false));
    place(7, 0, new XiangqiViewer.Horse(false));
    place(8, 0, new XiangqiViewer.Chariot(false));
    place(0, 3, new XiangqiViewer.Pawn(false));
    place(2, 3, new XiangqiViewer.Pawn(false));
    place(4, 3, new XiangqiViewer.Pawn(false));
    place(6, 3, new XiangqiViewer.Pawn(false));
    place(8, 3, new XiangqiViewer.Pawn(false));
    place(1, 2, new XiangqiViewer.Cannon(false));
    place(7, 2, new XiangqiViewer.Cannon(false));

    place(0, 9, new XiangqiViewer.Chariot(true));
    place(1, 9, new XiangqiViewer.Horse(true));
    place(2, 9, new XiangqiViewer.Elephant(true));
    place(3, 9, new XiangqiViewer.Advisor(true));
    place(4, 9, new XiangqiViewer.General(true));
    place(5, 9, new XiangqiViewer.Advisor(true));
    place(6, 9, new XiangqiViewer.Elephant(true));
    place(7, 9, new XiangqiViewer.Horse(true));
    place(8, 9, new XiangqiViewer.Chariot(true));
    place(0, 6, new XiangqiViewer.Pawn(true));
    place(2, 6, new XiangqiViewer.Pawn(true));
    place(4, 6, new XiangqiViewer.Pawn(true));
    place(6, 6, new XiangqiViewer.Pawn(true));
    place(8, 6, new XiangqiViewer.Pawn(true));
    place(1, 7, new XiangqiViewer.Cannon(true));
    place(7, 7, new XiangqiViewer.Cannon(true));
  };

  initialize();
}

XiangqiViewer.Chariot = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/chariot_red.svg";
    } else {
      return "images/chariot_black.svg";
    }
  };
};

XiangqiViewer.Horse = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/horse_red.svg";
    } else {
      return "images/horse_black.svg";
    }
  };
};

XiangqiViewer.Elephant = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/elephant_red.svg";
    } else {
      return "images/elephant_black.svg";
    }
  };
};

XiangqiViewer.Advisor = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/adviser_red.svg";
    } else {
      return "images/adviser_black.svg";
    }
  };
};

XiangqiViewer.General = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/general_red.svg";
    } else {
      return "images/general_black.svg";
    }
  };
};

XiangqiViewer.Pawn = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/pawn_red.svg";
    } else {
      return "images/pawn_black.svg";
    }
  };
};

XiangqiViewer.Cannon = function(red) {
  this.spriteUrl = function() {
    if (red) {
      return "images/cannon_red.svg";
    } else {
      return "images/cannon_black.svg";
    }
  };
};
<|endoftext|>


<commit_before>// Handle search query states
// Listens for changes in query string, then ensures that provided values are coherent,
// and if all is fine emits valid query objects
// (which are usually consumed by list managers to update state of tables)

'use strict';

var ensureObject     = require('es5-ext/object/valid-object')
  , ensureString     = require('es5-ext/object/validate-stringifiable-value')
  , once             = require('timers-ext/once')
  , fixLocationQuery = require('./fix-location-query')
  , QueryHandler     = require('./query-handler');

module.exports = function (handlersList, appLocation, pathname) {
	var queryHandler, update;
	appLocation = ensureObject(appLocation);
	pathname = ensureString(pathname);
	queryHandler = new QueryHandler(handlersList);
	queryHandler.update = update = once(function () {
		if (pathname !== appLocation.pathname) return;
		queryHandler.resolve(appLocation.query).catch(function (e) {
			if (!e.queryHandler) throw e;
			console.error("Invalid query value: " + e.message);
			fixLocationQuery(e.queryHandler.name, e.fixedQueryValue);
			return;
		});
	});
	queryHandler._handlers.forEach(function (handler) {
		appLocation.query.get(handler.name).on('change', update);
	});
	appLocation.on('change', update);
	update();
	return queryHandler;
};
<commit_msg>Ensure errors are exposed<commit_after>// Handle search query states
// Listens for changes in query string, then ensures that provided values are coherent,
// and if all is fine emits valid query objects
// (which are usually consumed by list managers to update state of tables)

'use strict';

var ensureObject     = require('es5-ext/object/valid-object')
  , ensureString     = require('es5-ext/object/validate-stringifiable-value')
  , once             = require('timers-ext/once')
  , fixLocationQuery = require('./fix-location-query')
  , QueryHandler     = require('./query-handler');

module.exports = function (handlersList, appLocation, pathname) {
	var queryHandler, update;
	appLocation = ensureObject(appLocation);
	pathname = ensureString(pathname);
	queryHandler = new QueryHandler(handlersList);
	queryHandler.update = update = once(function () {
		if (pathname !== appLocation.pathname) return;
		queryHandler.resolve(appLocation.query).catch(function (e) {
			if (!e.queryHandler) throw e;
			console.error("Invalid query value: " + e.message);
			fixLocationQuery(e.queryHandler.name, e.fixedQueryValue);
			return;
		}).done();
	});
	queryHandler._handlers.forEach(function (handler) {
		appLocation.query.get(handler.name).on('change', update);
	});
	appLocation.on('change', update);
	update();
	return queryHandler;
};
<|endoftext|>


<commit_before>"use strict";

const Promise = require('bluebird');
const engine = require('../numerics');

function gpsSource(id,latitude0,longitude0,altitude0)
{
  this.id = id;
  this.stime = null;
  this.samples = [];
  this.latitude0 = latitude0;
  this.longitude0 = longitude0;
  this.altitude0 = altitude0;
  this.initializing = false;
  this.initialized = false;
}

gpsSource.prototype.addCoordinate = Promise.coroutine(function*(millis,lat,long,alt)
{
  let sample = { millis:millis, lat:lat, long:long, alt:alt };

  try
  {
    if(!this.initialized)
    {
      if(!this.initializing)
      {
        this.initializing = true;

        let initialObservation = new Float64Array([lat,long,alt]);
        let initialVariance = new Float64Array([0.01,0.01,0.01]);

        this.state = yield engine.kalmanInitialGuess(initialObservation,initialVariance);
        this.model = yield engine.kalmanNewModel(this.id,0.0001,0.005,0.5);
        this.samples = [sample];
        this.initialized = true;
        this.stime = millis;
      }
    }
    else
    {
      let stime = this.stime;

      this.samples.push(sample);
      this.stime = millis;

      let predictedState = yield engine.kalmanPredict(this.id,this.model,this.state);
      let observations = new Float64Array([sample.lat,sample.long,sample.alt]);

      this.state = yield engine.kalmanUpdate(this.id,this.model,predictedState,observations,(millis - stime)/1000);
    }
  }
  catch(e)
  {
    console.log("kalman failed:",e);
  }
});

gpsSource.prototype.defaultGPS = function(callback)
{
  let res =  { lat:this.latitude0, long:this.longitude0, alt:this.altitude0, latVar:0, longVar:0, altVar:0 };

  callback(null,res);
}

const defaultGPS = Promise.promisify(function(src,callback)
{
   src.defaultGPS(callback);
});

gpsSource.prototype.predict = Promise.coroutine(function*()
{
  var res;

  if(this.model != null)
  {
    let predictedState = yield engine.kalmanPredict(this.id,this.model,this.state);
    let coordArray = yield engine.kalmanStateMean(predictedState);
    let varianceArray = yield engine.kalmanStateVariance(predictedState);

    res =
    {
      lat:coordArray[0],
      long:coordArray[1],
      alt:coordArray[2],
      vt:coordArray[3],
      vg:coordArray[4],
      va:coordArray[5],
      latVar:varianceArray[0],
      longVar:varianceArray[1],
      altVar:varianceArray[2]
    };
  }
  else res = yield defaultGPS(this);
  return res;
});

gpsSource.prototype.prune = function()
{
  let now = new Date();
  let newSamples = [];

  for(let i = 0;i < this.samples.length;i++)
  {
    if(now.valueOf() - 5000 < this.samples[i].millis) newSamples.push(this.samples[i]);
  }
  this.samples = newSamples;
}

module.exports =
{
  newSource: function(id,latitude0,longitude0,altitude0)
  {
    let source = new gpsSource(id,latitude0,longitude0,altitude0);

     setInterval(function() { source.prune(); },500);
     return source;
  }
}
<commit_msg>Added time offset for out-of-sync clocks<commit_after>"use strict";

const Promise = require('bluebird');
const engine = require('../numerics');

function gpsSource(id,latitude0,longitude0,altitude0)
{
  this.id = id;
  this.stime = null;
  this.time0 = null;
  this.refTime = null;
  this.samples = [];
  this.latitude0 = latitude0;
  this.longitude0 = longitude0;
  this.altitude0 = altitude0;
  this.initializing = false;
  this.initialized = false;
}

gpsSource.prototype.addCoordinate = Promise.coroutine(function*(millis,lat,long,alt)
{
  let sample = { millis:millis, lat:lat, long:long, alt:alt };

  try
  {
    if(!this.initialized)
    {
      if(!this.initializing)
      {
        this.initializing = true;

        let initialObservation = new Float64Array([lat,long,alt]);
        let initialVariance = new Float64Array([0.01,0.01,0.01]);

        this.state = yield engine.kalmanInitialGuess(initialObservation,initialVariance);
        this.model = yield engine.kalmanNewModel(this.id,0.0001,0.005,0.5);
        this.samples = [sample];
        this.initialized = true;
        this.stime = millis;

        let now = new Date();

        this.time0 = millis;
        this.refTime = now.valueOf();
      }
    }
    else
    {
      let stime = this.stime;

      this.samples.push(sample);
      this.stime = millis;

      let predictedState = yield engine.kalmanPredict(this.id,this.model,this.state);
      let observations = new Float64Array([sample.lat,sample.long,sample.alt]);

      this.state = yield engine.kalmanUpdate(this.id,this.model,predictedState,observations,(millis - stime)/1000);
    }
  }
  catch(e)
  {
    console.log("kalman failed:",e);
  }
});

gpsSource.prototype.defaultGPS = function(callback)
{
  let res =  { lat:this.latitude0, long:this.longitude0, alt:this.altitude0, latVar:0, longVar:0, altVar:0 };

  callback(null,res);
}

const defaultGPS = Promise.promisify(function(src,callback)
{
   src.defaultGPS(callback);
});

gpsSource.prototype.predict = Promise.coroutine(function*()
{
  var res;

  if(this.model != null)
  {
    let predictedState = yield engine.kalmanPredict(this.id,this.model,this.state);
    let coordArray = yield engine.kalmanStateMean(predictedState);
    let varianceArray = yield engine.kalmanStateVariance(predictedState);

    res =
    {
      lat:coordArray[0],
      long:coordArray[1],
      alt:coordArray[2],
      vt:coordArray[3],
      vg:coordArray[4],
      va:coordArray[5],
      latVar:varianceArray[0],
      longVar:varianceArray[1],
      altVar:varianceArray[2]
    };
  }
  else res = yield defaultGPS(this);
  return res;
});

gpsSource.prototype.prune = function()
{
  let now = new Date();
  let newSamples = [];
  let checkTime = now.valueOf() + (this.time0 - this.refTime) - 5000;

  for(let i = 0;i < this.samples.length;i++)
  {
    if(checkTime < this.samples[i].millis) newSamples.push(this.samples[i]);
  }
  this.samples = newSamples;
}

module.exports =
{
  newSource: function(id,latitude0,longitude0,altitude0)
  {
    let source = new gpsSource(id,latitude0,longitude0,altitude0);

     setInterval(function() { source.prune(); },500);
     return source;
  }
}
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {DragSource, DropTarget} from 'react-dnd';

import Checkbox from '../Checkbox';
import CircularLoading from '../CircularLoading';
import Theme from '../Theme';

import Util from '../_vendors/Util';
import DragDrop from '../_vendors/DragDrop';

import './DraggableGridItem.css';

const DRAG_GRID_ITEM_SYMBOL = Symbol('DRAG_GRID_ITEM');

@DropTarget(DRAG_GRID_ITEM_SYMBOL, DragDrop.getHorizontalTarget(), connect => ({
    connectDropTarget: connect.dropTarget()
}))
@DragSource(DRAG_GRID_ITEM_SYMBOL, DragDrop.getSource(), (connect, monitor) => ({
    connectDragPreview: connect.dragPreview(),
    connectDragSource: connect.dragSource(),
    isDragging: monitor.isDragging()
}))
export default class DraggableGridItem extends Component {

    static Mode = {
        NORMAL: 'normal',
        CHECKBOX: 'checkbox',
        RADIO: 'radio'
    };

    constructor(props) {

        super(props);

        this.state = {
            checked: props.checked
        };

        this.checkboxChangeHandler = this::this.checkboxChangeHandler;
        this.radioChangeHandler = this::this.radioChangeHandler;
        this.touchTapHandler = this::this.touchTapHandler;

    }

    checkboxChangeHandler(checked, callback) {
        this.setState({
            checked
        }, () => {

            const {onSelect, onDeselect} = this.props;

            if (checked) {
                onSelect && onSelect();
            } else {
                onDeselect && onDeselect();
            }

            callback && typeof callback === 'function' && callback();

        });
    }

    radioChangeHandler(callback) {

        const {checked} = this.state;

        if (!checked) {
            this.setState({
                checked: true
            }, () => {
                const {onSelect} = this.props;
                onSelect && onSelect();
                callback && typeof callback === 'function' && callback();
            });
        } else {
            callback && typeof callback === 'function' && callback();
        }

    }

    touchTapHandler(e) {

        e.preventDefault();

        const {disabled, isLoading, isGroupTitle} = this.props;

        if (disabled || isLoading || isGroupTitle) {
            return;
        }

        const {mode} = this.props,
            callback = () => {
                const {onTouchTap} = this.props;
                onTouchTap && onTouchTap(e);
            };

        switch (mode) {
            case DraggableGridItem.Mode.CHECKBOX:
                this.checkboxChangeHandler(!this.state.checked, callback);
                return;
            case DraggableGridItem.Mode.RADIO:
                this.radioChangeHandler(callback);
                return;
            case DraggableGridItem.Mode.NORMAL:
                callback();
                return;
        }

    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.checked !== this.state.checked) {
            this.setState({
                checked: nextProps.checked
            });
        }
    }

    render() {

        const {
                connectDragPreview, connectDragSource, connectDropTarget, isDragging,
                index, className, style, itemColWidth, theme, data, text, desc, iconCls, rightIconCls,
                mode, disabled, isLoading, itemRenderer, renderer, isGroupTitle, anchorIconCls, isDraggableAnyWhere,
                onMouseEnter, onMouseLeave
            } = this.props,
            {checked} = this.state,

            listItemClassName = (theme ? ` theme-${theme}` : '') + (checked ? ' activated' : '')
                + (isDragging ? ' dragging' : '') + (isDraggableAnyWhere ? ' draggable' : '')
                + (className ? ' ' + className : ''),

            loadingIconPosition = (rightIconCls && !iconCls) ? 'right' : 'left',

            anchorEl = ,

            el = (
                <div className={'draggable-grid-item-wrapper'}
                     style={itemColWidth ? {width: `${itemColWidth}%`} : null}>

                        {
                            mode === DraggableGridItem.Mode.CHECKBOX ?
                                <Checkbox className="draggable-grid-item-checkbox"
                                          value={checked}
                                          disabled={disabled || isLoading}/>
                                :
                                null
                        }

                        {
                            mode === DraggableGridItem.Mode.RADIO ?

                                :
                                null
                        }

                        {
                            isLoading && loadingIconPosition === 'left' ?

                                    <CircularLoading className="button-loading-icon"
                                                     size="small"/>

                                :
                                (
                                    iconCls ?
                                        <i className={`button-icon button-icon-left ${iconCls}`}
                                           aria-hidden="true">
                                        :
                                        null
                                )
                        }

                        {
                            itemRenderer && typeof itemRenderer === 'function' ?
                                itemRenderer(data, index)
                                :
                                (
                                    renderer && typeof renderer === 'function' ?
                                        renderer(data, index)
                                        :
                                        (
                                            desc ?

                                                        {text}

                                                        {desc}

                                                :
                                                text
                                        )
                                )
                        }

                        {
                            isLoading && loadingIconPosition === 'right' ?
                                <CircularLoading className="button-icon button-icon-right button-loading-icon"
                                                 size="small"/>
                                :
                                (
                                    rightIconCls ?
                                        <i className={`button-icon button-icon-right ${rightIconCls}`}
                                           aria-hidden="true">
                                        :
                                        null
                                )
                        }

                        {
                            isGroupTitle ?
                                null
                                :
                                (
                                    isDraggableAnyWhere ?
                                        anchorEl
                                        :
                                        connectDragSource(anchorEl)
                                )
                        }

            );

        return isGroupTitle ?
            el
            :
            (
                isDraggableAnyWhere ?
                    connectDragSource(connectDropTarget(el))
                    :
                    connectDragPreview(connectDropTarget(el))
            );

    }
};

DraggableGridItem.propTypes = {

    connectDragPreview: PropTypes.func,
    connectDragSource: PropTypes.func,
    connectDropTarget: PropTypes.func,
    isDragging: PropTypes.bool,

    index: PropTypes.number,

    /**
     * The CSS class name of the grid button.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the grid button.
     */
    style: PropTypes.object,

    /**
     * The theme of the grid button.
     */
    theme: PropTypes.oneOf(Object.keys(Theme).map(key => Theme[key])),

    /**
     *
     */
    data: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]),

    /**
     * The text value of the grid button. Type can be string or number.
     */
    value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

    /**
     * The grid item's display text. Type can be string, number or bool.
     */
    text: PropTypes.any,

    /**
     * The desc value of the grid button. Type can be string or number.
     */
    desc: PropTypes.string,

    /**
     * If true, the grid button will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * If true,the button will be have loading effect.
     */
    isLoading: PropTypes.bool,

    /**
     * Use this property to display an icon. It will display on the left.
     */
    iconCls: PropTypes.string,

    /**
     * Use this property to display an icon. It will display on the right.
     */
    rightIconCls: PropTypes.string,

    /**
     * You can create a complicated renderer callback instead of value and desc prop.
     */
    itemRenderer: PropTypes.func,

    /**
     * You can create a complicated renderer callback instead of value and desc prop.
     */
    renderer: PropTypes.func,

    /**
     *
     */
    checked: PropTypes.bool,

    /**
     *
     */
    mode: PropTypes.oneOf(Util.enumerateValue(DraggableGridItem.Mode)),

    /**
     *
     */
    groupIndex: PropTypes.number,

    /**
     *
     */
    isGroupTitle: PropTypes.bool,

    /**
     *
     */
    anchorIconCls: PropTypes.string,

    /**
     *
     */
    isDraggableAnyWhere: PropTypes.bool,

    /**
     * Callback function fired when a grid item touch-tapped.
     */
    onTouchTap: PropTypes.func,

    /**
     *
     */
    onSelect: PropTypes.func,

    /**
     *
     */
    onDeselect: PropTypes.func,

    /**
     *
     */
    onMouseEnter: PropTypes.func,

    /**
     *
     */
    onMouseLeave: PropTypes.func

};

DraggableGridItem.defaultProps = {

    index: 0,

    className: '',
    style: null,

    theme: Theme.DEFAULT,

    data: '',
    value: '',
    text: '',
    desc: '',

    disabled: false,
    isLoading: false,

    iconCls: '',
    rightIconCls: '',

    checked: false,

    mode: DraggableGridItem.Mode.NORMAL,

    isGroupTitle: false,

    anchorIconCls: 'fa fa-bars',
    isDraggableAnyWhere: false

};<commit_msg>update DraggableGridItem: add tip<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {DragSource, DropTarget} from 'react-dnd';

import Checkbox from '../Checkbox';
import CircularLoading from '../CircularLoading';
import Tip from '../Tip';
import Theme from '../Theme';

import Util from '../_vendors/Util';
import DragDrop from '../_vendors/DragDrop';

import './DraggableGridItem.css';

const DRAG_GRID_ITEM_SYMBOL = Symbol('DRAG_GRID_ITEM');

@DropTarget(DRAG_GRID_ITEM_SYMBOL, DragDrop.getHorizontalTarget(), connect => ({
    connectDropTarget: connect.dropTarget()
}))
@DragSource(DRAG_GRID_ITEM_SYMBOL, DragDrop.getSource(), (connect, monitor) => ({
    connectDragPreview: connect.dragPreview(),
    connectDragSource: connect.dragSource(),
    isDragging: monitor.isDragging()
}))
export default class DraggableGridItem extends Component {

    static Mode = {
        NORMAL: 'normal',
        CHECKBOX: 'checkbox',
        RADIO: 'radio'
    };

    constructor(props) {

        super(props);

        this.state = {
            checked: props.checked,
            tipVisible: false,
            tipTriggerEl: null
        };

        this.showTip = this::this.showTip;
        this.hideTip = this::this.hideTip;
        this.checkboxChangeHandler = this::this.checkboxChangeHandler;
        this.radioChangeHandler = this::this.radioChangeHandler;
        this.touchTapHandler = this::this.touchTapHandler;
        this.mouseEnterHandler = this::this.mouseEnterHandler;
        this.mouseOverHandler = this::this.mouseOverHandler;

    }

    showTip(e) {
        if (!this.state.tipVisible) {
            this.setState({
                tipVisible: true,
                tipTriggerEl: e.target
            });
        }
    }

    hideTip() {
        this.setState({
            tipVisible: false
        });
    }

    checkboxChangeHandler(checked, callback) {
        this.setState({
            checked
        }, () => {

            const {onSelect, onDeselect} = this.props;

            if (checked) {
                onSelect && onSelect();
            } else {
                onDeselect && onDeselect();
            }

            callback && typeof callback === 'function' && callback();

        });
    }

    radioChangeHandler(callback) {

        const {checked} = this.state;

        if (!checked) {
            this.setState({
                checked: true
            }, () => {
                const {onSelect} = this.props;
                onSelect && onSelect();
                callback && typeof callback === 'function' && callback();
            });
        } else {
            callback && typeof callback === 'function' && callback();
        }

    }

    touchTapHandler(e) {

        e.preventDefault();

        const {disabled, isLoading, isGroupTitle} = this.props;

        if (disabled || isLoading || isGroupTitle) {
            return;
        }

        const {mode} = this.props,
            callback = () => {
                const {onTouchTap} = this.props;
                onTouchTap && onTouchTap(e);
            };

        switch (mode) {
            case DraggableGridItem.Mode.CHECKBOX:
                this.checkboxChangeHandler(!this.state.checked, callback);
                return;
            case DraggableGridItem.Mode.RADIO:
                this.radioChangeHandler(callback);
                return;
            case DraggableGridItem.Mode.NORMAL:
                callback();
                return;
        }

    }

    mouseEnterHandler(e) {

        this.showTip(e);

        const {onMouseEnter} = this.props;
        onMouseEnter && onMouseEnter(e);

    }

    mouseOverHandler(e) {

        this.showTip(e);

        const {onMouseOver} = this.props;
        onMouseOver && onMouseOver(e);

    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.checked !== this.state.checked) {
            this.setState({
                checked: nextProps.checked
            });
        }
    }

    render() {

        const {
                connectDragPreview, connectDragSource, connectDropTarget, isDragging,
                index, className, style, itemColWidth, theme, data, text, desc, iconCls, rightIconCls,
                mode, disabled, isLoading, itemRenderer, renderer, isGroupTitle, anchorIconCls, isDraggableAnyWhere,
                tip, tipPosition, onMouseLeave
            } = this.props,
            {checked, tipVisible, tipTriggerEl} = this.state,

            listItemClassName = (theme ? ` theme-${theme}` : '') + (checked ? ' activated' : '')
                + (isDragging ? ' dragging' : '') + (isDraggableAnyWhere ? ' draggable' : '')
                + (className ? ' ' + className : ''),

            loadingIconPosition = (rightIconCls && !iconCls) ? 'right' : 'left',

            anchorEl = ,

            el = (
                <div className={'draggable-grid-item-wrapper'}
                     style={itemColWidth ? {width: `${itemColWidth}%`} : null}>

                        {
                            mode === DraggableGridItem.Mode.CHECKBOX ?
                                <Checkbox className="draggable-grid-item-checkbox"
                                          value={checked}
                                          disabled={disabled || isLoading}/>
                                :
                                null
                        }

                        {
                            mode === DraggableGridItem.Mode.RADIO ?

                                :
                                null
                        }

                        {
                            isLoading && loadingIconPosition === 'left' ?

                                    <CircularLoading className="button-loading-icon"
                                                     size="small"/>

                                :
                                (
                                    iconCls ?
                                        <i className={`button-icon button-icon-left ${iconCls}`}
                                           aria-hidden="true">
                                        :
                                        null
                                )
                        }

                        {
                            itemRenderer && typeof itemRenderer === 'function' ?
                                itemRenderer(data, index)
                                :
                                (
                                    renderer && typeof renderer === 'function' ?
                                        renderer(data, index)
                                        :
                                        (
                                            desc ?

                                                        {text}

                                                        {desc}

                                                :
                                                text
                                        )
                                )
                        }

                        {
                            isLoading && loadingIconPosition === 'right' ?
                                <CircularLoading className="button-icon button-icon-right button-loading-icon"
                                                 size="small"/>
                                :
                                (
                                    rightIconCls ?
                                        <i className={`button-icon button-icon-right ${rightIconCls}`}
                                           aria-hidden="true">
                                        :
                                        null
                                )
                        }

                        {
                            isGroupTitle ?
                                null
                                :
                                (
                                    isDraggableAnyWhere ?
                                        anchorEl
                                        :
                                        connectDragSource(anchorEl)
                                )
                        }

                    {
                        tip ?
                            <Tip text={tip}
                                 visible={tipVisible}
                                 triggerEl={tipTriggerEl}
                                 position={tipPosition}
                                 onRequestClose={this.hideTip}/>
                            :
                            null
                    }

            );

        return isGroupTitle ?
            el
            :
            (
                isDraggableAnyWhere ?
                    connectDragSource(connectDropTarget(el))
                    :
                    connectDragPreview(connectDropTarget(el))
            );

    }
};

DraggableGridItem.propTypes = {

    connectDragPreview: PropTypes.func,
    connectDragSource: PropTypes.func,
    connectDropTarget: PropTypes.func,
    isDragging: PropTypes.bool,

    index: PropTypes.number,

    className: PropTypes.string,
    style: PropTypes.object,
    theme: PropTypes.oneOf(Object.keys(Theme).map(key => Theme[key])),

    data: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]),
    value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    text: PropTypes.any,
    desc: PropTypes.string,
    disabled: PropTypes.bool,
    isLoading: PropTypes.bool,
    iconCls: PropTypes.string,
    rightIconCls: PropTypes.string,
    itemRenderer: PropTypes.func,
    renderer: PropTypes.func,
    checked: PropTypes.bool,
    mode: PropTypes.oneOf(Util.enumerateValue(DraggableGridItem.Mode)),
    groupIndex: PropTypes.number,
    isGroupTitle: PropTypes.bool,
    anchorIconCls: PropTypes.string,
    isDraggableAnyWhere: PropTypes.bool,

    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Tip.Position)),

    onTouchTap: PropTypes.func,
    onSelect: PropTypes.func,
    onDeselect: PropTypes.func,
    onMouseEnter: PropTypes.func,
    onMouseLeave: PropTypes.func,
    onMouseOver: PropTypes.func

};

DraggableGridItem.defaultProps = {

    index: 0,

    className: '',
    style: null,

    theme: Theme.DEFAULT,

    data: '',
    value: '',
    text: '',
    desc: '',

    disabled: false,
    isLoading: false,

    iconCls: '',
    rightIconCls: '',

    checked: false,

    mode: DraggableGridItem.Mode.NORMAL,

    isGroupTitle: false,

    anchorIconCls: 'fa fa-bars',
    isDraggableAnyWhere: false,

    tip: ''

};<|endoftext|>


<commit_before>/*
 Copyright 2015 Aleksandar Jankovic

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

const storageManager = require('./StorageManager');
const eventCentral = require('./EventCentral');

class SocketManager {
  constructor() {
    this.socket = io(); // eslint-disable-line no-undef
    this.lastAlive = (new Date()).getTime();
    this.reconnecting = false;
    this.hasConnected = false;

    /**
     * Checks if the screen has been unresponsive for some time.
     * Some devices disable Javascript when screen is off (iOS)
     * They also fail to notice that they have been disconnected
     * We check the time between heartbeats and if the time i
     * over 10 seconds (example: when screen is turned off and then on)
     * we force them to reconnect
     */
    const timeoutFunc = () => {
      const now = (new Date()).getTime();
      const diff = now - this.lastAlive;
      const offBy = diff - 1000;
      this.lastAlive = now;

      if (offBy > 10000) {
        this.reconnect();
      }

      setTimeout(timeoutFunc, 1000);
    };

    timeoutFunc();
  }

  addEvent(event, callback) {
    this.socket.on(event, callback);
  }

  addEvents(events) {
    events.forEach(event => this.addEvent(event.event, event.func));
  }

  updateId() {
    this.emitEvent('updateId', {
      device: {
        deviceId: storageManager.getDeviceId(),
      },
    }, ({ error, data }) => {
      if (error) {
        return;
      }

      if (error) {
        storageManager.removeUser();
        storageManager.setAccessLevel(0);
        storageManager.removeBlockedBy();

        return;
      }

      const { blockedBy, user: { userName, accessLevel, aliases, team, shortTeam } } = data;

      storageManager.setUserName(userName);
      storageManager.setAccessLevel(accessLevel);
      storageManager.setAliases(aliases);
      storageManager.setTeam(team);
      storageManager.setShortTeam(shortTeam);
      this.setConnected();

      eventCentral.triggerEvent({
        event: eventCentral.Events.SIGNALBLOCK,
        params: { blockedBy },
      });
      eventCentral.triggerEvent({
        event: eventCentral.Events.USER,
        params: {
          changedUser: userName,
          firstConnection: !this.hasConnected,
        },
      });

      this.emitEvent('getGameCode', { codeType: 'profile' }, ({ error: codeError, data: codeData }) => {
        if (codeError) {
          console.log(codeError);

          return;
        }

        const { gameCode } = codeData;

        storageManager.setGameCode(gameCode);
        eventCentral.triggerEvent({
          event: eventCentral.Events.GAMECODE,
          params: { gameCode },
        });
      });
    });
  }

  /**
   * Reconnect to socket.io
   */
  reconnect() {
    if (!this.reconnecting) {
      this.reconnecting = true;
      this.socket.disconnect();
      this.socket.connect({ forceNew: true });
      this.updateId();
    }
  }

  /**
   * Emit event through socket.io
   * @param {string} event - Event to emit
   * @param {Object} [params] - Parameters to send in the emit
   * @param {Function} [callback] - Callback
   */
  emitEvent(event, params, callback) {
    params.token = storageManager.getToken() || '';

    if (!callback) {
      this.socket.emit(event, params);
    } else {
      this.socket.emit(event, params, callback);
    }
  }

  reconnectDone() { this.reconnecting = false; }

  setConnected() { this.hasConnected = true; }
}

const socketManager = new SocketManager();

module.exports = socketManager;
<commit_msg>Return blocked correct run of function<commit_after>/*
 Copyright 2015 Aleksandar Jankovic

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

const storageManager = require('./StorageManager');
const eventCentral = require('./EventCentral');

class SocketManager {
  constructor() {
    this.socket = io(); // eslint-disable-line no-undef
    this.lastAlive = (new Date()).getTime();
    this.reconnecting = false;
    this.hasConnected = false;

    /**
     * Checks if the screen has been unresponsive for some time.
     * Some devices disable Javascript when screen is off (iOS)
     * They also fail to notice that they have been disconnected
     * We check the time between heartbeats and if the time i
     * over 10 seconds (example: when screen is turned off and then on)
     * we force them to reconnect
     */
    const timeoutFunc = () => {
      const now = (new Date()).getTime();
      const diff = now - this.lastAlive;
      const offBy = diff - 1000;
      this.lastAlive = now;

      if (offBy > 10000) {
        this.reconnect();
      }

      setTimeout(timeoutFunc, 1000);
    };

    timeoutFunc();
  }

  addEvent(event, callback) {
    this.socket.on(event, callback);
  }

  addEvents(events) {
    events.forEach(event => this.addEvent(event.event, event.func));
  }

  updateId() {
    this.emitEvent('updateId', {
      device: {
        deviceId: storageManager.getDeviceId(),
      },
    }, ({ error, data }) => {
      if (error) {
        storageManager.removeUser();
        storageManager.setAccessLevel(0);
        storageManager.removeBlockedBy();

        return;
      }

      const { blockedBy, user: { userName, accessLevel, aliases, team, shortTeam } } = data;

      storageManager.setUserName(userName);
      storageManager.setAccessLevel(accessLevel);
      storageManager.setAliases(aliases);
      storageManager.setTeam(team);
      storageManager.setShortTeam(shortTeam);
      this.setConnected();

      eventCentral.triggerEvent({
        event: eventCentral.Events.SIGNALBLOCK,
        params: { blockedBy },
      });
      eventCentral.triggerEvent({
        event: eventCentral.Events.USER,
        params: {
          changedUser: userName,
          firstConnection: !this.hasConnected,
        },
      });

      this.emitEvent('getGameCode', { codeType: 'profile' }, ({ error: codeError, data: codeData }) => {
        if (codeError) {
          console.log(codeError);

          return;
        }

        const { gameCode } = codeData;

        storageManager.setGameCode(gameCode);
        eventCentral.triggerEvent({
          event: eventCentral.Events.GAMECODE,
          params: { gameCode },
        });
      });
    });
  }

  /**
   * Reconnect to socket.io
   */
  reconnect() {
    if (!this.reconnecting) {
      this.reconnecting = true;
      this.socket.disconnect();
      this.socket.connect({ forceNew: true });
      this.updateId();
    }
  }

  /**
   * Emit event through socket.io
   * @param {string} event - Event to emit
   * @param {Object} [params] - Parameters to send in the emit
   * @param {Function} [callback] - Callback
   */
  emitEvent(event, params, callback) {
    params.token = storageManager.getToken() || '';

    if (!callback) {
      this.socket.emit(event, params);
    } else {
      this.socket.emit(event, params, callback);
    }
  }

  reconnectDone() { this.reconnecting = false; }

  setConnected() { this.hasConnected = true; }
}

const socketManager = new SocketManager();

module.exports = socketManager;
<|endoftext|>


<commit_before>var os = require( 'os' )
var assert = require( 'assert' )

/**
 * BlockDevice Constructor
 * @param {Object} options
 */
function BlockDevice( options ) {

  if( !(this instanceof BlockDevice) )
    return new BlockDevice( options )

  options = options != null ?
    options : {}

  this.fs = options.fs || require( 'fs' )
  this.fd = options.fd
  this.path = options.path
  this.mode = options.mode || 'rs+'

  this.blockSize = options.blockSize || -1
  this.size = options.size || -1

  // Heads per Track (for CHS addressing)
  this.headsPerTrack = options.headsPerTrack || -1
  // Sectors per Track (for CHS addressing)
  this.sectorsPerTrack = options.sectorsPerTrack || -1

  Object.defineProperty( this, 'fs', {
    enumerable: false
  })

}

/**
 * Partition Constructor
 * @type {Function}
 */
BlockDevice.Partition = require( './partition' )

/**
 * Returns physical device path from id
 * @param  {Number} id
 * @return {String} path
 */
BlockDevice.getPath = function( id ) {
  return os.platform() === 'win32' ?
    '\\\\.\\PhysicalDrive' + id :
    '/dev/disk' + id
}

/**
 * BlockDevice Prototype
 * @type {Object}
 */
BlockDevice.prototype = {

  /**
   * BlockDevice constructor
   * @type {Function}
   */
  constructor: BlockDevice,

  /**
   * Opens a file descriptor for this device
   * @param {Function} callback
   * @return {BlockDevice}
   */
  open: function( callback ) {

    var self = this

    // Close a previously opened handle
    if( this.fd != null ) {
      return this.close( function( error ) {
        if( error != null )
          return callback.call( self, error )
        self.open( self.path, self.mode, callback )
      })
    }

    // Open a new fd handle
    this.fs.open( this.path, this.mode, function( error, fd ) {

      if( error != null )
        return callback.call( self, error, fd )

      // Set file descriptor
      self.fd = fd

      // If no blockSize has been set, attempt to
      // detect it after opening the device
      if( self.blockSize == null || self.blockSize <= 0 ) {
        self.detectBlockSize( 0, 0, 0, function( error, blockSize ) {
          self.blockSize = blockSize || -1
          callback.call( self, error, self.fd )
        })
      } else {
        callback.call( self, error, fd )
      }

    })

    return this

  },

  /**
   * Closes the active file descriptor
   * @param {Function} callback
   * @return {BlockDevice}
   */
  close: function( callback ) {

    var self = this

    if( this.fd != null ) {
      this.fs.close( this.fd, function( error ) {
        self.fd = null
        callback.call( self )
      })
    }

    return this

  },

  /**
   * Primitive logical block size detection
   * @param  {Number} [size=128]
   * @param  {Number} [step=128]
   * @param  {Number} [limit=8192]
   * @param  {Function} callback( err, blockSize )
   * @return {BlockDevice}
   */
  detectBlockSize: function( size, step, limit, callback ) {

    if( this.fd == null )
      return callback.call( this, new Error( 'Invalid file descriptor' ) )

    size  = size || 0x200
    step  = step || 0x80
    limit = limit || 0x2000

    var self = this

    var readBlock = function() {

      var block = new Buffer( size )

      self.fs.read( self.fd, block, 0, size, 0, function( error, bytesRead ) {
        if( error != null ) {
          // EINVAL tells us that the block size
          // ain't just right (yet); everything
          // else is probably user error
          if( error.code !== 'EINVAL' )
            return callback.call( self, error )
          // Increase the blocksize by `step`
          size += step
          // Attempt next size read
          return readBlock()
        }
        // Check if bytes read correspond
        // to current block size
        if( size !== bytesRead )
          return callback.call( self, new Error( 'Size and bytes read mismatch: ' + size + ', ' + bytesRead ) )
        // Check if the limit has been reached,
        // and terminate with error, if so
        if( size > limit )
          return callback.call( self, new Error( 'Reached limit of ' + limit + ' bytes' ))
        // We've successfully found the
        // smallest readable block size;
        // stop looking...
        self.blockSize = size
        callback.call( self, null, size )

      })

    }

    // Start reading blocks
    readBlock()

    return this

  },

  /**
   * Experimental device size detection
   * NOTE: This is extremely slow and should only be used
   * if the device's size can not be determined by reading
   * structures (like GPT/MBR/VBR/EBR/Partitions) from it
   * @param  {Number} step
   * @param  {Function} callback
   * @return {BlockDevice}
   */
  detectSize: function( step, callback ) {

    if( this.fd == null )
      return callback.call( this, new Error( 'Invalid file descriptor' ) )

    if( this.blockSize <= 0 || this.blockSize == null )
      throw new Error( 'No block size specified' )

    step = step || 1024 * 1024 * 1024

    // Keep an output buffer around,
    // to avoid buffer creation on every read
    var block = new Buffer( this.blockSize )
    var bytesRead = -1, size = -1, offset = 0
    var self = this

    var readBlock = function() {
      self.fs.read( self.fd, block, 0, self.blockSize, offset, function( error, bytesRead ) {
        // console.log( 'bytes read:', bytesRead )
        // console.log( 'buffer:', block )
        // console.log( 'offset:', offset )
        // console.log( 'step size:', step )
        // console.log( 'size:', size / 1024 / 1024 / 1024, 'GB' )
        if( error != null || bytesRead !== self.blockSize ) {
          // We're only interested in I/O errors,
          // since they signal OOB reading, otherwise break out of loop
          if( error && error.code !== 'EIO') {
            return callback.call( self, error, size )
          }
          // Step back
          offset -= step
          // Decrease step size
          step = Math.max( step / 8, 1 )
        } else {
          // Size is block size added to previous offset
          size = offset + self.blockSize
          // Advance offset on successfull read
          offset += step
        }
        // If our maximum accuracy is reached,
        // break out of the loop
        if( step < self.blockSize ) {
          var blocks = Math.ceil( size / self.blockSize )
          var total = blocks * self.blockSize
          return callback.call( self, null, total )
        }
        // Continue reading blocks
        readBlock()
      })
    }

    // Start reading blocks
    readBlock()

    return this

  },

  /**
   * Return a new partition
   * @param  {Object} options
   * @return {BlockDevice.Partition}
   */
  partition: function( options ) {
    return new BlockDevice.Partition( this, options )
  },

  /**
   * Converts a CHS address to an LBA
   * @param  {Number} cylinder
   * @param  {Number} head
   * @param  {Number} sector
   * @return {BlockDevice}
   */
  getLBA: function( cylinder, head, sector ) {

    if( this.headsPerTrack < 0 || this.sectorsPerTrack < 0 )
      throw new Error( 'Unspecified device geometry' )

    return ( cylinder * this.headsPerTrack + head ) *
      this.sectorsPerTrack + ( sector - 1 )

  },

  read: function( offset, length, buffer, callback ) {

    if( this.fd == null )
      return callback.call( this, new Error( 'Invalid file descriptor' ) )

    var self = this

    buffer = buffer || new Buffer( length )

    this.fs.read(
      this.fd, buffer, 0, length, offset,
      function( error, bytesRead ) {
        callback.call( self, error, buffer, bytesRead )
      }
    )

    return this

  },

  /**
   * Reads from one LBA to another
   * @param  {Number} fromLBA
   * @param  {Number} toLBA
   * @param  {Buffer} buffer (optional)
   * @param  {Function} callback( error, buffer, bytesRead )
   * @return {BlockDevice}
   */
  readBlocks: function( fromLBA, toLBA, buffer, callback ) {

    fromLBA = fromLBA || 0
    toLBA = toLBA || ( fromLBA + 1 )

    if( fromLBA > toLBA ) {
      var swap = fromLBA
      fromLBA = toLBA
      toLBA = swap
      swap = void 0
    }

    var self = this
    var from = this.blockSize * fromLBA
    var to = this.blockSize * toLBA

    this.read( from, to - from, buffer, callback )

    return this

  },

  write: function( offset, buffer, callback ) {

    if( this.fd == null )
      return callback.call( this, new Error( 'Invalid file descriptor' ) )

    if( buffer.length % this.blockSize !== 0 )
      return callback( new Error( 'Buffer length not multiple of block size' ) )

    var self = this

    this.fs.write(
      this.fd, buffer, 0, buffer.length, offset,
      function( error, bytesWritten ) {
        callback.call( self, error, bytesWritten )
      }
    )

    return this

  },

  writeBlocks: function( fromLBA, buffer, callback ) {

    var self = this
    var offset = this.blockSize * fromLBA

    this.write( offset, buffer, callback )

    return this

  },

}

// Exports
module.exports = BlockDevice
<commit_msg>Updated lib/blockdevice: Changed default mode to 'r'<commit_after>var os = require( 'os' )
var assert = require( 'assert' )

/**
 * BlockDevice Constructor
 * @param {Object} options
 */
function BlockDevice( options ) {

  if( !(this instanceof BlockDevice) )
    return new BlockDevice( options )

  options = options != null ?
    options : {}

  this.fs = options.fs || require( 'fs' )
  this.fd = options.fd
  this.path = options.path
  this.mode = options.mode || 'r'

  this.blockSize = options.blockSize || -1
  this.size = options.size || -1

  // Heads per Track (for CHS addressing)
  this.headsPerTrack = options.headsPerTrack || -1
  // Sectors per Track (for CHS addressing)
  this.sectorsPerTrack = options.sectorsPerTrack || -1

  Object.defineProperty( this, 'fs', {
    enumerable: false
  })

}

/**
 * Partition Constructor
 * @type {Function}
 */
BlockDevice.Partition = require( './partition' )

/**
 * Returns physical device path from id
 * @param  {Number} id
 * @return {String} path
 */
BlockDevice.getPath = function( id ) {
  return os.platform() === 'win32' ?
    '\\\\.\\PhysicalDrive' + id :
    '/dev/disk' + id
}

/**
 * BlockDevice Prototype
 * @type {Object}
 */
BlockDevice.prototype = {

  /**
   * BlockDevice constructor
   * @type {Function}
   */
  constructor: BlockDevice,

  /**
   * Opens a file descriptor for this device
   * @param {Function} callback
   * @return {BlockDevice}
   */
  open: function( callback ) {

    var self = this

    // Close a previously opened handle
    if( this.fd != null ) {
      return this.close( function( error ) {
        if( error != null )
          return callback.call( self, error )
        self.open( self.path, self.mode, callback )
      })
    }

    // Open a new fd handle
    this.fs.open( this.path, this.mode, function( error, fd ) {

      if( error != null )
        return callback.call( self, error, fd )

      // Set file descriptor
      self.fd = fd

      // If no blockSize has been set, attempt to
      // detect it after opening the device
      if( self.blockSize == null || self.blockSize <= 0 ) {
        self.detectBlockSize( 0, 0, 0, function( error, blockSize ) {
          self.blockSize = blockSize || -1
          callback.call( self, error, self.fd )
        })
      } else {
        callback.call( self, error, fd )
      }

    })

    return this

  },

  /**
   * Closes the active file descriptor
   * @param {Function} callback
   * @return {BlockDevice}
   */
  close: function( callback ) {

    var self = this

    if( this.fd != null ) {
      this.fs.close( this.fd, function( error ) {
        self.fd = null
        callback.call( self )
      })
    }

    return this

  },

  /**
   * Primitive logical block size detection
   * @param  {Number} [size=128]
   * @param  {Number} [step=128]
   * @param  {Number} [limit=8192]
   * @param  {Function} callback( err, blockSize )
   * @return {BlockDevice}
   */
  detectBlockSize: function( size, step, limit, callback ) {

    if( this.fd == null )
      return callback.call( this, new Error( 'Invalid file descriptor' ) )

    size  = size || 0x200
    step  = step || 0x80
    limit = limit || 0x2000

    var self = this

    var readBlock = function() {

      var block = new Buffer( size )

      self.fs.read( self.fd, block, 0, size, 0, function( error, bytesRead ) {
        if( error != null ) {
          // EINVAL tells us that the block size
          // ain't just right (yet); everything
          // else is probably user error
          if( error.code !== 'EINVAL' )
            return callback.call( self, error )
          // Increase the blocksize by `step`
          size += step
          // Attempt next size read
          return readBlock()
        }
        // Check if bytes read correspond
        // to current block size
        if( size !== bytesRead )
          return callback.call( self, new Error( 'Size and bytes read mismatch: ' + size + ', ' + bytesRead ) )
        // Check if the limit has been reached,
        // and terminate with error, if so
        if( size > limit )
          return callback.call( self, new Error( 'Reached limit of ' + limit + ' bytes' ))
        // We've successfully found the
        // smallest readable block size;
        // stop looking...
        self.blockSize = size
        callback.call( self, null, size )

      })

    }

    // Start reading blocks
    readBlock()

    return this

  },

  /**
   * Experimental device size detection
   * NOTE: This is extremely slow and should only be used
   * if the device's size can not be determined by reading
   * structures (like GPT/MBR/VBR/EBR/Partitions) from it
   * @param  {Number} step
   * @param  {Function} callback
   * @return {BlockDevice}
   */
  detectSize: function( step, callback ) {

    if( this.fd == null )
      return callback.call( this, new Error( 'Invalid file descriptor' ) )

    if( this.blockSize <= 0 || this.blockSize == null )
      throw new Error( 'No block size specified' )

    step = step || 1024 * 1024 * 1024

    // Keep an output buffer around,
    // to avoid buffer creation on every read
    var block = new Buffer( this.blockSize )
    var bytesRead = -1, size = -1, offset = 0
    var self = this

    var readBlock = function() {
      self.fs.read( self.fd, block, 0, self.blockSize, offset, function( error, bytesRead ) {
        // console.log( 'bytes read:', bytesRead )
        // console.log( 'buffer:', block )
        // console.log( 'offset:', offset )
        // console.log( 'step size:', step )
        // console.log( 'size:', size / 1024 / 1024 / 1024, 'GB' )
        if( error != null || bytesRead !== self.blockSize ) {
          // We're only interested in I/O errors,
          // since they signal OOB reading, otherwise break out of loop
          if( error && error.code !== 'EIO') {
            return callback.call( self, error, size )
          }
          // Step back
          offset -= step
          // Decrease step size
          step = Math.max( step / 8, 1 )
        } else {
          // Size is block size added to previous offset
          size = offset + self.blockSize
          // Advance offset on successfull read
          offset += step
        }
        // If our maximum accuracy is reached,
        // break out of the loop
        if( step < self.blockSize ) {
          var blocks = Math.ceil( size / self.blockSize )
          var total = blocks * self.blockSize
          return callback.call( self, null, total )
        }
        // Continue reading blocks
        readBlock()
      })
    }

    // Start reading blocks
    readBlock()

    return this

  },

  /**
   * Return a new partition
   * @param  {Object} options
   * @return {BlockDevice.Partition}
   */
  partition: function( options ) {
    return new BlockDevice.Partition( this, options )
  },

  /**
   * Converts a CHS address to an LBA
   * @param  {Number} cylinder
   * @param  {Number} head
   * @param  {Number} sector
   * @return {BlockDevice}
   */
  getLBA: function( cylinder, head, sector ) {

    if( this.headsPerTrack < 0 || this.sectorsPerTrack < 0 )
      throw new Error( 'Unspecified device geometry' )

    return ( cylinder * this.headsPerTrack + head ) *
      this.sectorsPerTrack + ( sector - 1 )

  },

  read: function( offset, length, buffer, callback ) {

    if( this.fd == null )
      return callback.call( this, new Error( 'Invalid file descriptor' ) )

    var self = this

    buffer = buffer || new Buffer( length )

    this.fs.read(
      this.fd, buffer, 0, length, offset,
      function( error, bytesRead ) {
        callback.call( self, error, buffer, bytesRead )
      }
    )

    return this

  },

  /**
   * Reads from one LBA to another
   * @param  {Number} fromLBA
   * @param  {Number} toLBA
   * @param  {Buffer} buffer (optional)
   * @param  {Function} callback( error, buffer, bytesRead )
   * @return {BlockDevice}
   */
  readBlocks: function( fromLBA, toLBA, buffer, callback ) {

    fromLBA = fromLBA || 0
    toLBA = toLBA || ( fromLBA + 1 )

    if( fromLBA > toLBA ) {
      var swap = fromLBA
      fromLBA = toLBA
      toLBA = swap
      swap = void 0
    }

    var self = this
    var from = this.blockSize * fromLBA
    var to = this.blockSize * toLBA

    this.read( from, to - from, buffer, callback )

    return this

  },

  write: function( offset, buffer, callback ) {

    if( this.fd == null )
      return callback.call( this, new Error( 'Invalid file descriptor' ) )

    if( buffer.length % this.blockSize !== 0 )
      return callback( new Error( 'Buffer length not multiple of block size' ) )

    var self = this

    this.fs.write(
      this.fd, buffer, 0, buffer.length, offset,
      function( error, bytesWritten ) {
        callback.call( self, error, bytesWritten )
      }
    )

    return this

  },

  writeBlocks: function( fromLBA, buffer, callback ) {

    var self = this
    var offset = this.blockSize * fromLBA

    this.write( offset, buffer, callback )

    return this

  },

}

// Exports
module.exports = BlockDevice
<|endoftext|>