<commit_before>/* global describe, it */
import { Chess, web3 } from '../contract/Chess.sol';

var assert = require('chai').assert;

const defaultBoard = [-4,-2,-3,-5,-6,-3,-2,-4,0,0,0,4,0,0,0,0,
                      -1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
                      4,2,3,5,6,3,2,4,0,0,0,116,0,0,0,0];

describe('Chess contract', function() {
  this.timeout(10000);
  this.slow(500);

  var testGames = [];
  const player1 = web3.eth.accounts[0];
  const player2 = web3.eth.accounts[1];
  const player3 = web3.eth.accounts[2];

  // Remove this for CI/deploy, otherwise the test never finishes
  /*
  var debugFilter = Chess.DebugInts({});
  debugFilter.watch(function(error, result){
    console.log(result.args.message,
                result.args.value1.toNumber(),
                result.args.value2.toNumber(),
                result.args.value3.toNumber());
  });
  */

  // We create a few test games here that will later be accessed in testGames[]
  describe('initGame()', function () {
    it('should initialize a game with player1 playing white', function (done) {
      Chess.initGame('Alice', true, {from: player1, gas: 2000000});

      // Watch for event from contract to check if it worked
      var filter = Chess.GameInitialized({});
      filter.watch(function(error, result){
        testGames[0] = result.args.gameId;
        assert.isOk(result.args.gameId);
        assert.equal('Alice', result.args.player1Alias);
        assert.equal(player1, result.args.player1);
        assert.equal(player1, result.args.playerWhite);
        filter.stopWatching(); // Need to remove filter again
        done();
      });
    });

    it('should broadcast the initial game state', function(done) {
      Chess.initGame('Bob', true, {from: player1, gas: 2000000});

      var eventGamestate = Chess.GameStateChanged({});
      eventGamestate.watch(function(error, result){
        let state = result.args.state.map(n => n.toNumber());
        assert.deepEqual(defaultBoard, state);
        eventGamestate.stopWatching(); // Need to remove filter again
        done();
      });
    });

    it('should initialize a game with player1 playing black', function (done) {
      Chess.initGame('Susan', false, {from: player1, gas: 2000000});

      // Watch for event from contract to check if it worked
      var filter = Chess.GameInitialized({});
      filter.watch(function(error, result){
        testGames[1] = result.args.gameId;
        assert.isOk(result.args.gameId);
        assert.equal('Susan', result.args.player1Alias);
        assert.equal(0, result.args.playerWhite);
        filter.stopWatching(); // Need to remove filter again
        done();
      });
    });
  });

  describe('joinGame()', function () {
    it('should join player2 as black if player1 is white', function(done) {
      assert.doesNotThrow(function(){
        Chess.joinGame(testGames[0], 'Bob', {from: player2, gas: 500000});
      }, Error);

      // Watch for event from contract to check if it worked
      var filter = Chess.GameJoined({gameId: testGames[0]});
      filter.watch(function(error, result){
        assert.equal(testGames[0], result.args.gameId);
        assert.equal(player2, result.args.player2);
        assert.equal(player1, result.args.player1);
        assert.equal('Bob', result.args.player2Alias);
        assert.equal('Alice', result.args.player1Alias);
        assert.equal(player1, result.args.playerWhite);
        filter.stopWatching(); // Need to remove filter again
        done();
      });
    });

    it('should disallow joining a game with two payers', function() {
      assert.throws(function(){
        Chess.joinGame(testGames[0], 'Bob', {from: player2, gas: 500000});
      }, Error);
    });

    it('should join player2 as white if player1 is black', function(done) {
      assert.doesNotThrow(function(){
        Chess.joinGame(testGames[1], 'Bob', {from: player2, gas: 500000});
      }, Error);

      // Watch for event from contract to check if it worked
      var filter = Chess.GameJoined({gameId: testGames[1]});
      filter.watch(function(error, result){
        assert.equal(testGames[1], result.args.gameId);
        assert.equal(player2, result.args.playerWhite);
        filter.stopWatching(); // Need to remove filter again
        done();
      });
    });
  });

  describe('move()', function () {
    it('should throw an exception when it is not this player\'s turn', function() {
      assert.throws(function(){
        Chess.move(testGames[0], 0, 0, {from: player2, gas: 500000});
      }, Error);
    });

    it('should throw an exception when P1 is black, so they cannot move first', function() {
      assert.throws(function(){
        Chess.move(testGames[1], 0, 0, {from: player1, gas: 500000});
      }, Error);
    });

    // TODO: Enable after finishing implementation of move validation
    it('should accept a valid move', function(done) {
      // As player1 is the next player, this move should be valid
      assert.doesNotThrow(function(){
        Chess.move(testGames[0], 96, 80, {from: player1, gas: 500000});
      }, Error);

      // Watch for event from contract to check if it worked
      var filter = Chess.Move({gameId: testGames[0]});
      filter.watch(function(error, result){
        assert.equal(player1, result.args.player);
        assert.equal(96, result.args.fromIndex);
        assert.equal(80, result.args.toIndex);
        filter.stopWatching(); // Need to remove filter again
        done();
      });
    });

    it('should have updated nextPlayer after the previous move', function() {
      assert.throws(function(){
        // Cannot move again from player1 because nextPlayer will be player2
        Chess.move(testGames[0], 0, 0, {from: player1, gas: 500000});
      }, Error);
    });
  });

  describe('surrender()', function () {
    // Setup a new game for this test
    let gameId;
    it('should initialize a new game and join both players', function(done) {
      Chess.initGame('Bob', true, {from: player1, gas: 2000000});
      var filter = Chess.GameInitialized({});
      filter.watch(function(error, result){
        gameId = result.args.gameId;
        filter.stopWatching();

        Chess.joinGame(gameId, 'Bob', {from: player2, gas: 500000});
        var filter2 = Chess.GameJoined({gameId: gameId});
        filter2.watch(function(){
          filter2.stopWatching();
          done();
        });
      });
    });

    it('should throw an exception for message from non-participant', function() {
      assert.throws(function(){
        Chess.surrender(gameId, {from: player3, gas: 500000});
      }, Error);
    });

    it('should allow surrender from P1 and declare P2 as winner', function(done) {
      Chess.surrender(gameId, {from: player1, gas: 500000});
      var filter = Chess.GameEnded({gameId: gameId});
      filter.watch(function(error, result){
        assert.equal(player2, result.args.winner);
        filter.stopWatching();
        done();
      });
    });

    it('should throw an exception when surrendering a game that already ended', function() {
      assert.throws(function(){
        Chess.surrender(gameId, {from: player2, gas: 500000});
      }, Error);
    });
  });

  // log game state changes
  /* Debugging
  var filter = Chess.GameStateChanged({});
  filter.watch(function(error, result){
    var rows = [];
    console.log(result.args.gameId, 'Game state changed');
    for (var i = 0; i < 8; i++) {
      var row = [];
      for (var j = 0; j < 8; j++) {
        row.push(result.args.state[i*8+j].toString(10));
      }
      rows.push(row.join(' '));
    }
    console.log(rows);
    filter.stopWatching();
  });
  */
});

<commit_msg>Add a few test cases for invalid moves. Should add one for every case in the validation<commit_after>/* global describe, it */
import { Chess, web3 } from '../contract/Chess.sol';

var assert = require('chai').assert;

const defaultBoard = [-4,-2,-3,-5,-6,-3,-2,-4,0,0,0,4,0,0,0,0,
                      -1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                      1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
                      4,2,3,5,6,3,2,4,0,0,0,116,0,0,0,0];

describe('Chess contract', function() {
  this.timeout(10000);
  this.slow(500);

  var testGames = [];
  const player1 = web3.eth.accounts[0];
  const player2 = web3.eth.accounts[1];
  const player3 = web3.eth.accounts[2];

  // Remove this for CI/deploy, otherwise the test never finishes
  /*
  var debugFilter = Chess.DebugInts({});
  debugFilter.watch(function(error, result){
    console.log(result.args.message,
                result.args.value1.toNumber(),
                result.args.value2.toNumber(),
                result.args.value3.toNumber());
  });
  */

  // We create a few test games here that will later be accessed in testGames[]
  describe('initGame()', function () {
    it('should initialize a game with player1 playing white', function (done) {
      Chess.initGame('Alice', true, {from: player1, gas: 2000000});

      // Watch for event from contract to check if it worked
      var filter = Chess.GameInitialized({});
      filter.watch(function(error, result){
        testGames[0] = result.args.gameId;
        assert.isOk(result.args.gameId);
        assert.equal('Alice', result.args.player1Alias);
        assert.equal(player1, result.args.player1);
        assert.equal(player1, result.args.playerWhite);
        filter.stopWatching(); // Need to remove filter again
        done();
      });
    });

    it('should broadcast the initial game state', function(done) {
      Chess.initGame('Bob', true, {from: player1, gas: 2000000});

      var eventGamestate = Chess.GameStateChanged({});
      eventGamestate.watch(function(error, result){
        let state = result.args.state.map(n => n.toNumber());
        assert.deepEqual(defaultBoard, state);
        eventGamestate.stopWatching(); // Need to remove filter again
        done();
      });
    });

    it('should initialize a game with player1 playing black', function (done) {
      Chess.initGame('Susan', false, {from: player1, gas: 2000000});

      // Watch for event from contract to check if it worked
      var filter = Chess.GameInitialized({});
      filter.watch(function(error, result){
        testGames[1] = result.args.gameId;
        assert.isOk(result.args.gameId);
        assert.equal('Susan', result.args.player1Alias);
        assert.equal(0, result.args.playerWhite);
        filter.stopWatching(); // Need to remove filter again
        done();
      });
    });
  });

  describe('joinGame()', function () {
    it('should join player2 as black if player1 is white', function(done) {
      assert.doesNotThrow(function(){
        Chess.joinGame(testGames[0], 'Bob', {from: player2, gas: 500000});
      }, Error);

      // Watch for event from contract to check if it worked
      var filter = Chess.GameJoined({gameId: testGames[0]});
      filter.watch(function(error, result){
        assert.equal(testGames[0], result.args.gameId);
        assert.equal(player2, result.args.player2);
        assert.equal(player1, result.args.player1);
        assert.equal('Bob', result.args.player2Alias);
        assert.equal('Alice', result.args.player1Alias);
        assert.equal(player1, result.args.playerWhite);
        filter.stopWatching(); // Need to remove filter again
        done();
      });
    });

    it('should disallow joining a game with two payers', function() {
      assert.throws(function(){
        Chess.joinGame(testGames[0], 'Bob', {from: player2, gas: 500000});
      }, Error);
    });

    it('should join player2 as white if player1 is black', function(done) {
      assert.doesNotThrow(function(){
        Chess.joinGame(testGames[1], 'Bob', {from: player2, gas: 500000});
      }, Error);

      // Watch for event from contract to check if it worked
      var filter = Chess.GameJoined({gameId: testGames[1]});
      filter.watch(function(error, result){
        assert.equal(testGames[1], result.args.gameId);
        assert.equal(player2, result.args.playerWhite);
        filter.stopWatching(); // Need to remove filter again
        done();
      });
    });
  });

  describe('move()', function () {
    it('should throw an exception when it is not this player\'s turn', function() {
      assert.throws(function(){
        Chess.move(testGames[0], 0, 0, {from: player2, gas: 500000});
      }, Error);
    });

    it('should throw an exception when P1 is black, so they cannot move first', function() {
      assert.throws(function(){
        Chess.move(testGames[1], 0, 0, {from: player1, gas: 500000});
      }, Error);
    });

    it('should throw an exception when a move is invalid', function() {
      // Test some invalid moves, but from correct player
      assert.throws(function(){
        // a1a1
        Chess.move(testGames[0], 0, 0, {from: player1, gas: 500000});
      }, Error);
      assert.throws(function(){
        // a8a7
        Chess.move(testGames[0], 112, 96, {from: player1, gas: 500000});
      }, Error);
      // TODO: Add more invalid moves
    });

    it('should accept a valid move', function(done) {
      // As player1 is the next player, this move should be valid
      assert.doesNotThrow(function(){
        // a7a6
        Chess.move(testGames[0], 96, 80, {from: player1, gas: 500000});
      }, Error);

      // Watch for event from contract to check if it worked
      var filter = Chess.Move({gameId: testGames[0]});
      filter.watch(function(error, result){
        assert.equal(player1, result.args.player);
        assert.equal(96, result.args.fromIndex);
        assert.equal(80, result.args.toIndex);
        filter.stopWatching(); // Need to remove filter again
        done();
      });
    });

    it('should have updated nextPlayer after the previous move', function() {
      assert.throws(function(){
        // Cannot move again from player1 because nextPlayer will be player2
        Chess.move(testGames[0], 0, 0, {from: player1, gas: 500000});
      }, Error);
    });
  });

  describe('surrender()', function () {
    // Setup a new game for this test
    let gameId;
    it('should initialize a new game and join both players', function(done) {
      Chess.initGame('Bob', true, {from: player1, gas: 2000000});
      var filter = Chess.GameInitialized({});
      filter.watch(function(error, result){
        gameId = result.args.gameId;
        filter.stopWatching();

        Chess.joinGame(gameId, 'Bob', {from: player2, gas: 500000});
        var filter2 = Chess.GameJoined({gameId: gameId});
        filter2.watch(function(){
          filter2.stopWatching();
          done();
        });
      });
    });

    it('should throw an exception for message from non-participant', function() {
      assert.throws(function(){
        Chess.surrender(gameId, {from: player3, gas: 500000});
      }, Error);
    });

    it('should allow surrender from P1 and declare P2 as winner', function(done) {
      Chess.surrender(gameId, {from: player1, gas: 500000});
      var filter = Chess.GameEnded({gameId: gameId});
      filter.watch(function(error, result){
        assert.equal(player2, result.args.winner);
        filter.stopWatching();
        done();
      });
    });

    it('should throw an exception when surrendering a game that already ended', function() {
      assert.throws(function(){
        Chess.surrender(gameId, {from: player2, gas: 500000});
      }, Error);
    });
  });

  // log game state changes
  /* Debugging
  var filter = Chess.GameStateChanged({});
  filter.watch(function(error, result){
    var rows = [];
    console.log(result.args.gameId, 'Game state changed');
    for (var i = 0; i < 8; i++) {
      var row = [];
      for (var j = 0; j < 8; j++) {
        row.push(result.args.state[i*8+j].toString(10));
      }
      rows.push(row.join(' '));
    }
    console.log(rows);
    filter.stopWatching();
  });
  */
});

<|endoftext|>


<commit_before>/**@license
 *  sysend.js - send messages between browser windows/tabs
 *  Copyright (C) 2014 Jakub Jankiewicz <http://jcubic.pl>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  The idea for this implementation came from this StackOverflow question:
 *  http://stackoverflow.com/q/24182409/387194
 */
var sysend = (function() {
    // we use id because storage event is not executed if message was not
    // changed, and we want it if user send same object twice
    var id = 0;
    function get(key) {
        return localStorage.getItem(key);
    }
    function set(key, value) {
        localStorage.setItem(key, value);
    }
    function remove(key) {
        localStorage.removeItem(key);
    }
    function to_json(message) {
        return JSON.stringify([id++, message]);
    }
    function from_json(json) {
        return JSON.parse(json)[1];
    }
    var callbacks = {};
    window.addEventListener('storage', function(e) {
        if (callbacks[e.key]) {
            var message = from_json(get(e.key));
            callbacks[e.key].forEach(function(fn) {
                fn(message, e.key);
            });
        }
    }, false);
    var timer;
    return {
        broadcast: function(event, message) {
            // undefined is not stringified
            set(event, to_json(message || null));
            cleanTimeout(timer);
            // clean up localstorage
            timer = setTimeout(function() {
                remove(event);
            }, 1000);
        },
        on: function(event, fn) {
            if (!callbacks[event]) {
                callbacks[event] = [];
            }
            callbacks[event].push(fn);
        },
        off: function(event, fn) {
            if (callbacks[event]) {
                if (fn) {
                    for (var i=callbacks[event].length; i--;) {
                        if (callbacks[event][i] == fn) {
                            callbacks[event].splice(i, 1);
                        }
                    }
                } else {
                    for (var i=callbacks[event].length; i--;) {
                        callbacks[event].splice(i, 1);
                    }
                }
            }
        }
    };
})();
<commit_msg>use uniq key; fix remove<commit_after>/**@license
 *  sysend.js - send messages between browser windows/tabs
 *  Copyright (C) 2014 Jakub Jankiewicz <http://jcubic.pl>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  The idea for this implementation came from this StackOverflow question:
 *  http://stackoverflow.com/q/24182409/387194
 */
var sysend = (function() {
    // we use prefix so `foo' event don't colide with `foo' locaStorage value
    var uniq_prefix = '___sysend___';
    // we use id because storage event is not executed if message was not
    // changed, and we want it if user send same object twice
    var id = 0;
    function get(key) {
        return localStorage.getItem(uniq_prefix + key);
    }
    function set(key, value) {
        localStorage.setItem(uniq_prefix + key, value);
    }
    function remove(key) {
        localStorage.removeItem(uniq_prefix + key);
    }
    function to_json(input) {
        var obj = [id++];
        if (typeof input != 'undefined') {
            obj.push(input);
        }
        return JSON.stringify(obj);
    }
    function from_json(json) {
        return JSON.parse(json);
    }
    var callbacks = {};
    window.addEventListener('storage', function(e) {
        var key = e.key.replace(new RegExp('^' + uniq_prefix), '');
        if (callbacks[key]) {
            var obj = JSON.parse(get(key));
            if (obj) {
                // don't call if removed
                callbacks[key].forEach(function(fn) {
                    fn(obj[1], key);
                });
            }
        }
    }, false);
    var timer;
    return {
        broadcast: function(event, message) {
            set(event, to_json(message));
            clearTimeout(timer);
            // clean up localstorage
            timer = setTimeout(function() {
                remove(event);
            }, 1000);
        },
        on: function(event, fn) {
            if (!callbacks[event]) {
                callbacks[event] = [];
            }
            callbacks[event].push(fn);
        },
        off: function(event, fn) {
            if (callbacks[event]) {
                if (fn) {
                    for (var i=callbacks[event].length; i--;) {
                        if (callbacks[event][i] == fn) {
                            callbacks[event].splice(i, 1);
                        }
                    }
                } else {
                    for (var i=callbacks[event].length; i--;) {
                        callbacks[event].splice(i, 1);
                    }
                }
            }
        }
    };
})();
<|endoftext|>


<commit_before>/*jslint node: true */
var express = require('express');
var session = require('express-session');
var path = require('path');
var swig = require('swig');
var q = require('q');
var logger = require('morgan');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var mongoClient = require('mongodb').MongoClient;

var GithubEvents = require('./routes/githubEvents');
var MongoRepository = require('./routes/mongoRepository');
var GithubOAuth = require('./routes/githubOAuth');
var QdService = require('./routes/qdService');
var app = express();

/*jslint nomen: true */
app.use(express.static(path.join(__dirname, 'public')));
/*jslint nomen: false */

app.use(logger());
app.use(cookieParser());
app.use(bodyParser.urlencoded({
    extended: true
}));

var winston = require('winston');
var filename = process.env.LOGGINGDIR ? path.join(process.env.LOGGINGDIR, 'github.log') : 'github.log';
winston.info('logging debug messages to ' + filename);
winston.add(winston.transports.File, { filename: filename, level: 'debug', json: false });
winston.error('Errors will be logged here');
winston.warn('Warns will be logged here');
winston.info('Info will be logged here');
winston.verbose('Verbose will be logged here');
winston.debug('Debug will be logged here');
winston.silly('Silly will be logged here');

winston.info('DBURI=' + process.env.DBURI);
var mongoUri = process.env.DBURI;

winston.info('PORT=' + process.env.PORT);
var port = process.env.PORT || 5001;

winston.info('APIURI=' + process.env.APIURI);

winston.info('SESSION_SECRET=' + process.env.SESSION_SECRET.substring(0,2) + '...');
var sessionSecret = process.env.SESSION_SECRET;

var logger = winston;

logger.logInfo = function(username, message, object){
    if(object) {
        logger.info(username + ': ' + message, object);
    }
    else {
        logger.info(username + ': ' + message, []);
    }
}

logger.logDebug = function(username, message, object){
    if(object) {
        logger.debug(username + ': ' + message, object);
    }
    else {
        logger.debug(username + ': ' + message, []);
    }
}

logger.logError = function(username, message, object){
    if(object) {
        logger.error(username + ': ' + message, object);
    }
    else {
        logger.error(username + ': ' + message, []);
    }
}

logger.logSilly = function(username, message, object){
    if(object) {
        logger.silly(username + ': ' + message, object);
    }
    else {
        logger.silly(username + ': ' + message, []);
    }
}

app.use(session({
    secret: sessionSecret,
    cookie: {
        maxAge: 2 * 365 * 24 * 60 * 60 * 1000, // 2 years
        secure: false // change to true when using https
    },
    resave: false, // don't save session if unmodified
    saveUninitialized: false // don't create session until something stored
}));

app.use(bodyParser.json());
app.engine('html', swig.renderFile);
app.set('views', __dirname + '/views');
app.set('view engine', 'html');

var attachLogger = function(req, res, next){
    req.logger = winston;
    next();
};
app.use(attachLogger);

var server = app.listen(port, function () {
    logger.logInfo('', 'Listening on ' + port);
});

var qdService = new QdService();

var mongoRepository;
var githubEvents;
var githubOAuth;
mongoClient.connect(mongoUri, function (err, databaseConnection) {
    if (err) {
        logger.logError('Could not connect to Mongodb with URI: ', [mongoUri, err]);
        process.exit(1);
    } else {
        logger.logInfo('connected to mongo: ', mongoUri);
        mongoRepository = new MongoRepository(databaseConnection);
        githubEvents = new GithubEvents(mongoRepository, qdService);
        githubOAuth = new GithubOAuth(app, mongoRepository, qdService);

        githubEvents.setLogger(logger);
    }
});

app.get('/', function (req, res) {
    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = req.headers.referer === undefined ? '/' : req.headers.referer.split('/').slice(0,3).join('/');
    process.env.appUri = req.session.appUri;
    req.session.oneselfUsername = req.query.username;
    req.session.registrationToken = req.query.token;
    logger.logInfo(req.query.username, 'github setup started: appUri, registrationToken', [req.session.appUri, req.query.token]);
    res.render('index');
});

app.get('/reauth', function (req, res) {
    if(req.query.username === undefined){
        res.render('reauthUnknownUser');
        return;
    }

    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = process.env.CONTEXT_URI;
    req.session.redirect = '/reauth/complete';
    req.session.reauth = true;
    req.session.username = req.query.username;
    logger.logInfo(req.query.username, 'reauthing', [req.session.appUri, req.query.token]);
    logger.logInfo(req.query.username, 'serving reauth page');
    res.render('reauth');
});

app.get('/reauth/complete', function (req, res) {
    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = null;
    req.session.redirect = null
    req.session.reauth = null;
    req.session.username = null;
    logger.logInfo(req.query.username, 'reauthing complete, ', [req.session.appUri, req.query.token]);
    logger.logDebug(req.query.username, 'serving reauth complete page');
    res.render('reauthcomplete');
});

// This is the entry point after auth, to do a sync. It's also used
// as the callback url in the stream
app.get('/authSuccess', function (req, res) {
    var githubUsername = req.query.username;
    var streamInfo = {
        streamid: req.query.streamid,
        writeToken: req.headers.authorization,
        lastSyncDate: req.query.latestSyncField
    };
    logger.logInfo(req.query.username, 'syncing data, [stream id, write token]', [streamInfo.streamid.substring(0, 2), streamInfo.writeToken.substring(0, 2)]);

    mongoRepository.findByGithubUsername(githubUsername)
        .then(function(user) {
            logger.logDebug(user.githubUsername, 'found in the database');
            var userInfo = {
                githubUsername: githubUsername,
                accessToken: user.accessToken,
                displayName: user.displayName,
                email: user.email
            };

            return githubEvents.sendGithubEvents(userInfo, streamInfo, process.env.appUri);
        })
        .catch(function(error){
            logger.logError(githubUsername, 'sync requested for unknown user', error);
        });

        res.status(200).send('ok, sync request acknowledged');
    }
);<commit_msg>correcting apiuri<commit_after>/*jslint node: true */
var express = require('express');
var session = require('express-session');
var path = require('path');
var swig = require('swig');
var q = require('q');
var logger = require('morgan');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var mongoClient = require('mongodb').MongoClient;

var GithubEvents = require('./routes/githubEvents');
var MongoRepository = require('./routes/mongoRepository');
var GithubOAuth = require('./routes/githubOAuth');
var QdService = require('./routes/qdService');
var app = express();

/*jslint nomen: true */
app.use(express.static(path.join(__dirname, 'public')));
/*jslint nomen: false */

app.use(logger());
app.use(cookieParser());
app.use(bodyParser.urlencoded({
    extended: true
}));

var winston = require('winston');
var filename = process.env.LOGGINGDIR ? path.join(process.env.LOGGINGDIR, 'github.log') : 'github.log';
winston.info('logging debug messages to ' + filename);
winston.add(winston.transports.File, { filename: filename, level: 'debug', json: false });
winston.error('Errors will be logged here');
winston.warn('Warns will be logged here');
winston.info('Info will be logged here');
winston.verbose('Verbose will be logged here');
winston.debug('Debug will be logged here');
winston.silly('Silly will be logged here');

winston.info('DBURI=' + process.env.DBURI);
var mongoUri = process.env.DBURI;

winston.info('PORT=' + process.env.PORT);
var port = process.env.PORT || 5001;

winston.info('APIURI=' + process.env.APIURI);

winston.info('SESSION_SECRET=' + process.env.SESSION_SECRET.substring(0,2) + '...');
var sessionSecret = process.env.SESSION_SECRET;

var logger = winston;

logger.logInfo = function(username, message, object){
    if(object) {
        logger.info(username + ': ' + message, object);
    }
    else {
        logger.info(username + ': ' + message, []);
    }
}

logger.logDebug = function(username, message, object){
    if(object) {
        logger.debug(username + ': ' + message, object);
    }
    else {
        logger.debug(username + ': ' + message, []);
    }
}

logger.logError = function(username, message, object){
    if(object) {
        logger.error(username + ': ' + message, object);
    }
    else {
        logger.error(username + ': ' + message, []);
    }
}

logger.logSilly = function(username, message, object){
    if(object) {
        logger.silly(username + ': ' + message, object);
    }
    else {
        logger.silly(username + ': ' + message, []);
    }
}

app.use(session({
    secret: sessionSecret,
    cookie: {
        maxAge: 2 * 365 * 24 * 60 * 60 * 1000, // 2 years
        secure: false // change to true when using https
    },
    resave: false, // don't save session if unmodified
    saveUninitialized: false // don't create session until something stored
}));

app.use(bodyParser.json());
app.engine('html', swig.renderFile);
app.set('views', __dirname + '/views');
app.set('view engine', 'html');

var attachLogger = function(req, res, next){
    req.logger = winston;
    next();
};
app.use(attachLogger);

var server = app.listen(port, function () {
    logger.logInfo('', 'Listening on ' + port);
});

var qdService = new QdService();

var mongoRepository;
var githubEvents;
var githubOAuth;
mongoClient.connect(mongoUri, function (err, databaseConnection) {
    if (err) {
        logger.logError('Could not connect to Mongodb with URI: ', [mongoUri, err]);
        process.exit(1);
    } else {
        logger.logInfo('connected to mongo: ', mongoUri);
        mongoRepository = new MongoRepository(databaseConnection);
        githubEvents = new GithubEvents(mongoRepository, qdService);
        githubOAuth = new GithubOAuth(app, mongoRepository, qdService);

        githubEvents.setLogger(logger);
    }
});

app.get('/', function (req, res) {
    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = req.headers.referer === undefined ? '/' : req.headers.referer.split('/').slice(0,3).join('/');
    process.env.appUri = req.session.appUri;
    req.session.oneselfUsername = req.query.username;
    req.session.registrationToken = req.query.token;
    logger.logInfo(req.query.username, 'github setup started: appUri, registrationToken', [req.session.appUri, req.query.token]);
    res.render('index');
});

app.get('/reauth', function (req, res) {
    if(req.query.username === undefined){
        res.render('reauthUnknownUser');
        return;
    }

    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = process.env.CONTEXT_URI;
    req.session.redirect = '/reauth/complete';
    req.session.reauth = true;
    req.session.username = req.query.username;
    logger.logInfo(req.query.username, 'reauthing', [req.session.appUri, req.query.token]);
    logger.logInfo(req.query.username, 'serving reauth page');
    res.render('reauth');
});

app.get('/reauth/complete', function (req, res) {
    //req.session.integrationUri = req.headers['x-forwarded-host'];
    req.session.appUri = null;
    req.session.redirect = null
    req.session.reauth = null;
    req.session.username = null;
    logger.logInfo(req.query.username, 'reauthing complete, ', [req.session.appUri, req.query.token]);
    logger.logDebug(req.query.username, 'serving reauth complete page');
    res.render('reauthcomplete');
});

// This is the entry point after auth, to do a sync. It's also used
// as the callback url in the stream
app.get('/authSuccess', function (req, res) {
    var githubUsername = req.query.username;
    var streamInfo = {
        streamid: req.query.streamid,
        writeToken: req.headers.authorization,
        lastSyncDate: req.query.latestSyncField
    };
    logger.logInfo(req.query.username, 'syncing data, [stream id, write token]', [streamInfo.streamid.substring(0, 2), streamInfo.writeToken.substring(0, 2)]);

    mongoRepository.findByGithubUsername(githubUsername)
        .then(function(user) {
            logger.logDebug(user.githubUsername, 'found in the database');
            var userInfo = {
                githubUsername: githubUsername,
                accessToken: user.accessToken,
                displayName: user.displayName,
                email: user.email
            };

            return githubEvents.sendGithubEvents(userInfo, streamInfo, process.env.APPURI);
        })
        .catch(function(error){
            logger.logError(githubUsername, 'sync requested for unknown user', error);
        });

        res.status(200).send('ok, sync request acknowledged');
    }
);<|endoftext|>


<commit_before><commit_msg>Fixed drag bug when initialised<commit_after><|endoftext|>


<commit_before>"use strict";

var CityTour = CityTour || {};

CityTour.RoadNetwork = function(terrain) {
  var Intersection = function(mapX, mapZ, height, surfaceType) {
    var edges = [];

    var addEdge = function(destinationMapX, destinationMapZ, distance, surfaceType) {
      var i;

      for(i = 0; i < edges.length; i++) {
        if (edges[i].destinationMapX === destinationMapX && edges[i].destinationMapZ === destinationMapZ) {
          edges[i].edge = { distance: distance, surfaceType: surfaceType };
          return;
        }
      }

      edges.push({ destinationMapX: destinationMapX, destinationMapZ: destinationMapZ, edge: { distance: distance, surfaceType: surfaceType }});
    };

    var removeEdge = function(mapX, mapZ) {
      var i, indexToRemove;

      for (i = 0; i < edges.length; i++) {
        if (edges[i].destinationMapX === mapX && edges[i].destinationMapZ == mapZ) {
          indexToRemove = i;
        }
      }

      if (indexToRemove !== undefined) {
        edges.splice(indexToRemove, 1);
      }
    };

    var hasEdgeTo = function(destinationMapX, destinationMapZ, surfaceType) {
      var i;

      for (i = 0; i < edges.length; i++) {
        if (edges[i].destinationMapX === destinationMapX && edges[i].destinationMapZ === destinationMapZ) {
          if (surfaceType) {
            return edges[i].edge.surfaceType === surfaceType;
          }
          else {
            return true;
          }
        }
      }

      return false;
    };

    var getEdge = function(destinationMapX, destinationMapZ) {
      var i;

      for (i = 0; i < edges.length; i++) {
        if (edges[i].destinationMapX === destinationMapX && edges[i].destinationMapZ === destinationMapZ) {
          return edges[i].edge;
        }
      }

      return undefined;
    };

    return {
      getHeight: function() { return height; },
      getSurfaceType: function() { return surfaceType; },
      addEdge: addEdge,
      removeEdge: removeEdge,
      hasEdgeTo: hasEdgeTo,
      getEdge: getEdge,
      edgesFrom: function() { return edges; },
      edgeCount: function() { return edges.length; },
    };
  };

  var minColumn = Number.POSITIVE_INFINITY, maxColumn = Number.NEGATIVE_INFINITY, minRow = Number.POSITIVE_INFINITY, maxRow = Number.NEGATIVE_INFINITY;
  var intersections = [];
  for (var mapX = Math.ceil(terrain.minMapX()); mapX <= Math.floor(terrain.maxMapX()); mapX++) {
    intersections[mapX] = [];
  }

  var hasIntersection = function(mapX, mapZ) {
    return intersections[mapX] !== undefined && intersections[mapX][mapZ] !== undefined;
  };

  var getIntersectionHeight = function(mapX, mapZ) {
    if (hasIntersection(mapX, mapZ)) {
      return intersections[mapX][mapZ].getHeight();
    }
    else {
      return undefined;
    }
  };

  var getRoadHeight = function(mapX, mapZ) {
    var xIsExact = Math.floor(mapX) === mapX;
    var zIsExact = Math.floor(mapZ) === mapZ;
    var floor, ceil;

    if (xIsExact && zIsExact) {
      return getIntersectionHeight(mapX, mapZ);
    }
    else if (xIsExact) {
      ceil = getIntersectionHeight(mapX, Math.ceil(mapZ));
      floor = getIntersectionHeight(mapX, Math.floor(mapZ));

      if (ceil !== undefined && floor !== undefined) {
        return CityTour.Math.lerp(floor, ceil, mapZ - Math.floor(mapZ));
      }
      else {
        return undefined;
      }
    }
    else if (zIsExact) {
      ceil = getIntersectionHeight(Math.ceil(mapX), mapZ);
      floor = getIntersectionHeight(Math.floor(mapX), mapZ);

      if (ceil !== undefined && floor !== undefined) {
        return CityTour.Math.lerp(floor, ceil, mapX - Math.floor(mapX));
      }
      else {
        return undefined;
      }
    }

    return undefined;
  };

  var getIntersectionSurfaceType = function(mapX, mapZ) {
    if (hasIntersection(mapX, mapZ)) {
      return intersections[mapX][mapZ].getSurfaceType();
    }
    else {
      return false;
    }
  };

  var addEdge = function(mapX1, mapZ1, mapX2, mapZ2, nonTerrainHeight, surfaceType) {
    var intersection1 = intersections[mapX1][mapZ1];
    var intersection2 = intersections[mapX2][mapZ2];
    var intersectionHeight, intersectionSurfaceType;

    if (!intersection1) {
      intersectionHeight = (terrain.waterHeightAtCoordinates(mapX1, mapZ1) === 0.0) ? terrain.heightAtCoordinates(mapX1, mapZ1) : nonTerrainHeight;
      intersectionSurfaceType = (terrain.waterHeightAtCoordinates(mapX1, mapZ1) === 0.0) ? CityTour.RoadNetwork.TERRAIN_SURFACE : CityTour.RoadNetwork.BRIDGE_SURFACE;
      intersection1 = new Intersection(mapX1, mapZ1, intersectionHeight, intersectionSurfaceType);
      intersections[mapX1][mapZ1] = intersection1;
    }

    if (!intersection2) {
      intersectionHeight = (terrain.waterHeightAtCoordinates(mapX2, mapZ2) === 0.0) ? terrain.heightAtCoordinates(mapX2, mapZ2) : nonTerrainHeight;
      intersectionSurfaceType = (terrain.waterHeightAtCoordinates(mapX2, mapZ2) === 0.0) ? CityTour.RoadNetwork.TERRAIN_SURFACE : CityTour.RoadNetwork.BRIDGE_SURFACE;
      intersection2 = new Intersection(mapX2, mapZ2, intersectionHeight, intersectionSurfaceType);
      intersections[mapX2][mapZ2] = intersection2;
    }

    intersection1.addEdge(mapX2, mapZ2, 1.0, surfaceType);
    intersection2.addEdge(mapX1, mapZ1, 1.0, surfaceType);

    minColumn = Math.min(minColumn, mapX1, mapX2);
    maxColumn = Math.max(maxColumn, mapX1, mapX2);
    minRow = Math.min(minRow, mapZ1, mapZ2);
    maxRow = Math.max(maxRow, mapZ1, mapZ2);
  };

  var removeEdge = function(mapX1, mapZ1, mapX2, mapZ2) {
    var intersection1 = (intersections[mapX1] === undefined) ? undefined : intersections[mapX1][mapZ1];
    var intersection2 = (intersections[mapX2] === undefined) ? undefined : intersections[mapX2][mapZ2];

    if (intersection1) {
      intersection1.removeEdge(mapX2, mapZ2);
      if (intersection1.edgeCount() === 0) {
        intersections[mapX1][mapZ1] = undefined;
      }
    }
    if (intersection2) {
      intersection2.removeEdge(mapX1, mapZ1);
      if (intersection2.edgeCount() === 0) {
        intersections[mapX2][mapZ2] = undefined;
      }
    }
  };

  var hasEdgeBetween = function(mapX1, mapZ1, mapX2, mapZ2, surfaceType) {
    var intersection1 = (intersections[mapX1] === undefined) ? undefined : intersections[mapX1][mapZ1];
    var intersection2 = (intersections[mapX2] === undefined) ? undefined : intersections[mapX2][mapZ2];

    return intersection1 !== undefined &&
           intersection2 !== undefined &&
           intersection1.hasEdgeTo(mapX2, mapZ2, surfaceType) && intersection2.hasEdgeTo(mapX1, mapZ1, surfaceType);
  };

  var edgeBetween = function(mapX1, mapZ1, mapX2, mapZ2) {
    var intersection1 = (intersections[mapX1] === undefined) ? undefined : intersections[mapX1][mapZ1];

    return (intersection1 === undefined) ? undefined : intersection1.getEdge(mapX2, mapZ2);
  };

  var edgesFrom = function(mapX, mapZ) {
    var intersection = (intersections[mapX] === undefined) ? undefined : intersections[mapX][mapZ];

    return (intersection === undefined) ? undefined : intersection.edgesFrom();
  };

  return {
    hasIntersection: hasIntersection,
    getRoadHeight: getRoadHeight,
    getIntersectionSurfaceType: getIntersectionSurfaceType,
    addEdge: addEdge,
    removeEdge: removeEdge,
    hasEdgeBetween: hasEdgeBetween,
    edgeBetween: edgeBetween,
    edgesFrom: edgesFrom,
    minColumn: function() { return minColumn; },
    maxColumn: function() { return maxColumn; },
    minRow: function() { return minRow; },
    maxRow: function() { return maxRow; },
  };
};

CityTour.RoadNetwork.TERRAIN_SURFACE = 'terrain';
CityTour.RoadNetwork.BRIDGE_SURFACE = 'bridge';
<commit_msg>Same edge object shared by both nodes of a road segment<commit_after>"use strict";

var CityTour = CityTour || {};

CityTour.RoadNetwork = function(terrain) {
  var Intersection = function(mapX, mapZ, height, surfaceType) {
    var edges = [];

    var addEdge = function(destinationMapX, destinationMapZ, edge) {
      var i;

      for(i = 0; i < edges.length; i++) {
        if (edges[i].destinationMapX === destinationMapX && edges[i].destinationMapZ === destinationMapZ) {
          edges[i].edge = edge;
          return;
        }
      }

      edges.push({ destinationMapX: destinationMapX, destinationMapZ: destinationMapZ, edge: edge});
    };

    var removeEdge = function(mapX, mapZ) {
      var i, indexToRemove;

      for (i = 0; i < edges.length; i++) {
        if (edges[i].destinationMapX === mapX && edges[i].destinationMapZ == mapZ) {
          indexToRemove = i;
        }
      }

      if (indexToRemove !== undefined) {
        edges.splice(indexToRemove, 1);
      }
    };

    var hasEdgeTo = function(destinationMapX, destinationMapZ, surfaceType) {
      var i;

      for (i = 0; i < edges.length; i++) {
        if (edges[i].destinationMapX === destinationMapX && edges[i].destinationMapZ === destinationMapZ) {
          if (surfaceType) {
            return edges[i].edge.surfaceType === surfaceType;
          }
          else {
            return true;
          }
        }
      }

      return false;
    };

    var getEdge = function(destinationMapX, destinationMapZ) {
      var i;

      for (i = 0; i < edges.length; i++) {
        if (edges[i].destinationMapX === destinationMapX && edges[i].destinationMapZ === destinationMapZ) {
          return edges[i].edge;
        }
      }

      return undefined;
    };

    return {
      getHeight: function() { return height; },
      getSurfaceType: function() { return surfaceType; },
      addEdge: addEdge,
      removeEdge: removeEdge,
      hasEdgeTo: hasEdgeTo,
      getEdge: getEdge,
      edgesFrom: function() { return edges; },
      edgeCount: function() { return edges.length; },
    };
  };

  var minColumn = Number.POSITIVE_INFINITY, maxColumn = Number.NEGATIVE_INFINITY, minRow = Number.POSITIVE_INFINITY, maxRow = Number.NEGATIVE_INFINITY;
  var intersections = [];
  for (var mapX = Math.ceil(terrain.minMapX()); mapX <= Math.floor(terrain.maxMapX()); mapX++) {
    intersections[mapX] = [];
  }

  var hasIntersection = function(mapX, mapZ) {
    return intersections[mapX] !== undefined && intersections[mapX][mapZ] !== undefined;
  };

  var getIntersectionHeight = function(mapX, mapZ) {
    if (hasIntersection(mapX, mapZ)) {
      return intersections[mapX][mapZ].getHeight();
    }
    else {
      return undefined;
    }
  };

  var getRoadHeight = function(mapX, mapZ) {
    var xIsExact = Math.floor(mapX) === mapX;
    var zIsExact = Math.floor(mapZ) === mapZ;
    var floor, ceil;

    if (xIsExact && zIsExact) {
      return getIntersectionHeight(mapX, mapZ);
    }
    else if (xIsExact) {
      ceil = getIntersectionHeight(mapX, Math.ceil(mapZ));
      floor = getIntersectionHeight(mapX, Math.floor(mapZ));

      if (ceil !== undefined && floor !== undefined) {
        return CityTour.Math.lerp(floor, ceil, mapZ - Math.floor(mapZ));
      }
      else {
        return undefined;
      }
    }
    else if (zIsExact) {
      ceil = getIntersectionHeight(Math.ceil(mapX), mapZ);
      floor = getIntersectionHeight(Math.floor(mapX), mapZ);

      if (ceil !== undefined && floor !== undefined) {
        return CityTour.Math.lerp(floor, ceil, mapX - Math.floor(mapX));
      }
      else {
        return undefined;
      }
    }

    return undefined;
  };

  var getIntersectionSurfaceType = function(mapX, mapZ) {
    if (hasIntersection(mapX, mapZ)) {
      return intersections[mapX][mapZ].getSurfaceType();
    }
    else {
      return false;
    }
  };

  var addEdge = function(mapX1, mapZ1, mapX2, mapZ2, nonTerrainHeight, surfaceType) {
    var intersection1 = intersections[mapX1][mapZ1];
    var intersection2 = intersections[mapX2][mapZ2];
    var intersectionHeight, intersectionSurfaceType;
    var edge = { distance: 1.0, surfaceType: surfaceType };

    if (!intersection1) {
      intersectionHeight = (terrain.waterHeightAtCoordinates(mapX1, mapZ1) === 0.0) ? terrain.heightAtCoordinates(mapX1, mapZ1) : nonTerrainHeight;
      intersectionSurfaceType = (terrain.waterHeightAtCoordinates(mapX1, mapZ1) === 0.0) ? CityTour.RoadNetwork.TERRAIN_SURFACE : CityTour.RoadNetwork.BRIDGE_SURFACE;
      intersection1 = new Intersection(mapX1, mapZ1, intersectionHeight, intersectionSurfaceType);
      intersections[mapX1][mapZ1] = intersection1;
    }

    if (!intersection2) {
      intersectionHeight = (terrain.waterHeightAtCoordinates(mapX2, mapZ2) === 0.0) ? terrain.heightAtCoordinates(mapX2, mapZ2) : nonTerrainHeight;
      intersectionSurfaceType = (terrain.waterHeightAtCoordinates(mapX2, mapZ2) === 0.0) ? CityTour.RoadNetwork.TERRAIN_SURFACE : CityTour.RoadNetwork.BRIDGE_SURFACE;
      intersection2 = new Intersection(mapX2, mapZ2, intersectionHeight, intersectionSurfaceType);
      intersections[mapX2][mapZ2] = intersection2;
    }

    intersection1.addEdge(mapX2, mapZ2, edge);
    intersection2.addEdge(mapX1, mapZ1, edge);

    minColumn = Math.min(minColumn, mapX1, mapX2);
    maxColumn = Math.max(maxColumn, mapX1, mapX2);
    minRow = Math.min(minRow, mapZ1, mapZ2);
    maxRow = Math.max(maxRow, mapZ1, mapZ2);
  };

  var removeEdge = function(mapX1, mapZ1, mapX2, mapZ2) {
    var intersection1 = (intersections[mapX1] === undefined) ? undefined : intersections[mapX1][mapZ1];
    var intersection2 = (intersections[mapX2] === undefined) ? undefined : intersections[mapX2][mapZ2];

    if (intersection1) {
      intersection1.removeEdge(mapX2, mapZ2);
      if (intersection1.edgeCount() === 0) {
        intersections[mapX1][mapZ1] = undefined;
      }
    }
    if (intersection2) {
      intersection2.removeEdge(mapX1, mapZ1);
      if (intersection2.edgeCount() === 0) {
        intersections[mapX2][mapZ2] = undefined;
      }
    }
  };

  var hasEdgeBetween = function(mapX1, mapZ1, mapX2, mapZ2, surfaceType) {
    var intersection1 = (intersections[mapX1] === undefined) ? undefined : intersections[mapX1][mapZ1];
    var intersection2 = (intersections[mapX2] === undefined) ? undefined : intersections[mapX2][mapZ2];

    return intersection1 !== undefined &&
           intersection2 !== undefined &&
           intersection1.hasEdgeTo(mapX2, mapZ2, surfaceType) && intersection2.hasEdgeTo(mapX1, mapZ1, surfaceType);
  };

  var edgeBetween = function(mapX1, mapZ1, mapX2, mapZ2) {
    var intersection1 = (intersections[mapX1] === undefined) ? undefined : intersections[mapX1][mapZ1];

    return (intersection1 === undefined) ? undefined : intersection1.getEdge(mapX2, mapZ2);
  };

  var edgesFrom = function(mapX, mapZ) {
    var intersection = (intersections[mapX] === undefined) ? undefined : intersections[mapX][mapZ];

    return (intersection === undefined) ? undefined : intersection.edgesFrom();
  };

  return {
    hasIntersection: hasIntersection,
    getRoadHeight: getRoadHeight,
    getIntersectionSurfaceType: getIntersectionSurfaceType,
    addEdge: addEdge,
    removeEdge: removeEdge,
    hasEdgeBetween: hasEdgeBetween,
    edgeBetween: edgeBetween,
    edgesFrom: edgesFrom,
    minColumn: function() { return minColumn; },
    maxColumn: function() { return maxColumn; },
    minRow: function() { return minRow; },
    maxRow: function() { return maxRow; },
  };
};

CityTour.RoadNetwork.TERRAIN_SURFACE = 'terrain';
CityTour.RoadNetwork.BRIDGE_SURFACE = 'bridge';
<|endoftext|>


<commit_before>
/**
 *  Application
 */

define([
  'require',
  'skeleton/app'
], function(require, SkeletonApp){

  'use strict';

  var App = SkeletonApp.extend({

    // Add your custom code here

  });

  return new App();

});<commit_msg>Removed unused dependency from app.<commit_after>
/**
 *  Application
 */

define([
  'skeleton/app'
], function(SkeletonApp){

  'use strict';

  var App = SkeletonApp.extend({

    // Add your custom code here

  });

  return new App();

});<|endoftext|>


<commit_before>app.directive("currentProfile", ["profileService", function(profileService){
	return({
		// detect current profile based on visibility
		link: function postLink(scope) {
			console.log("???");
			scope.getCurrentProfile = function() {
				profileService.fetchCurrent(true)
					.then(function(result) {
						if (result.data.status === 200) {
							$scope.profile = result.data.data;
						} else {
							$scope.alerts[0] = {
								type: "danger",
								msg: "You are not logged in."
							};
						}
					});
			};
		},
		restrict: "E",
		template: "",
		transclude: true
	});
}]);<commit_msg>Currently doesn't work https://app.asana.com/0/84113659891181/91309023675436<commit_after>app.directive("currentProfile", ["profileService", function(profileService){
	return({
		// detect current profile based on visibility
		link: function postLink(scope, element, attrs, ctrl, transclude) {
			console.log("???");
			scope.getCurrentProfile = function() {
				profileService.fetchCurrent(true)
					.then(function(result) {
						if (result.data.status === 200) {
							$scope.profile = result.data.data;
						} else {
							$scope.alerts[0] = {
								type: "danger",
								msg: "You are not logged in."
							};
						}
					});
			};
		},
		restrict: "E",
		template: "",
		transclude: true,
		scope: {
			target: "="
		}
	});
}]);<|endoftext|>


<commit_before>import React from 'react';
import Transition from 'react-addons-css-transition-group';
import { Link } from 'react-router';

var MobileListItem = React.createClass({
	displayName: 'MobileListItem',
	propTypes: {
		children: React.PropTypes.node.isRequired,
		className: React.PropTypes.string,
		href: React.PropTypes.string.isRequired,
	},
	render () {
		return (
			<Link className={this.props.className} to={this.props.href} tabIndex="-1">
				{this.props.children}
			</Link>
		);
	},
});

var MobileSectionItem = React.createClass({
	displayName: 'MobileSectionItem',
	propTypes: {
		children: React.PropTypes.node.isRequired,
		className: React.PropTypes.string,
		currentListKey: React.PropTypes.string,
		href: React.PropTypes.string.isRequired,
		lists: React.PropTypes.array,
	},
	// TODO FIX THIS
	renderLists () {
		if (!this.props.lists || this.props.lists.length <= 1) return null;

		const navLists = this.props.lists.map((item) => {
			const href = item.external ? item.path : `${Keystone.adminPath}/${item.path}`;
			const className = (this.props.currentListKey && this.props.currentListKey === item.path) ? 'MobileNavigation__list-item is-active' : 'MobileNavigation__list-item';

			return (
				<MobileListItem key={item.path} href={href} className={className}>
					{item.label}
				</MobileListItem>
			);
		});

		return (

				{navLists}

		);
	},
	render () {
		return (

					{this.props.children}

				{this.renderLists()}

		);
	},
});

var MobileNavigation = React.createClass({
	displayName: 'MobileNavigation',
	propTypes: {
		brand: React.PropTypes.string,
		currentListKey: React.PropTypes.string,
		currentSectionKey: React.PropTypes.string,
		sections: React.PropTypes.array.isRequired,
		signoutUrl: React.PropTypes.string,
	},
	getInitialState () {
		return {
			barIsVisible: false,
		};
	},
	componentDidMount () {
		this.handleResize();
		window.addEventListener('resize', this.handleResize);
	},
	componentWillUnmount () {
		window.removeEventListener('resize', this.handleResize);
	},
	handleResize () {
		this.setState({
			barIsVisible: window.innerWidth < 768,
		});
	},
	toggleMenu () {
		this[this.state.menuIsVisible ? 'hideMenu' : 'showMenu']();
	},
	showMenu () {
		this.setState({
			menuIsVisible: true,
		});

		document.body.style.overflow = 'hidden';
		document.body.addEventListener('keyup', this.handleEscapeKey, false);
	},
	hideMenu () {
		this.setState({
			menuIsVisible: false,
		});

		document.body.style.overflow = null;
		document.body.removeEventListener('keyup', this.handleEscapeKey, false);
	},
	handleEscapeKey (event) {
		const escapeKeyCode = 27;

		if (event.which === escapeKeyCode) {
			this.hideMenu();
		}
	},
	renderNavigation () {
		if (!this.props.sections || !this.props.sections.length) return null;

		return this.props.sections.map((section) => {
			const href = section.lists[0].external ? section.lists[0].path : `${Keystone.adminPath}/${section.lists[0].path}`;
			const className = (this.props.currentSectionKey && this.props.currentSectionKey === section.key) ? 'MobileNavigation__section is-active' : 'MobileNavigation__section';

			return (
				<MobileSectionItem key={section.key} className={className} href={href} lists={section.lists} currentListKey={this.props.currentListKey}>
					{section.label}
				</MobileSectionItem>
			);
		});
	},
	renderBlockout () {
		if (!this.state.menuIsVisible) return null;

		return
;
	},
	renderMenu () {
		if (!this.state.menuIsVisible) return null;

		return (

					{this.renderNavigation()}

		);
	},
	render () {
		if (!this.state.barIsVisible) return null;

		return (

					<button type="button" onClick={this.toggleMenu} className="MobileNavigation__bar__button MobileNavigation__bar__button--menu">

					</button>
					{this.props.brand}

				<Transition transitionName="MobileNavigation__menu" transitionEnterTimeout={260} transitionLeaveTimeout={200}>
					{this.renderMenu()}
				</Transition>
				<Transition transitionName="react-transitiongroup-fade">
					{this.renderBlockout()}
				</Transition>

		);
	},
});

module.exports = MobileNavigation;
<commit_msg>Fix mobile navigation<commit_after>import React from 'react';
import Transition from 'react-addons-css-transition-group';
import { Link } from 'react-router';

var MobileListItem = React.createClass({
	displayName: 'MobileListItem',
	propTypes: {
		children: React.PropTypes.node.isRequired,
		className: React.PropTypes.string,
		href: React.PropTypes.string.isRequired,
	},
	render () {
		return (
			<Link className={this.props.className} to={this.props.href} tabIndex="-1">
				{this.props.children}
			</Link>
		);
	},
});

var MobileSectionItem = React.createClass({
	displayName: 'MobileSectionItem',
	propTypes: {
		children: React.PropTypes.node.isRequired,
		className: React.PropTypes.string,
		currentListKey: React.PropTypes.string,
		href: React.PropTypes.string.isRequired,
		lists: React.PropTypes.array,
	},
	// TODO FIX THIS
	renderLists () {
		if (!this.props.lists || this.props.lists.length <= 1) return null;

		const navLists = this.props.lists.map((item) => {
			const href = item.external ? item.path : `${Keystone.adminPath}/${item.path}`;
			const className = (this.props.currentListKey && this.props.currentListKey === item.path) ? 'MobileNavigation__list-item is-active' : 'MobileNavigation__list-item';

			return (
				<MobileListItem key={item.path} href={href} className={className}>
					{item.label}
				</MobileListItem>
			);
		});

		return (

				{navLists}

		);
	},
	render () {
		return (

				<Link className="MobileNavigation__section-item" to={this.props.href} tabIndex="-1">
					{this.props.children}
				</Link>
				{this.renderLists()}

		);
	},
});

var MobileNavigation = React.createClass({
	displayName: 'MobileNavigation',
	propTypes: {
		brand: React.PropTypes.string,
		currentListKey: React.PropTypes.string,
		currentSectionKey: React.PropTypes.string,
		sections: React.PropTypes.array.isRequired,
		signoutUrl: React.PropTypes.string,
	},
	getInitialState () {
		return {
			barIsVisible: false,
		};
	},
	componentDidMount () {
		this.handleResize();
		window.addEventListener('resize', this.handleResize);
	},
	componentWillUnmount () {
		window.removeEventListener('resize', this.handleResize);
	},
	handleResize () {
		this.setState({
			barIsVisible: window.innerWidth < 768,
		});
	},
	toggleMenu () {
		this[this.state.menuIsVisible ? 'hideMenu' : 'showMenu']();
	},
	showMenu () {
		this.setState({
			menuIsVisible: true,
		});

		document.body.style.overflow = 'hidden';
		document.body.addEventListener('keyup', this.handleEscapeKey, false);
	},
	hideMenu () {
		this.setState({
			menuIsVisible: false,
		});

		document.body.style.overflow = null;
		document.body.removeEventListener('keyup', this.handleEscapeKey, false);
	},
	handleEscapeKey (event) {
		const escapeKeyCode = 27;

		if (event.which === escapeKeyCode) {
			this.hideMenu();
		}
	},
	renderNavigation () {
		if (!this.props.sections || !this.props.sections.length) return null;

		return this.props.sections.map((section) => {
			const href = section.lists[0].external ? section.lists[0].path : `${Keystone.adminPath}/${section.lists[0].path}`;
			const className = (this.props.currentSectionKey && this.props.currentSectionKey === section.key) ? 'MobileNavigation__section is-active' : 'MobileNavigation__section';

			return (
				<MobileSectionItem
					key={section.key}
					className={className}
					href={href}
					lists={section.lists}
					currentListKey={this.props.currentListKey}
				>
					{section.label}
				</MobileSectionItem>
			);
		});
	},
	renderBlockout () {
		if (!this.state.menuIsVisible) return null;

		return
;
	},
	renderMenu () {
		if (!this.state.menuIsVisible) return null;

		return (

					{this.renderNavigation()}

		);
	},
	render () {
		if (!this.state.barIsVisible) return null;

		return (

					<button type="button" onClick={this.toggleMenu} className="MobileNavigation__bar__button MobileNavigation__bar__button--menu">

					</button>
					{this.props.brand}

				<Transition transitionName="MobileNavigation__menu" transitionEnterTimeout={260} transitionLeaveTimeout={200}>
					{this.renderMenu()}
				</Transition>
				<Transition transitionName="react-transitiongroup-fade">
					{this.renderBlockout()}
				</Transition>

		);
	},
});

module.exports = MobileNavigation;
<|endoftext|>


<commit_before>'use strict';

var SETS = 'dataType';
var LABELS = 'bindingsCount';
var VALUES = 'scriptTime';
var FILTERS = [{
  key: 'dataSize',
  value: function (val) {
    return val === 5;
  }
}];
var DIR_NAME = '../log/';
var CHART_DIR = '../charts/';
var RenderData = require('./RenderData');
var Filter = require('./Filter');
var FilterRule = require('./FilterRule');
var ChartRenderer = require('./ChartRenderer');

var dataFilter = new Filter(FILTERS.map(function (f) {
  return new FilterRule(f.key, f.value);
}));

var fs = require('fs');
var path = require('path');
var files = fs.readdirSync(DIR_NAME);

files = files.filter(function (f) {
  return fs.statSync(path.join(DIR_NAME, f)).isFile();
});

// Elegant but not efficient, requires memory...
var logs = files.map(function (file) {
  return require('./' + path.join(DIR_NAME, file));
}).filter(function (data) {
  return dataFilter.filter(data.description.description);
});

var renderData = new RenderData(SETS, LABELS, VALUES);
renderData.process(logs);
var data = renderData.aggregate();
var labels = data[0].labels;

var chart = ChartRenderer.generate(labels, data);
var filters = FILTERS.map(function (f) {
  return f.key;
}).join('-');
console.log(filters);
ChartRenderer.save(chart, path.join(CHART_DIR) + filters + '.png');
<commit_msg>Update log parser<commit_after>'use strict';

var SETS = 'dataType';
var LABELS = 'bindingsCount';
var VALUES = 'scriptTime';
var FILTERS = [{
  key: 'dataSize',
  value: function (val) {
    return val === 5;
  }
}];
var DIR_NAME = './log/';
var CHART_DIR = './charts/';
var RenderData = require('./RenderData');
var Filter = require('./Filter');
var FilterRule = require('./FilterRule');
var ChartRenderer = require('./ChartRenderer');

var dataFilter = new Filter(FILTERS.map(function (f) {
  return new FilterRule(f.key, f.value);
}));

var fs = require('fs');
var path = require('path');
var files = fs.readdirSync(DIR_NAME);

files = files.filter(function (f) {
  return fs.statSync(path.join(DIR_NAME, f)).isFile();
});

// Elegant but not efficient, requires memory...
var logs = files.map(function (file) {
  return require('./' + path.join(DIR_NAME, file));
}).filter(function (data) {
  return dataFilter.filter(data.description.description);
});

var renderData = new RenderData(SETS, LABELS, VALUES);
renderData.process(logs);
var data = renderData.aggregate();
var labels = data[0].labels;

var chart = ChartRenderer.generate(labels, data);
var filters = FILTERS.map(function (f) {
  return f.key;
}).join('-');

ChartRenderer.save(chart, path.join(CHART_DIR) + filters + '.png');
<|endoftext|>


<commit_before>var fs = require('fs')
var path = require('path')
var util = require('util')
var mqtt = require('mqtt');
var express = require('express')
var morgan = require('morgan')
var bodyParser = require('body-parser')
var parameterize = require('parameterize')

var config_dir = process.env.CONFIG_DIR || './config'
var config = require(config_dir + '/config.json');

var harmonyHubDiscover = require('harmonyhubjs-discover')
var harmony = require('harmonyhubjs-client')

var harmonyHubClients = {}
var harmonyActivitiesCache = {}
var harmonyActivityUpdateInterval = 1*60*1000 // 1 minute
var harmonyActivityUpdateTimers = {}

var harmonyHubStates = {}
var harmonyStateUpdateInterval = 5*1000 // 5 seconds
var harmonyStateUpdateTimers = {}

var harmonyDevicesCache = {}
var harmonyDeviceUpdateInterval = 1*60*1000 // 1 minute
var harmonyDeviceUpdateTimers = {}

var mqttClient = config.hasOwnProperty("mqtt_options") ?
    mqtt.connect(config.mqtt_host, config.mqtt_options) :
    mqtt.connect(config.mqtt_host);
var TOPIC_NAMESPACE = config.topic_namespace || "harmony-api";

var app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(express.static(path.join(__dirname, 'public')));

var logFormat = "'[:date[iso]] - :remote-addr - :method :url :status :response-time ms - :res[content-length]b'"
app.use(morgan(logFormat))

// Middleware
// Check to make sure we have a harmonyHubClient to connect to
var hasHarmonyHubClient = function(req, res, next) {
  if (Object.keys(harmonyHubClients).length > 0) {
    next()
  }else{
    res.status(500).json({message: "No hubs available."})
  }
}
app.use(hasHarmonyHubClient)

var discover = new harmonyHubDiscover(61991)

discover.on('online', function(hubInfo) {
  // Triggered when a new hub was found
  console.log('Hub discovered: ' + hubInfo.friendlyName + ' at ' + hubInfo.ip + '.')

  if (hubInfo.ip) {
    harmony(hubInfo.ip).then(function(client){
      startProcessing(parameterize(hubInfo.friendlyName), client)
    })
  }

})

discover.on('offline', function(hubInfo) {
  // Triggered when a hub disappeared
  console.log('Hub lost: ' + hubInfo.friendlyName + ' at ' + hubInfo.ip + '.')
  hubSlug = parameterize(hubInfo.friendlyName)

  clearInterval(harmonyStateUpdateTimers[hubSlug])
  clearInterval(harmonyActivityUpdateTimers[hubSlug])
  delete(harmonyHubClients[hubSlug])
  delete(harmonyActivitiesCache[hubSlug])
  delete(harmonyHubStates[hubSlug])
})

// Look for hubs:
console.log('Starting discovery.')
discover.start()

// mqtt api

mqttClient.on('connect', function () {
  mqttClient.subscribe(TOPIC_NAMESPACE + '/hubs/+/activities/+/command')
});

mqttClient.on('message', function (topic, message) {
  var commandPattern = new RegExp(/hubs\/(.*)\/activities\/(.*)\/command/);
  var commandMatches = topic.match(commandPattern);

  if (commandMatches) {
    var hubSlug = commandMatches[1]
    var activitySlug = commandMatches[2]
    var state = message.toString()

    activity = activityBySlugs(hubSlug, activitySlug)
    if (!activity) { return }

    if (state === 'on') {
      startActivity(hubSlug, activity.id)
    }else if (state === 'off'){
      off(hubSlug)
    }
  }

});

function startProcessing(hubSlug, harmonyClient){
  harmonyHubClients[hubSlug] = harmonyClient

  // update the list of activities
  updateActivities(hubSlug)
  // then do it on the set interval
  clearInterval(harmonyActivityUpdateTimers[hubSlug])
  harmonyActivityUpdateTimers[hubSlug] = setInterval(function(){ updateActivities(hubSlug) }, harmonyActivityUpdateInterval)

  // update the state
  updateState(hubSlug)
  // update the list of activities on the set interval
  clearInterval(harmonyStateUpdateTimers[hubSlug])
  harmonyStateUpdateTimers[hubSlug] = setInterval(function(){ updateState(hubSlug) }, harmonyStateUpdateInterval)

  // update devices
  updateDevices(hubSlug)
  // update the list of devices on the set interval
  clearInterval(harmonyDeviceUpdateTimers[hubSlug])
  harmonyDeviceUpdateTimers[hubSlug] = setInterval(function(){ updateDevices(hubSlug) }, harmonyDeviceUpdateInterval)
}

function updateActivities(hubSlug){
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (!harmonyHubClient) { return }
  console.log('Updating activities for ' + hubSlug + '.')

  try {
    harmonyHubClient.getActivities().then(function(activities){
      foundActivities = {}
      activities.some(function(activity) {
        foundActivities[activity.id] = {id: activity.id, slug: parameterize(activity.label), label:activity.label, isAVActivity: activity.isAVActivity}
      })

      harmonyActivitiesCache[hubSlug] = foundActivities
    })
  } catch(err) {
    console.log("ERROR: " + err.message);
  }

}

function updateState(hubSlug){
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (!harmonyHubClient) { return }
  console.log('Updating state for ' + hubSlug + '.')

  // save for comparing later after we get the true current state
  var previousActivity = currentActivity(hubSlug)

  try {
    harmonyHubClient.getCurrentActivity().then(function(activityId){
      data = {off: true}

      activity = harmonyActivitiesCache[hubSlug][activityId]

      if (activityId != -1 && activity) {
        data = {off: false, current_activity: activity}
      }else{
        data = {off: true, current_activity: activity}
      }

      // cache state for later
      harmonyHubStates[hubSlug] = data

      if (!previousActivity || (activity.id != previousActivity.id)) {
        publish('hubs/' + hubSlug + '/' + 'current_activity', activity.slug, {retain: true})
        publish('hubs/' + hubSlug + '/' + 'state', activity.id == -1 ? 'off' : 'on' , {retain: true})

        for (var i = 0; i < cachedHarmonyActivities(hubSlug).length; i++) {
          activities = cachedHarmonyActivities(hubSlug)
          cachedActivity = activities[i]

          if (activity == cachedActivity) {
            publish('hubs/' + hubSlug + '/' + 'activities/' + cachedActivity.slug + '/state', 'on', {retain: true})
          }else{
            publish('hubs/' + hubSlug + '/' + 'activities/' + cachedActivity.slug + '/state', 'off', {retain: true})
          }
        }
      }

    })
  } catch(err) {
    console.log("ERROR: " + err.message);
  }

}

function updateDevices(hubSlug){
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (!harmonyHubClient) { return }
  console.log('Updating devices for ' + hubSlug + '.')
  try {
    harmonyHubClient.getAvailableCommands().then(function(commands) {
      foundDevices = {}
      commands.device.some(function(device) {
        deviceCommands = {}
        device.controlGroup.some(function(group) {
          group.function.some(function(func) {
            deviceCommands[func.name] = {action:func.action, label:func.label}
          })
        })
        foundDevices[device.id] = {id: device.id, slug: parameterize(device.label), label:device.label, commands:deviceCommands}
      })

      harmonyDevicesCache[hubSlug] = foundDevices
    })

  } catch(err) {
    console.log("Devices ERROR: " + err.message);
  }
}

function cachedHarmonyActivities(hubSlug){
  activities = harmonyActivitiesCache[hubSlug]
  if (!activities) { return [] }

  return Object.keys(harmonyActivitiesCache[hubSlug]).map(function(key) {
    return harmonyActivitiesCache[hubSlug][key]
  })
}

function currentActivity(hubSlug){
  harmonyHubClient = harmonyHubClients[hubSlug]
  harmonyHubState = harmonyHubStates[hubSlug]
  if (!harmonyHubClient || !harmonyHubState) { return null}

  return harmonyHubState.current_activity
}

function activityBySlugs(hubSlug, activitySlug){
  var activity
  cachedHarmonyActivities(hubSlug).some(function(a) {
    if(a.slug === activitySlug) {
      activity = a
      return true
    }
  })

  return activity
}

function cachedHarmonyDevices(hubSlug){
  devices = harmonyDevicesCache[hubSlug]
  if (!devices) { return [] }

  return Object.keys(harmonyDevicesCache[hubSlug]).map(function(key) {
    return harmonyDevicesCache[hubSlug][key]
  })
}

function off(hubSlug){
  harmonyHubClient = harmonyHubClients[hubSlug]
  if (!harmonyHubClient) { return }

  harmonyHubClient.turnOff().then(function(){
    updateState(hubSlug)
  })
}

function startActivity(hubSlug, activityId){
  harmonyHubClient = harmonyHubClients[hubSlug]
  if (!harmonyHubClient) { return }

  harmonyHubClient.startActivity(activityId).then(function(){
    updateState(hubSlug)
  })
}

function publish(topic, message, options){
  topic = TOPIC_NAMESPACE + "/" + topic
  mqttClient.publish(topic, message, options);
}

app.get('/_ping', function(req, res){
  res.send('OK');
})

app.get('/', function(req, res){
  res.sendfile('index.html');
})

app.get('/hubs', function(req, res){
  res.json({hubs: Object.keys(harmonyHubClients)})
})

app.get('/hubs/:hubSlug/activities', function(req, res){
  hubSlug = req.params.hubSlug
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (harmonyHubClient) {
    res.json({activities: cachedHarmonyActivities(hubSlug)})
  }else{
    res.status(404).json({message: "Not Found"})
  }
})

app.get('/hubs/:hubSlug/status', function(req, res){
  hubSlug = req.params.hubSlug
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (harmonyHubClient) {
    res.json(harmonyHubStates[hubSlug])
  }else{
    res.status(404).json({message: "Not Found"})
  }
})

app.put('/hubs/:hubSlug/off', function(req, res){
  hubSlug = req.params.hubSlug
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (harmonyHubClient) {
    off(hubSlug)
    res.json({message: "ok"})
  }else{
    res.status(404).json({message: "Not Found"})
  }
})

app.post('/hubs/:hubSlug/start_activity', function(req, res){
  activity = activityBySlugs(req.params.hubSlug, req.query.activity)

  if (activity) {
    startActivity(req.params.hubSlug, activity.id)

    res.json({message: "ok"})
  }else{
    res.status(404).json({message: "Not Found"})
  }
})

app.get('/hubs_for_index', function(req, res){
  hubSlugs = Object.keys(harmonyHubClients)
  output = ""

  Object.keys(harmonyHubClients).forEach(function(hubSlug) {
    output += '
' + hubSlug.replace('-', ' ') + '
'
    output += '
GET /hubs/' + hubSlug + '/status
'
    output += '
GET /hubs/' + hubSlug + '/activities
'
  });

  res.send(output)
})

app.listen(process.env.PORT || 8282)
<commit_msg>Add devices to HTTP API<commit_after>var fs = require('fs')
var path = require('path')
var util = require('util')
var mqtt = require('mqtt');
var express = require('express')
var morgan = require('morgan')
var bodyParser = require('body-parser')
var parameterize = require('parameterize')

var config_dir = process.env.CONFIG_DIR || './config'
var config = require(config_dir + '/config.json');

var harmonyHubDiscover = require('harmonyhubjs-discover')
var harmony = require('harmonyhubjs-client')

var harmonyHubClients = {}
var harmonyActivitiesCache = {}
var harmonyActivityUpdateInterval = 1*60*1000 // 1 minute
var harmonyActivityUpdateTimers = {}

var harmonyHubStates = {}
var harmonyStateUpdateInterval = 5*1000 // 5 seconds
var harmonyStateUpdateTimers = {}

var harmonyDevicesCache = {}
var harmonyDeviceUpdateInterval = 1*60*1000 // 1 minute
var harmonyDeviceUpdateTimers = {}

var mqttClient = config.hasOwnProperty("mqtt_options") ?
    mqtt.connect(config.mqtt_host, config.mqtt_options) :
    mqtt.connect(config.mqtt_host);
var TOPIC_NAMESPACE = config.topic_namespace || "harmony-api";

var app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(express.static(path.join(__dirname, 'public')));

var logFormat = "'[:date[iso]] - :remote-addr - :method :url :status :response-time ms - :res[content-length]b'"
app.use(morgan(logFormat))

// Middleware
// Check to make sure we have a harmonyHubClient to connect to
var hasHarmonyHubClient = function(req, res, next) {
  if (Object.keys(harmonyHubClients).length > 0) {
    next()
  }else{
    res.status(500).json({message: "No hubs available."})
  }
}
app.use(hasHarmonyHubClient)

var discover = new harmonyHubDiscover(61991)

discover.on('online', function(hubInfo) {
  // Triggered when a new hub was found
  console.log('Hub discovered: ' + hubInfo.friendlyName + ' at ' + hubInfo.ip + '.')

  if (hubInfo.ip) {
    harmony(hubInfo.ip).then(function(client){
      startProcessing(parameterize(hubInfo.friendlyName), client)
    })
  }

})

discover.on('offline', function(hubInfo) {
  // Triggered when a hub disappeared
  console.log('Hub lost: ' + hubInfo.friendlyName + ' at ' + hubInfo.ip + '.')
  hubSlug = parameterize(hubInfo.friendlyName)

  clearInterval(harmonyStateUpdateTimers[hubSlug])
  clearInterval(harmonyActivityUpdateTimers[hubSlug])
  delete(harmonyHubClients[hubSlug])
  delete(harmonyActivitiesCache[hubSlug])
  delete(harmonyHubStates[hubSlug])
})

// Look for hubs:
console.log('Starting discovery.')
discover.start()

// mqtt api

mqttClient.on('connect', function () {
  mqttClient.subscribe(TOPIC_NAMESPACE + '/hubs/+/activities/+/command')
});

mqttClient.on('message', function (topic, message) {
  var commandPattern = new RegExp(/hubs\/(.*)\/activities\/(.*)\/command/);
  var commandMatches = topic.match(commandPattern);

  if (commandMatches) {
    var hubSlug = commandMatches[1]
    var activitySlug = commandMatches[2]
    var state = message.toString()

    activity = activityBySlugs(hubSlug, activitySlug)
    if (!activity) { return }

    if (state === 'on') {
      startActivity(hubSlug, activity.id)
    }else if (state === 'off'){
      off(hubSlug)
    }
  }

});

function startProcessing(hubSlug, harmonyClient){
  harmonyHubClients[hubSlug] = harmonyClient

  // update the list of activities
  updateActivities(hubSlug)
  // then do it on the set interval
  clearInterval(harmonyActivityUpdateTimers[hubSlug])
  harmonyActivityUpdateTimers[hubSlug] = setInterval(function(){ updateActivities(hubSlug) }, harmonyActivityUpdateInterval)

  // update the state
  updateState(hubSlug)
  // update the list of activities on the set interval
  clearInterval(harmonyStateUpdateTimers[hubSlug])
  harmonyStateUpdateTimers[hubSlug] = setInterval(function(){ updateState(hubSlug) }, harmonyStateUpdateInterval)

  // update devices
  updateDevices(hubSlug)
  // update the list of devices on the set interval
  clearInterval(harmonyDeviceUpdateTimers[hubSlug])
  harmonyDeviceUpdateTimers[hubSlug] = setInterval(function(){ updateDevices(hubSlug) }, harmonyDeviceUpdateInterval)
}

function updateActivities(hubSlug){
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (!harmonyHubClient) { return }
  console.log('Updating activities for ' + hubSlug + '.')

  try {
    harmonyHubClient.getActivities().then(function(activities){
      foundActivities = {}
      activities.some(function(activity) {
        foundActivities[activity.id] = {id: activity.id, slug: parameterize(activity.label), label:activity.label, isAVActivity: activity.isAVActivity}
      })

      harmonyActivitiesCache[hubSlug] = foundActivities
    })
  } catch(err) {
    console.log("ERROR: " + err.message);
  }

}

function updateState(hubSlug){
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (!harmonyHubClient) { return }
  console.log('Updating state for ' + hubSlug + '.')

  // save for comparing later after we get the true current state
  var previousActivity = currentActivity(hubSlug)

  try {
    harmonyHubClient.getCurrentActivity().then(function(activityId){
      data = {off: true}

      activity = harmonyActivitiesCache[hubSlug][activityId]

      if (activityId != -1 && activity) {
        data = {off: false, current_activity: activity}
      }else{
        data = {off: true, current_activity: activity}
      }

      // cache state for later
      harmonyHubStates[hubSlug] = data

      if (!previousActivity || (activity.id != previousActivity.id)) {
        publish('hubs/' + hubSlug + '/' + 'current_activity', activity.slug, {retain: true})
        publish('hubs/' + hubSlug + '/' + 'state', activity.id == -1 ? 'off' : 'on' , {retain: true})

        for (var i = 0; i < cachedHarmonyActivities(hubSlug).length; i++) {
          activities = cachedHarmonyActivities(hubSlug)
          cachedActivity = activities[i]

          if (activity == cachedActivity) {
            publish('hubs/' + hubSlug + '/' + 'activities/' + cachedActivity.slug + '/state', 'on', {retain: true})
          }else{
            publish('hubs/' + hubSlug + '/' + 'activities/' + cachedActivity.slug + '/state', 'off', {retain: true})
          }
        }
      }

    })
  } catch(err) {
    console.log("ERROR: " + err.message);
  }

}

function updateDevices(hubSlug){
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (!harmonyHubClient) { return }
  console.log('Updating devices for ' + hubSlug + '.')
  try {
    harmonyHubClient.getAvailableCommands().then(function(commands) {
      foundDevices = {}
      commands.device.some(function(device) {
        deviceCommands = {}
        device.controlGroup.some(function(group) {
          group.function.some(function(func) {
            deviceCommands[func.name] = {action:func.action, label:func.label}
          })
        })
        foundDevices[device.id] = {id: device.id, slug: parameterize(device.label), label:device.label, commands:deviceCommands}
      })

      harmonyDevicesCache[hubSlug] = foundDevices
    })

  } catch(err) {
    console.log("Devices ERROR: " + err.message);
  }
}

function cachedHarmonyActivities(hubSlug){
  activities = harmonyActivitiesCache[hubSlug]
  if (!activities) { return [] }

  return Object.keys(harmonyActivitiesCache[hubSlug]).map(function(key) {
    return harmonyActivitiesCache[hubSlug][key]
  })
}

function currentActivity(hubSlug){
  harmonyHubClient = harmonyHubClients[hubSlug]
  harmonyHubState = harmonyHubStates[hubSlug]
  if (!harmonyHubClient || !harmonyHubState) { return null}

  return harmonyHubState.current_activity
}

function activityBySlugs(hubSlug, activitySlug){
  var activity
  cachedHarmonyActivities(hubSlug).some(function(a) {
    if(a.slug === activitySlug) {
      activity = a
      return true
    }
  })

  return activity
}

function cachedHarmonyDevices(hubSlug){
  devices = harmonyDevicesCache[hubSlug]
  if (!devices) { return [] }

  return Object.keys(harmonyDevicesCache[hubSlug]).map(function(key) {
    return harmonyDevicesCache[hubSlug][key]
  })
}

function off(hubSlug){
  harmonyHubClient = harmonyHubClients[hubSlug]
  if (!harmonyHubClient) { return }

  harmonyHubClient.turnOff().then(function(){
    updateState(hubSlug)
  })
}

function startActivity(hubSlug, activityId){
  harmonyHubClient = harmonyHubClients[hubSlug]
  if (!harmonyHubClient) { return }

  harmonyHubClient.startActivity(activityId).then(function(){
    updateState(hubSlug)
  })
}

function publish(topic, message, options){
  topic = TOPIC_NAMESPACE + "/" + topic
  mqttClient.publish(topic, message, options);
}

app.get('/_ping', function(req, res){
  res.send('OK');
})

app.get('/', function(req, res){
  res.sendfile('index.html');
})

app.get('/hubs', function(req, res){
  res.json({hubs: Object.keys(harmonyHubClients)})
})

app.get('/hubs/:hubSlug/activities', function(req, res){
  hubSlug = req.params.hubSlug
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (harmonyHubClient) {
    res.json({activities: cachedHarmonyActivities(hubSlug)})
  }else{
    res.status(404).json({message: "Not Found"})
  }
})

app.get('/hubs/:hubSlug/devices', function(req, res){
  hubSlug = req.params.hubSlug
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (harmonyHubClient) {
    var devices = [];
    res.json({devices: cachedHarmonyDevices(hubSlug).map(function(device) {
      return device.slug
    })})
  }else{
    res.status(404).json({message: "Not Found"})
  }
})

app.get('/hubs/:hubSlug/status', function(req, res){
  hubSlug = req.params.hubSlug
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (harmonyHubClient) {
    res.json(harmonyHubStates[hubSlug])
  }else{
    res.status(404).json({message: "Not Found"})
  }
})

app.put('/hubs/:hubSlug/off', function(req, res){
  hubSlug = req.params.hubSlug
  harmonyHubClient = harmonyHubClients[hubSlug]

  if (harmonyHubClient) {
    off(hubSlug)
    res.json({message: "ok"})
  }else{
    res.status(404).json({message: "Not Found"})
  }
})

app.post('/hubs/:hubSlug/start_activity', function(req, res){
  activity = activityBySlugs(req.params.hubSlug, req.query.activity)

  if (activity) {
    startActivity(req.params.hubSlug, activity.id)

    res.json({message: "ok"})
  }else{
    res.status(404).json({message: "Not Found"})
  }
})

app.get('/hubs_for_index', function(req, res){
  hubSlugs = Object.keys(harmonyHubClients)
  output = ""

  Object.keys(harmonyHubClients).forEach(function(hubSlug) {
    output += '
' + hubSlug.replace('-', ' ') + '
'
    output += '
GET /hubs/' + hubSlug + '/status
'
    output += '
GET /hubs/' + hubSlug + '/activities
'
    output += '
GET /hubs/' + hubSlug + '/devices
'
  });

  res.send(output)
})

app.listen(process.env.PORT || 8282)
<|endoftext|>


<commit_before>/****************************************************************************
 * Copyright (C) 2015-2016 EPAM Systems
 *
 * This file is part of Indigo-Node binding.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.md  included in the
 * packaging of this file.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ***************************************************************************/
var path = require('path');
var local = path.join.bind(path, __dirname);
var config = require(local('configureIndigo'));
var lib_api = require(local('indigo-api'));
var IndigoObject = require(local('indigoObject'));
var Indigo = require(local('indigo'));

var IndigoInchi = function (indigo, options) {
	options = options || {};
	var libpath = local('shared/' + process.platform + '/' + process.arch + '/'+ config[process.platform].libs['indigo-inchi']);
	this.libpath = options.libpath || libpath;
	this.exception = options.exception || false;
	this.logger = options.logger || console;
	this._lib = lib_api.Library(libpath, lib_api.api_inchi);
	if (indigo instanceof Indigo) {
		this.indigo = indigo;
	} else {
		if (this.exception)
			throw new Indigo.IndigoException("indigo isn't an instance of Indigo");
		else
			this.logger.error("indigo isn't an instance of Indigo");
	}
};

/*
 *
 * @method version
 * @return {string} string of version
 */
IndigoInchi.prototype.version = function () {
	this.indigo._setSessionId();
	return this._lib.indigoInchiVersion();
};

/*
 *
 * @method resetOptions
 * @return {boolean} return true if option applies as successful
 */
IndigoInchi.prototype.resetOptions = function () {
	this.indigo._setSessionId();
	return (this.indigo._checkResult(this._lib.indigoInchiResetOptions()) === 1);
};

/*
 *
 *
 * @method loadMolecule
 * @param {string}
 * @return {object} a new indigo object
 */
IndigoInchi.prototype.loadMolecule = function (inchi) {
	this.indigo._setSessionId();
	return new IndigoObject(this.indigo, this.indigo._checkResult(this._lib.indigoInchiLoadMolecule(inchi)))
}

module.exports = IndigoInchi;

<commit_msg>add IndigoInchi.getInchi and getWarning<commit_after>/****************************************************************************
 * Copyright (C) 2015-2016 EPAM Systems
 *
 * This file is part of Indigo-Node binding.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.md  included in the
 * packaging of this file.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ***************************************************************************/
var path = require('path');
var local = path.join.bind(path, __dirname);
var config = require(local('configureIndigo'));
var lib_api = require(local('indigo-api'));
var IndigoObject = require(local('indigoObject'));
var Indigo = require(local('indigo'));

var IndigoInchi = function (indigo, options) {
	options = options || {};
	var libpath = local('shared/' + process.platform + '/' + process.arch + '/'+ config[process.platform].libs['indigo-inchi']);
	this.libpath = options.libpath || libpath;
	this.exception = options.exception || false;
	this.logger = options.logger || console;
	this._lib = lib_api.Library(libpath, lib_api.api_inchi);
	if (indigo instanceof Indigo) {
		this.indigo = indigo;
	} else {
		if (this.exception)
			throw new Indigo.IndigoException("indigo isn't an instance of Indigo");
		else
			this.logger.error("indigo isn't an instance of Indigo");
	}
};

/*
 *
 * @method version
 * @return {string} string of version
 */
IndigoInchi.prototype.version = function () {
	this.indigo._setSessionId();
	return this._lib.indigoInchiVersion();
};

/*
 *
 * @method resetOptions
 * @return {boolean} return true if option applies as successful
 */
IndigoInchi.prototype.resetOptions = function () {
	this.indigo._setSessionId();
	return (this.indigo._checkResult(this._lib.indigoInchiResetOptions()) === 1);
};

/*
 *
 *
 * @method loadMolecule
 * @param {string}
 * @return {object} a new indigo object
 */
IndigoInchi.prototype.loadMolecule = function (inchi) {
	this.indigo._setSessionId();
	return new IndigoObject(this.indigo, this.indigo._checkResult(this._lib.indigoInchiLoadMolecule(inchi)));
};

/*
 *
 * @method getInchi
 * @param {object}
 * @return {string}
 */
IndigoInchi.prototype.getInchi = function (molecule) {
	this.indigo._setSessionId();
	return this.indigo._checkResultString(this._lib.indigoInchiGetInchi(molecule.id));
};

/*
 *
 * @method getWarning
 * @return {string}
 */
IndigoInchi.prototype.getWarning = function () {
	this.indigo._setSessionId();
	return this.indigo._checkResultString(this._lib.indigoInchiGetWarning());
};

module.exports = IndigoInchi;

<|endoftext|>