<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

const Reading = require('./../models/Reading');
const { log } = require('../log');

/**
 * Validate an array of Readings value according to certain criteria
 * @param {array of Readings} arrayToValidate
 * @param {number} maxVal maximum acceptable reading value
 * @param {number} minVal minimum acceptable reading value
 * @param {Moment} minDate earliest acceptable date
 * @param {Moment} maxDate latest acceptable date
 * @param {boolean} interval the expected interval between reading time
 * @param {number} maxError the maximum number of errors to be reported
 */

function validateReadings(arrayToValidate, maxVal, minVal, minDate, maxDate, interval, maxError) {
	validDates = checkDate(arrayToValidate, minDate, maxDate, maxError / 3);
	validValues = checkValue(arayToValidate, minVal, maxVal, maxError / 3);
	validIntervals = checkIntervals(arrayToValidate, interval, maxError / 3);
	return validDates && validValues && validIntervals;
}

function checkDate(arrayToValidate, minDate, maxDate, maxError) {
	validDates = true;
	for (reading of arrayToValidate) {
		if (maxError < 0) {
			break;
		}
		if (reading.startTimestamp.isBefore(minDate)) {
			log.error(`ERROR WHEN CHECKING READING TIME FROM METER ${reading.meterID}: Time ${reading.startTimestamp} is earlier than lower bound ${minDate}`);
			--maxError;
			validDate = false;
		}
		if (reading.endTimestamp.isAfter(maxDate)) {
			log.error(`ERROR WHEN CHECKING READING TIME FROM METER ${reading.meterID}: Time ${reading.startTimestamp} is later than upper bound ${maxDate}`);
			--maxError;
			validDate = false;
		}
	}
	return validDates;
}

function checkValue(arrayToValidate, minVal, maxVal, maxError) {
	validValues = true;
	for (reading of arrayToValidate) {
		if (maxError < 0) {
			break;
		}
		if (reading.reading < minVal) {
			log.error(`ERROR WHEN CHECKING READING VALUE FROM METER ${reading.meterID}: ${reading.reading} is smaller than lower bound ${minVal}`);
			--maxError;
			validValues = false;
		} else if (reading.reading > maxDate) {
			log.error(`ERROR WHEN CHECKING READING VALUE FROM METER ${reading.meterID}: ${reading.reading} is larger than upper bound ${maxVal}`);
			--maxError;
			validValues = false;
		}
	}
	return validValues;
}

function checkIntervals(arrayToValidate, interval, maxError) {
	if (interval == null) {
		return true;
	}
	equalIntervals = true;
	lastTime = arrayToValidate[0].startTimestamp;
	for (reading of arrayToValidate) {
		if (maxError < 0) {
			break;
		}
		if (reading == arrayToValidate[0]) {
			continue;
		}
		if (lastTime.diff(reading.startTimestamp) !== interval) {
			log.error(`UNEQUAL INTERVAL IS DETECTED FROM METER ${reading.meterID}`);
			--maxError;
			equalIntervals = false;
		}
		lastTime = reading.startTimestamp;
	}
	return equalIntervals;
}
module.exports = validateReadings;
<commit_msg>Add comments<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

const Reading = require('./../models/Reading');
const { log } = require('../log');

/**
 * Validate an array of Readings value according to certain criteria
 * @param {array of Readings} arrayToValidate
 * @param {number} maxVal maximum acceptable reading value
 * @param {number} minVal minimum acceptable reading value
 * @param {Moment} minDate earliest acceptable date
 * @param {Moment} maxDate latest acceptable date
 * @param {boolean} interval the expected interval between reading time
 * @param {number} maxError the maximum number of errors to be reported, ignore the rest
 */

function validateReadings(arrayToValidate, maxVal, minVal, minDate, maxDate, interval, maxError) {
	validDates = checkDate(arrayToValidate, minDate, maxDate, maxError / 3);
	validValues = checkValue(arayToValidate, minVal, maxVal, maxError / 3);
	validIntervals = checkIntervals(arrayToValidate, interval, maxError / 3);
	return validDates && validValues && validIntervals;
}

/**
 * Check and report any out-of-bound date. Can be ignored by passing null minDate and maxDate
 * @param {array of Readings} arrayToValidate
 * @param {Moment} minDate earliest acceptable date
 * @param {Moment} maxDate latest acceptable date
 * @param {number} maxError maximum number of errors to be reported, ignore the rest
 */
function checkDate(arrayToValidate, minDate, maxDate, maxError) {
	if (minDate === null && maxDate === null) {
		return true;
	}
	validDates = true;
	for (reading of arrayToValidate) {
		if (maxError < 0) {
			break;
		}
		if (reading.startTimestamp.isBefore(minDate)) {
			log.error(`ERROR WHEN CHECKING READING TIME FROM METER ${reading.meterID}: Time ${reading.startTimestamp} is earlier than lower bound ${minDate}`);
			--maxError;
			validDate = false;
		}
		if (reading.endTimestamp.isAfter(maxDate)) {
			log.error(`ERROR WHEN CHECKING READING TIME FROM METER ${reading.meterID}: Time ${reading.startTimestamp} is later than upper bound ${maxDate}`);
			--maxError;
			validDate = false;
		}
	}
	return validDates;
}

/**
 * Check and report any out-of-bound reading value. Can be ignored by passing MIN_VALUE & MAX_VALUE
 * @param {*} arrayToValidate
 * @param {*} minVal maximum acceptable reading value
 * @param {*} maxVal minimum acceptable reading value
 * @param {*} maxError maximum number of errors to be reported, ignore the rest
 */
function checkValue(arrayToValidate, minVal, maxVal, maxError) {
	validValues = true;
	for (reading of arrayToValidate) {
		if (maxError < 0) {
			break;
		}
		if (reading.reading < minVal) {
			log.error(`ERROR WHEN CHECKING READING VALUE FROM METER ${reading.meterID}: ${reading.reading} is smaller than lower bound ${minVal}`);
			--maxError;
			validValues = false;
		} else if (reading.reading > maxDate) {
			log.error(`ERROR WHEN CHECKING READING VALUE FROM METER ${reading.meterID}: ${reading.reading} is larger than upper bound ${maxVal}`);
			--maxError;
			validValues = false;
		}
	}
	return validValues;
}

/**
 * Check and report unequal intervals. Can be ignore by passing null interval
 * @param {*} arrayToValidate
 * @param {*} interval expected gap between 2 consecutive reading values
 * @param {*} maxError maximum number of errors to be reported. Ignore the rest
 */
function checkIntervals(arrayToValidate, interval, maxError) {
	if (interval == null) {
		return true;
	}
	equalIntervals = true;
	lastTime = arrayToValidate[0].startTimestamp;
	for (reading of arrayToValidate) {
		if (maxError < 0) {
			break;
		}
		if (reading === arrayToValidate[0]) {
			continue;
		}
		if (lastTime.diff(reading.startTimestamp) !== interval) {
			log.error(`UNEQUAL INTERVAL IS DETECTED FROM METER ${reading.meterID}`);
			--maxError;
			equalIntervals = false;
		}
		lastTime = reading.startTimestamp;
	}
	return equalIntervals;
}
module.exports = validateReadings;
<|endoftext|>


<commit_before>
const expect = require('chai').expect;
const RG = require('../../../client/src/battles');

const ItemRand = RG.Factory.ItemRandomizer;
const temple = require('../../../client/data/temple.json');

describe('RG.Factory.ItemRandomizer', () => {
    it('Randomizes item properties for proc generation', () => {
        const itemRand = new ItemRand();
        const food = new RG.Item.Food('meat');
        const weightBefore = food.getWeight();
        itemRand.adjustItem(food);

        const weightAfter = food.getWeight();
        expect(weightBefore !== weightAfter).to.equal(true);
    });
});

const MockParser = function() {
    this.createRandomItem = () => new RG.Item.Food('testFood');

};

describe('RG.Factory.Base', () => {
    it('Can create randomized towns', () => {
        const factory = new RG.Factory.Base();
        const conf = {
            parser: new MockParser(),
            func: function() {return 'dummy';},
            nShops: 2,
            shopFunc: [
                item => (item.getType() === 'potion'),
                item => (item.getType() === 'food')
            ]
        };

        const townLevel = factory.createLevel('town', 80, 80, conf);
        const actors = townLevel.getActors();
        const keeper = actors[0];

        expect(actors.length).to.equal(2);
        expect(keeper.getName()).to.equal('shopkeeper');

    });
});

describe('RG.Factory.Game', () => {

    let conf = null;

    beforeEach(() => {
        conf = {
            cols: 40,
            rows: 30,
            levels: 2,
            playerLevel: 'Medium',
            sqrPerActor: 40,
            sqrPerItem: 100,
            playMode: 'Dungeon',
            loadedPlayer: null,
            loadedLevel: null,
            playerName: 'Player Hero'
        };
    });

    it('can create new games', () => {
        const gameFactory = new RG.Factory.Game();
        const game = gameFactory.createNewGame(conf);
        expect(game).to.exist;
        expect(game.getPlayer().getName()).to.equal('Player Hero');
    });

    it('can create new games with preset levels', () => {
        const gameFactory = new RG.Factory.Game();
        temple.id = RG.LEVEL_ID_ADD + 1000000;
        const worldConf = {
            name: 'PresetLevelWorld',
            presetLevels: {
                'Beast dungeon.Animals': [{nLevel: 0, level: temple}]
            },
            nAreas: 1,
            area: [
                {
                    name: 'Ravendark',
                    maxX: 1,
                    maxY: 1,
                    cols: 70, rows: 30,
                    nDungeons: 1,
                    dungeon: [
                        { x: 0, y: 0, name: 'Beast dungeon', nBranches: 1,
                            branch: [
                                {name: 'Animals', nLevels: 2, entranceLevel: 0}
                            ]
                        }
                    ]
                }
            ]
        };
        conf.world = worldConf;
        conf.playMode = 'World';
        const game = gameFactory.createNewGame(conf);
        expect(game).to.exist;
        expect(game.getLevels()).to.have.length(3);

        const presetLevel = game.getLevels().find(level => (
            level.getID() === temple.id
        ));
        expect(presetLevel).to.exist;
    });

});
<commit_msg>Added createActor().<commit_after>
const expect = require('chai').expect;
const RG = require('../../../client/src/battles');

const ItemRand = RG.Factory.ItemRandomizer;
const temple = require('../../../client/data/temple.json');

describe('RG.Factory.ItemRandomizer', () => {
    it('Randomizes item properties for proc generation', () => {
        const itemRand = new ItemRand();
        const food = new RG.Item.Food('meat');
        const weightBefore = food.getWeight();
        itemRand.adjustItem(food);

        const weightAfter = food.getWeight();
        expect(weightBefore !== weightAfter).to.equal(true);
    });
});

const MockParser = function() {
    this.createRandomItem = () => new RG.Item.Food('testFood');
    this.createActor = () => new RG.Actor.Rogue('shopkeeper');
};

describe('RG.Factory.Base', () => {
    it('Can create randomized towns', () => {
        const factory = new RG.Factory.Base();
        const conf = {
            parser: new MockParser(),
            func: function() {return 'dummy';},
            nShops: 2,
            shopFunc: [
                item => (item.getType() === 'potion'),
                item => (item.getType() === 'food')
            ]
        };

        const townLevel = factory.createLevel('town', 80, 80, conf);
        const actors = townLevel.getActors();
        const keeper = actors[0];

        expect(actors.length).to.equal(2);
        expect(keeper.getName()).to.equal('shopkeeper');

    });
});

describe('RG.Factory.Game', () => {

    let conf = null;

    beforeEach(() => {
        conf = {
            cols: 40,
            rows: 30,
            levels: 2,
            playerLevel: 'Medium',
            sqrPerActor: 40,
            sqrPerItem: 100,
            playMode: 'Dungeon',
            loadedPlayer: null,
            loadedLevel: null,
            playerName: 'Player Hero'
        };
    });

    it('can create new games', () => {
        const gameFactory = new RG.Factory.Game();
        const game = gameFactory.createNewGame(conf);
        expect(game).to.exist;
        expect(game.getPlayer().getName()).to.equal('Player Hero');
    });

    it('can create new games with preset levels', () => {
        const gameFactory = new RG.Factory.Game();
        temple.id = RG.LEVEL_ID_ADD + 1000000;
        const worldConf = {
            name: 'PresetLevelWorld',
            presetLevels: {
                'Beast dungeon.Animals': [{nLevel: 0, level: temple}]
            },
            nAreas: 1,
            area: [
                {
                    name: 'Ravendark',
                    maxX: 1,
                    maxY: 1,
                    cols: 70, rows: 30,
                    nDungeons: 1,
                    dungeon: [
                        { x: 0, y: 0, name: 'Beast dungeon', nBranches: 1,
                            branch: [
                                {name: 'Animals', nLevels: 2, entranceLevel: 0}
                            ]
                        }
                    ]
                }
            ]
        };
        conf.world = worldConf;
        conf.playMode = 'World';
        const game = gameFactory.createNewGame(conf);
        expect(game).to.exist;
        expect(game.getLevels()).to.have.length(3);

        const presetLevel = game.getLevels().find(level => (
            level.getID() === temple.id
        ));
        expect(presetLevel).to.exist;
    });

});
<|endoftext|>


<commit_before>window.onload = function() {

    var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-game', { preload: preload, create: create, update: update });

    var player
    var cursors
    var player_id
    var player_id_int

    var enemies

    var other_players = []
    var world_state = { players: {} }

    function preload () {

        game.load.image('sheep_1', 'images/sheep_1.png')
        game.load.image('field', 'images/field.jpg')

    }

    function create () {

        // add background
        game.add.sprite(0, 0, 'field');

        game.physics.startSystem(Phaser.Physics.ARCADE);

        cursors = game.input.keyboard.createCursorKeys()

        enemies = game.add.group()

        player = game.add.sprite(game.world.centerX, game.world.centerY, 'sheep_1');
        player.anchor.setTo(0.5, 0.5);

        game.physics.enable(player, Phaser.Physics.ARCADE);

        player_id_int = Math.floor(Math.random() * 1000)
        player_id = player_id_int.toString()

        channel.push("im_new_here", { player_id: player_id,
                                       position: { x: player.x, y: player.y },
                                       velocity: { x: player.body.velocity.x, y: player.body.velocity.y }
                                    })

    }

    function update () {

        player.body.velocity.x = 0
        player.body.velocity.y = 0

        if (cursors.left.isDown) {
          player.body.velocity.x = -300
        }
        else if (cursors.right.isDown) {
          player.body.velocity.x = 300
        }

        if (cursors.up.isDown) {
          player.body.velocity.y = -300
        }
        else if (cursors.down.isDown) {
          player.body.velocity.y = 300
        }

        if (player.body.velocity.x > 0) {
          player.scale.x = 1
        } else if (player.body.velocity.x < 0) {
          player.scale.x = -1
        }

        if (player_id_int in world_state.players) {
          if (world_state.players[player_id_int].position.x != player.x ||
                  world_state.players[player_id_int].position.y != player.y ) {
            channel.push("new_position", { player_id: player_id,
                                           position: { x: player.x, y: player.y },
                                           velocity: { x: player.body.velocity.x, y: player.body.velocity.y }
                                         })
          }
        }

    }

    channel.on("update_world", payload => {

      world_state = payload

      other_players.forEach(function(other_player) {
        var other_player_id = parseInt(other_player.player_id);

        if (other_player_id in payload.players) {
          other_player.game_object.x = payload.players[other_player_id].position.x
          other_player.game_object.y = payload.players[other_player_id].position.y

          other_player.game_object.body.velocity.x = payload.players[other_player_id].velocity.x
          other_player.game_object.body.velocity.y = payload.players[other_player_id].velocity.y

          if (other_player.game_object.body.velocity.x > 0) {
            other_player.game_object.scale.x = 1
          } else if (other_player.game_object.body.velocity.x < 0) {
            other_player.game_object.scale.x = -1
          }

        }
      })

    })

    channel.on("new_player_joined", payload => {

      var other_player_id = payload.player_id
      var position = payload.position

      var new_player = game.add.sprite(position.x, position.y, 'sheep_1')
      new_player.anchor.setTo(0.5, 0.5)
      game.physics.enable(new_player, Phaser.Physics.ARCADE);

      other_players.push({player_id: other_player_id, game_object: new_player})

    })

    channel.on("hello_world", payload => {

      Object.keys(payload.players).forEach(function(other_player_id) {
        if (other_player_id == player_id_int) { return }

        var new_player = game.add.sprite(payload.players[other_player_id].position.x, payload.players[other_player_id].position.y, 'sheep_1')
        new_player.anchor.setTo(0.5, 0.5);
        game.physics.enable(new_player, Phaser.Physics.ARCADE);

        enemies.add(new_player)

        other_players.push({player_id: other_player_id, game_object: new_player})
      })

    })

    channel.on("player_left", payload => {

      other_players = other_players.filter(function( player ) {
        if (player.player_id == payload.player_id){
          player.game_object.destroy()
        }
        return player.player_id !== payload.player_id;
      });

    })

};
<commit_msg>Add comments<commit_after>window.onload = function() {

    var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-game', { preload: preload, create: create, update: update });

    var player
    var cursors
    var player_id
    var player_id_int

    var enemies

    var other_players = []
    var world_state = { players: {} }

    function preload () {

        game.load.image('sheep_1', 'images/sheep_1.png')
        game.load.image('field', 'images/field.jpg')

    }

    function create () {

        // add background
        game.add.sprite(0, 0, 'field');

        // start physics used for storing sheep velocity
        game.physics.startSystem(Phaser.Physics.ARCADE);

        // enable keyboard control via arrow keys
        cursors = game.input.keyboard.createCursorKeys()

        // create enemies groups before player
        enemies = game.add.group()

        // add player after enemy so it displays on top
        player = game.add.sprite(game.world.centerX, game.world.centerY, 'sheep_1');
        player.anchor.setTo(0.5, 0.5);
        game.physics.enable(player, Phaser.Physics.ARCADE);

        // create a random number for id
        player_id_int = Math.floor(Math.random() * 1000)
        player_id = player_id_int.toString()

        channel.push("im_new_here", { player_id: player_id,
                                       position: { x: player.x, y: player.y },
                                       velocity: { x: player.body.velocity.x, y: player.body.velocity.y }
                                    })

    }

    function update () {

        // reset velocity to zero by override in based on input
        player.body.velocity.x = 0
        player.body.velocity.y = 0

        // set velocity based on keyboard input
        if (cursors.left.isDown) {
          player.body.velocity.x = -300
        }
        else if (cursors.right.isDown) {
          player.body.velocity.x = 300
        }

        if (cursors.up.isDown) {
          player.body.velocity.y = -300
        }
        else if (cursors.down.isDown) {
          player.body.velocity.y = 300
        }

        // make sprite face correct direction
        if (player.body.velocity.x > 0) {
          player.scale.x = 1
        } else if (player.body.velocity.x < 0) {
          player.scale.x = -1
        }

        // send details to game server
        if (player_id_int in world_state.players) {
          if (world_state.players[player_id_int].position.x != player.x ||
                  world_state.players[player_id_int].position.y != player.y ) {
            channel.push("new_position", { player_id: player_id,
                                           position: { x: player.x, y: player.y },
                                           velocity: { x: player.body.velocity.x, y: player.body.velocity.y }
                                         })
          }
        }

    }

    channel.on("update_world", payload => {

      // save the state of the world
      world_state = payload

      // update other_players with most recent world information
      other_players.forEach(function(other_player) {
        var other_player_id = parseInt(other_player.player_id);

        if (other_player_id in payload.players) {
          other_player.game_object.x = payload.players[other_player_id].position.x
          other_player.game_object.y = payload.players[other_player_id].position.y

          other_player.game_object.body.velocity.x = payload.players[other_player_id].velocity.x
          other_player.game_object.body.velocity.y = payload.players[other_player_id].velocity.y

          if (other_player.game_object.body.velocity.x > 0) {
            other_player.game_object.scale.x = 1
          } else if (other_player.game_object.body.velocity.x < 0) {
            other_player.game_object.scale.x = -1
          }

        }
      })

    })

    // add a new player to the game
    channel.on("new_player_joined", payload => {
      var other_player_id = payload.player_id
      var position = payload.position

      var new_player = game.add.sprite(position.x, position.y, 'sheep_1')
      new_player.anchor.setTo(0.5, 0.5)
      game.physics.enable(new_player, Phaser.Physics.ARCADE);

      other_players.push({player_id: other_player_id, game_object: new_player})

    })

    // show already existing players
    channel.on("hello_world", payload => {

      Object.keys(payload.players).forEach(function(other_player_id) {
        if (other_player_id == player_id_int) { return }

        var new_player = game.add.sprite(payload.players[other_player_id].position.x, payload.players[other_player_id].position.y, 'sheep_1')
        new_player.anchor.setTo(0.5, 0.5);
        game.physics.enable(new_player, Phaser.Physics.ARCADE);

        enemies.add(new_player)

        other_players.push({player_id: other_player_id, game_object: new_player})
      })

    })

    // remove a player when they leave
    channel.on("player_left", payload => {

      other_players = other_players.filter(function( player ) {
        if (player.player_id == payload.player_id){
          player.game_object.destroy()
        }
        return player.player_id !== payload.player_id;
      });

    })

};
<|endoftext|>


<commit_before>window.onload = function() {

    var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-game', { preload: preload, create: create, update: update });

    var player
    var player_id

    var cursors

    var enemies

    var other_players = []
    var world_state = { players: {} }

    function preload () {

        game.load.image('sheep_1', 'images/sheep_1.png')
        game.load.image('field', 'images/field.jpg')

    }

    function create () {

        // add background
        game.add.sprite(0, 0, 'field');

        // start physics used for storing sheep velocity
        game.physics.startSystem(Phaser.Physics.ARCADE);

        // enable keyboard control via arrow keys
        cursors = game.input.keyboard.createCursorKeys()

        // create enemies groups before player
        enemies = game.add.group()

        // add player after enemy so it displays on top
        player = game.add.sprite(game.world.centerX, game.world.centerY, 'sheep_1');
        player.anchor.setTo(0.5, 0.5);
        game.physics.enable(player, Phaser.Physics.ARCADE);

        // create a random number for id
        player_id = Math.floor(Math.random() * 1000)

        channel.push("im_new_here", { player_id: player_id,
                                       position: { x: player.x, y: player.y },
                                       velocity: { x: player.body.velocity.x, y: player.body.velocity.y }
                                    })

    }

    function update () {

        // reset velocity to zero by override in based on input
        player.body.velocity.x = 0
        player.body.velocity.y = 0

        if (game.physics.arcade.distanceToPointer(player) > 10) {
          game.physics.arcade.moveToPointer(player, 150)
        }

        // set velocity based on keyboard input
        if (cursors.left.isDown) {
          player.body.velocity.x = -300
        }
        else if (cursors.right.isDown) {
          player.body.velocity.x = 300
        }

        if (cursors.up.isDown) {
          player.body.velocity.y = -300
        }
        else if (cursors.down.isDown) {
          player.body.velocity.y = 300
        }

        // make sprite face correct direction
        if (player.body.velocity.x > 0) {
          player.scale.x = 1
        } else if (player.body.velocity.x < 0) {
          player.scale.x = -1
        }

        // send details to game server
        if (player_id in world_state.players) {
          if (world_state.players[player_id].position.x != player.x ||
                  world_state.players[player_id].position.y != player.y ) {
            channel.push("new_position", { player_id: player_id,
                                           position: { x: player.x, y: player.y },
                                           velocity: { x: player.body.velocity.x, y: player.body.velocity.y }
                                         })
          }
        }

    }

    channel.on("update_world", payload => {

      // save the state of the world
      world_state = payload

      // update other_players with most recent world information
      other_players.forEach(function(other_player) {
        var other_player_id = other_player.player_id

        if (other_player_id in payload.players) {
          other_player.game_object.x = payload.players[other_player_id].position.x
          other_player.game_object.y = payload.players[other_player_id].position.y

          other_player.game_object.body.velocity.x = payload.players[other_player_id].velocity.x
          other_player.game_object.body.velocity.y = payload.players[other_player_id].velocity.y

          if (other_player.game_object.body.velocity.x > 0) {
            other_player.game_object.scale.x = 1
          } else if (other_player.game_object.body.velocity.x < 0) {
            other_player.game_object.scale.x = -1
          }

        }
      })

    })

    // add a new player to the game
    channel.on("new_player_joined", payload => {
      var other_player_id = payload.player_id
      var position = payload.position

      var new_player = game.add.sprite(position.x, position.y, 'sheep_1')
      new_player.anchor.setTo(0.5, 0.5)
      game.physics.enable(new_player, Phaser.Physics.ARCADE);

      other_players.push({player_id: other_player_id, game_object: new_player})

    })

    // show already existing players
    channel.on("hello_world", payload => {

      Object.keys(payload.players).forEach(function(other_player_id) {
        if (other_player_id == player_id) { return }

        var new_player = game.add.sprite(payload.players[other_player_id].position.x, payload.players[other_player_id].position.y, 'sheep_1')
        new_player.anchor.setTo(0.5, 0.5);
        game.physics.enable(new_player, Phaser.Physics.ARCADE);

        enemies.add(new_player)

        other_players.push({player_id: other_player_id, game_object: new_player})
      })

    })

    // remove a player when they leave
    channel.on("player_left", payload => {

      other_players = other_players.filter(function( player ) {
        if (player.player_id == payload.player_id){
          player.game_object.destroy()
        }
        return player.player_id !== payload.player_id;
      });

    })

};
<commit_msg>Limit to one pointer<commit_after>window.onload = function() {

    var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-game', { preload: preload, create: create, update: update });

    var player
    var player_id

    var cursors

    var enemies

    var other_players = []
    var world_state = { players: {} }

    function preload () {

        game.load.image('sheep_1', 'images/sheep_1.png')
        game.load.image('field', 'images/field.jpg')

    }

    function create () {

        // add background
        game.add.sprite(0, 0, 'field');

        // start physics used for storing sheep velocity
        game.physics.startSystem(Phaser.Physics.ARCADE);

        // enable keyboard control via arrow keys
        cursors = game.input.keyboard.createCursorKeys()

        // limit to one pointer object
        game.input.maxPointers = 1

        // create enemies groups before player
        enemies = game.add.group()

        // add player after enemy so it displays on top
        player = game.add.sprite(game.world.centerX, game.world.centerY, 'sheep_1');
        player.anchor.setTo(0.5, 0.5);
        game.physics.enable(player, Phaser.Physics.ARCADE);

        // create a random number for id
        player_id = Math.floor(Math.random() * 1000)

        channel.push("im_new_here", { player_id: player_id,
                                       position: { x: player.x, y: player.y },
                                       velocity: { x: player.body.velocity.x, y: player.body.velocity.y }
                                    })

    }

    function update () {

        // reset velocity to zero by override in based on input
        player.body.velocity.x = 0
        player.body.velocity.y = 0

        if (game.physics.arcade.distanceToPointer(player) > 10) {
          game.physics.arcade.moveToPointer(player, 150)
        }

        // set velocity based on keyboard input
        if (cursors.left.isDown) {
          player.body.velocity.x = -300
        }
        else if (cursors.right.isDown) {
          player.body.velocity.x = 300
        }

        if (cursors.up.isDown) {
          player.body.velocity.y = -300
        }
        else if (cursors.down.isDown) {
          player.body.velocity.y = 300
        }

        // make sprite face correct direction
        if (player.body.velocity.x > 0) {
          player.scale.x = 1
        } else if (player.body.velocity.x < 0) {
          player.scale.x = -1
        }

        // send details to game server
        if (player_id in world_state.players) {
          if (world_state.players[player_id].position.x != player.x ||
                  world_state.players[player_id].position.y != player.y ) {
            channel.push("new_position", { player_id: player_id,
                                           position: { x: player.x, y: player.y },
                                           velocity: { x: player.body.velocity.x, y: player.body.velocity.y }
                                         })
          }
        }

    }

    channel.on("update_world", payload => {

      // save the state of the world
      world_state = payload

      // update other_players with most recent world information
      other_players.forEach(function(other_player) {
        var other_player_id = other_player.player_id

        if (other_player_id in payload.players) {
          other_player.game_object.x = payload.players[other_player_id].position.x
          other_player.game_object.y = payload.players[other_player_id].position.y

          other_player.game_object.body.velocity.x = payload.players[other_player_id].velocity.x
          other_player.game_object.body.velocity.y = payload.players[other_player_id].velocity.y

          if (other_player.game_object.body.velocity.x > 0) {
            other_player.game_object.scale.x = 1
          } else if (other_player.game_object.body.velocity.x < 0) {
            other_player.game_object.scale.x = -1
          }

        }
      })

    })

    // add a new player to the game
    channel.on("new_player_joined", payload => {
      var other_player_id = payload.player_id
      var position = payload.position

      var new_player = game.add.sprite(position.x, position.y, 'sheep_1')
      new_player.anchor.setTo(0.5, 0.5)
      game.physics.enable(new_player, Phaser.Physics.ARCADE);

      other_players.push({player_id: other_player_id, game_object: new_player})

    })

    // show already existing players
    channel.on("hello_world", payload => {

      Object.keys(payload.players).forEach(function(other_player_id) {
        if (other_player_id == player_id) { return }

        var new_player = game.add.sprite(payload.players[other_player_id].position.x, payload.players[other_player_id].position.y, 'sheep_1')
        new_player.anchor.setTo(0.5, 0.5);
        game.physics.enable(new_player, Phaser.Physics.ARCADE);

        enemies.add(new_player)

        other_players.push({player_id: other_player_id, game_object: new_player})
      })

    })

    // remove a player when they leave
    channel.on("player_left", payload => {

      other_players = other_players.filter(function( player ) {
        if (player.player_id == payload.player_id){
          player.game_object.destroy()
        }
        return player.player_id !== payload.player_id;
      });

    })

};
<|endoftext|>


<commit_before>/**
 * Webpack config for hot reloading, lint checking and serving example page
 */
const webpack = require('webpack'),
    webpackConfig = require('./webpack.config.js'),
    path = require('path');

module.exports = {
    cache: true,
    entry: webpackConfig.entry,
    debug: true,
    devtools: 'source-map',
    target: 'node',
    output: {
        path: path.resolve(__dirname + '/build'),
        publicPath: '/build/',
        filename: 'index.js'
    },
    resolve: webpackConfig.resolve,
    plugins: [
        new webpack.DefinePlugin({
            'PROCESS_ENV': '"development"',
            'VERSION': JSON.stringify(require('./package.json').version)
        }),
        new webpack.optimize.UglifyJsPlugin()
    ],
    module: webpackConfig.module
};
<commit_msg>updated webpack conf<commit_after>/**
 * Webpack config for hot reloading, lint checking and serving example page
 */
const webpack = require('webpack'),
    webpackConfig = require('./webpack.config.js'),
    path = require('path');

module.exports = {
    cache: true,
    entry: webpackConfig.entry,
    debug: true,
    devtool: 'source-map',
    target: 'node',
    output: {
        path: path.resolve(__dirname + '/build'),
        publicPath: '/build/',
        filename: 'index.js'
    },
    resolve: webpackConfig.resolve,
    plugins: [
        new webpack.DefinePlugin({
            'PROCESS_ENV': '"development"',
            'VERSION': JSON.stringify(require('./package.json').version)
        }),
        new webpack.optimize.UglifyJsPlugin()
    ],
    module: webpackConfig.module
};
<|endoftext|>


<commit_before>/**
 * Converts any DOM node/s to a loopable array
 * @param   { HTMLElement|NodeList } els - single html element or a node list
 * @returns { Array } always a loopable object
 */
export default function domToArray(els) {
  // can this object be already looped?
  if (!Array.isArray(els)) {
    // is it a node list?
    // watch out window.length exists and must be filtered
    if (els !== window && els.length)
      return Array.from(els)
    else
      // if it's a single node
      // it will be returned as "array" with one single entry
      return [els]
  }
  // this object could be looped out of the box
  return els
}<commit_msg>updated: better node list detection against also select<commit_after>/**
 * Converts any DOM node/s to a loopable array
 * @param   { HTMLElement|NodeList } els - single html element or a node list
 * @returns { Array } always a loopable object
 */
export default function domToArray(els) {
  // can this object be already looped?
  if (!Array.isArray(els)) {
    // is it a node list?
    if (
        /^\[object (HTMLCollection|NodeList|Object)\]$/
          .test(Object.prototype.toString.call(els))
        && typeof els.length === 'number'
      )
      return Array.from(els)
    else
      // if it's a single node
      // it will be returned as "array" with one single entry
      return [els]
  }
  // this object could be looped out of the box
  return els
}<|endoftext|>


<commit_before>import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import autoprefixer from 'autoprefixer';
import path from 'path';
import DotenvPlugin from 'webpack-dotenv-plugin';

export default {
  resolve: {
    extensions: ['*', '.js', '.jsx', '.json']
  },
  devtool: 'eval-source-map', // more info:https://webpack.github.io/docs/build-performance.html#sourcemaps and https://webpack.github.io/docs/configuration.html#devtool
  entry: [
    // must be first entry to properly set public path
    './src/webpack-public-path',
    'webpack-hot-middleware/client?reload=true',
    path.resolve(__dirname, 'src/index.js') // Defining path seems necessary for this to work consistently on Windows machines.
  ],
  target: 'web', // necessary per https://webpack.github.io/docs/testing.html#compile-and-test
  output: {
    path: path.resolve(__dirname, 'dist'), // Note: Physical files are only output by the production build task `npm run build`.
    publicPath: '/',
    filename: 'bundle.js'
  },
  plugins: [
    new DotenvPlugin({
      allowEmptyValues: true,
      sample: './config/.env.development',
      path: './config/.env.development'
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('development'), // Tells React to build in either dev or prod modes. https://facebook.github.io/react/downloads.html (See bottom)
      __DEV__: true
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new HtmlWebpackPlugin({     // Create HTML file that includes references to bundled CSS and JS.
      template: 'src/index.ejs',
      minify: {
        removeComments: true,
        collapseWhitespace: true
      },
      inject: true
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: false,
      debug: true,
      noInfo: true, // set to false to see a list of every file being bundled.
      options: {
        sassLoader: {
          includePaths: [path.resolve(__dirname, 'src', 'scss')]
        },
        context: '/',
        postcss: () => [autoprefixer],
      }
    })
  ],
  module: {
    rules: [
      {test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel-loader']},
      {test: /\.eot(\?v=\d+.\d+.\d+)?$/, loader: 'file-loader'},
      {test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff'},
      {test: /\.[ot]tf(\?v=\d+.\d+.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream'},
      {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml'},
      {test: /\.(jpe?g|png|gif)$/i, loader: 'file-loader?name=[name].[ext]'},
      {test: /\.ico$/, loader: 'file-loader?name=[name].[ext]'},
      {test: /(\.css|\.scss)$/, loaders: ['style-loader', 'css-loader?sourceMap', 'postcss-loader', 'sass-loader?sourceMap']}
    ]
  }
};
<commit_msg>Updating webpack config<commit_after>import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import autoprefixer from 'autoprefixer';
import path from 'path';
import DotenvPlugin from 'webpack-dotenv-plugin';

export default {
  resolve: {
    extensions: ['*', '.js', '.jsx', '.json']
  },
  devtool: 'eval-source-map', // more info:https://webpack.github.io/docs/build-performance.html#sourcemaps and https://webpack.github.io/docs/configuration.html#devtool
  entry: [
    // must be first entry to properly set public path
    './src/webpack-public-path',
    'webpack-hot-middleware/client?reload=true',
    path.resolve(__dirname, 'src/index.js') // Defining path seems necessary for this to work consistently on Windows machines.
  ],
  target: 'web', // necessary per https://webpack.github.io/docs/testing.html#compile-and-test
  output: {
    path: path.resolve(__dirname, 'dist'), // Note: Physical files are only output by the production build task `npm run build`.
    publicPath: '/',
    filename: 'bundle.js'
  },
  stats: {
    colors: true,
    reasons: true,
    chunks: true
  },
  plugins: [
    new DotenvPlugin({
      allowEmptyValues: true,
      sample: './config/.env.development',
      path: './config/.env.development'
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('development'), // Tells React to build in either dev or prod modes. https://facebook.github.io/react/downloads.html (See bottom)
      __DEV__: true
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new HtmlWebpackPlugin({     // Create HTML file that includes references to bundled CSS and JS.
      template: 'src/index.ejs',
      minify: {
        removeComments: true,
        collapseWhitespace: true
      },
      inject: true
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: false,
      debug: true,
      noInfo: true, // set to false to see a list of every file being bundled.
      options: {
        sassLoader: {
          includePaths: [path.resolve(__dirname, 'src', 'scss')]
        },
        context: '/',
        postcss: () => [autoprefixer],
      }
    })
  ],
  module: {
    rules: [
      {test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel-loader']},
      {test: /\.eot(\?v=\d+.\d+.\d+)?$/, loader: 'file-loader'},
      {test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff'},
      {test: /\.[ot]tf(\?v=\d+.\d+.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream'},
      {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml'},
      {test: /\.(jpe?g|png|gif)$/i, loader: 'file-loader?name=[name].[ext]'},
      {test: /\.ico$/, loader: 'file-loader?name=[name].[ext]'},
      {test: /(\.css|\.scss)$/, loaders: ['style-loader', 'css-loader?sourceMap', 'postcss-loader', 'sass-loader?sourceMap']}
    ]
  }
};
<|endoftext|>


<commit_before>// Distance in feet to speak approaching street.
var m_dblApproachDistanceKm = convertFTtoKM(200.0);

var m_bSpeakLocation = false;

// Intersection history, last X items.
var m_aryIntersectionHistory = new Array();

// Position history, last X items.
var m_aryPositionHistory = new Array();
var m_iDirectionTimeMs = 10000;

var m_strLastIntersection = "";
var m_strLastAddress = "";

function setCookie(cname) {
    var date = new Date();
    date.setTime(date.getTime() + (14*24*60*60*1000));
    var expires = "expires="+ date.toUTCString();
    document.cookie = cname + "=" + m_strUsername + ";" + expires;
}

function getCookie(cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for(var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

function checkCookie() {
    m_strUsername=getCookie("username");
    if (m_strUsername != "") {
        //do nothing
    } else {
       m_strUsername = prompt("To use this service, you must enter your GeoName username below : ", "Username");
       if (m_strUsername != "" && m_strUsername != null) {
           setCookie("username", m_strUsername, 30);
       }
    }
}

function resetCookie() {
		m_strUsername = prompt("To use this service, you must enter your GeoName username below : ", "Username");
    if (m_strUsername != "" && m_strUsername != null) {
         setCookie("username", m_strUsername, 30);
		}
}

$(document).ready(function()
{
  document.getElementById('edAddressTimeout').value = Number(m_iAddrFrequencyMs / 1000).toFixed(1);
  document.getElementById('edIntersectionTimeout').value = Number(m_iIntersectionFrequencyMs / 1000).toFixed(1);
  document.getElementById('edDirectionTime').value = Number(m_iDirectionTimeMs / 1000).toFixed(1);
  document.getElementById('edIntersectionApproach').value = Number(convertKMtoFT(m_dblApproachDistanceKm)).toFixed(1);

  if('speechSynthesis' in window)
  {
    // You're good to go!
  }
  else
  {
    alert("Text to Speech is not available in this browser");
  }

  if('geolocation' in navigator)
  {
    // You're good to go!
  }
  else
  {
    alert("Geolocation is not available in this browser");
  }

  $("#btnFollowStreets").click(function(e)
  {
    // Stops our form from resetting and going to the top of the page.
    // If the form is just a div, preventDefault is not needed.
    e.preventDefault();

    if(m_idFollowStreets == 0)
    {
      // This is stupid, but ios needs some text spoken here.
      SpeakText("Start");

      StartFollowingStreets();
      this.value = "Stop";
    }
    else
    {
      SpeakText("Stop");
      StopFollowingStreets();
      this.value = "Start";

      // Reset our values
      m_aryIntersectionHistory.length = 0;

	  m_strLastIntersection = "";
      m_strLastAddress = "";
    }
  });

  $("#btnCurrentLocation").click(function(e)
  {
    // Stops our form from resetting and going to the top of the page.
    // If the form is just a div, preventDefault is not needed.
    e.preventDefault();

    SpeakText("Location");
    m_bSpeakLocation = true;

    m_strLastAddress = "";

    GetCurrentLocation();
  });

  $("#btnApplySettings").click(function(e)
  {
    m_iIntersectionFrequencyMs = Math.max(document.getElementById('edIntersectionTimeout').value * 1000, 1500);
    m_iAddrFrequencyMs = document.getElementById('edAddressTimeout').value * 1000;
		m_iDirectionTimeMs = Math.max(document.getElementById('edDirectionTime').value * 1000, 5000);
    if(m_idFollowStreets != 0)
    {
      StopFollowingStreets();
      StartFollowingStreets();
    }

    m_dblApproachDistanceKm = convertFTtoKM(document.getElementById('edIntersectionApproach').value);

	if(/(iPad|iPhone|iPod)/g.test(navigator.userAgent) && !window.MSStream)
  {
    // This is an apple product that doesn't need to waste the data on the video.
    $('#videoKeepAwake').remove();
  }

  });

  //alert(GetBearing({latitude: 39.099912, longitude: -94.581213}, {latitude: 38.627089, longitude: -90.200203}));
});

function OnGetGeoCoordinates(position)
{
  var lastPosition = null;
  if(m_aryPositionHistory.length > 0)
  {
		 lastPosition = m_aryPositionHistory[m_aryPositionHistory.length - 1];
    if(lastPosition.coords.latitude != position.coords.latitude
      && lastPosition.coords.longitude != position.coords.longitude)
    {
      if(m_aryPositionHistory.length > 20)
      {
        m_aryPositionHistory.shift();
      }

      m_aryPositionHistory.push(position);
    }
  }
  else
  {
    m_aryPositionHistory.push(position);
  }

  var dblBearing = null;

  if(position.coords.heading)
  {
    dblBearing = position.coords.heading;
  }
  else
  {
    dblBearing = GetBearingFromPositions(m_aryPositionHistory, m_iDirectionTimeMs);
  }
  if(dblBearing)
  {
    if(dblBearing < 0)
    {
      dblBearing += 360.0;
    }
    var strDirection = "";
    if(dblBearing < 23 || dblBearing > 337)
    {
      strDirection = "N";
    }
    else if(dblBearing < 67)
    {
      strDirection = "NE";
    }
    else if(dblBearing < 113)
    {
      strDirection = "E";
    }
    else if(dblBearing < 157)
    {
      strDirection = "SE";
    }
    else if(dblBearing < 203)
    {
      strDirection = "S";
    }
    else if(dblBearing < 248)
    {
      strDirection = "SW";
    }
    else if(dblBearing < 293)
    {
      strDirection = "W";
    }
    else
    {
      strDirection = "NW";
    }

    document.getElementById('tdSpeedDirection').innerHTML = strDirection;

    console.log(dblBearing);
  }

  document.getElementById('edDebug').value += "lat: " + position.coords.latitude.toString() + " lng: " + position.coords.longitude.toString() + " acc: " + Number(convertKMtoFT(position.coords.accuracy / 1000)).toFixed(3) + ' ft\n';
};

function OnGetCurrentPositionError(positionError)
{
  var date = new Date();
  var strError = date + ": Error getCurrentPosition (" + positionError.code + "): " + positionError.message;

  console.warn(strError);

  document.getElementById('edError'). value += strError + '\n';
};

function OnWatchPositionError(positionError)
{
  var date = new Date();
  var strError = date + ": Error watchPosition (" + positionError.code + "): " + positionError.message;

  console.warn(strError);

  document.getElementById('edError'). value += strError + '\n';
};

function OnGetCurrentLocation(response)
{
  if (response.readyState == 4 && response.status == 200)
  {
    //document.getElementById('edCurrentLocation').value = response.responseText;

    var jsonObj = JSON.parse(response.responseText);

		if(!jsonObj.address)
    {
      if(jsonObj.status && jsonObj.status.message)
      {
        alert(jsonObj.status.message);
        return;
      }
    }

    var strFullAddress = jsonObj.address.streetNumber + " " + jsonObj.address.street;
    strFullAddress += "
" + jsonObj.address.placename + ", " + jsonObj.address.adminName1 + " " + jsonObj.address.postalcode;
    strFullAddress += "
Within " + Number(convertKMtoFT(jsonObj.address.distance)).toFixed(1) + " ft";
    $("#tdAddress").html(strFullAddress);

    document.getElementById('edDebug').value += "addr: " + jsonObj.address.streetNumber + " " + jsonObj.address.street + '\n';

    if(m_bSpeakLocation)
    {
      // Get the street number and street to send to the speech synthesizer.
      SpeakText(jsonObj.address.streetNumber + " " + jsonObj.address.street);
      m_strLastAddress = jsonObj.address.streetNumber + " " + jsonObj.address.street;
			m_bSpeakLocation = false;
    }
  }
};

function OnGetNearestIntersection(response)
{
  if (response.readyState == 4 && response.status == 200)
  {
    //document.getElementById('edIntersection').value = response.responseText;

    var jsonObj = JSON.parse(response.responseText);

    if(!jsonObj.intersection)
    {
			if(jsonObj.status && jsonObj.status.message)
      {
        alert(jsonObj.status.message);
      }
      return;
    }

    var strIntersection = jsonObj.intersection.street1+ "/" + jsonObj.intersection.street2;
    strIntersection += "
Dist: " + Number(convertKMtoFT(jsonObj.intersection.distance)).toFixed(1) + " ft";
    $("#tdIntersection").html(strIntersection);

    var intersection = {street1:jsonObj.intersection.street1, street2: jsonObj.intersection.street2, distance: jsonObj.intersection.distance};

    if(m_aryIntersectionHistory.length >= 10)
    {
      m_aryIntersectionHistory.shift();
    }

    m_aryIntersectionHistory.push(intersection);

    if(intersection.distance <= m_dblApproachDistanceKm
      && (jsonObj.intersection.street1 + " " + jsonObj.intersection.street2) != m_strLastIntersection)
    {
      // Get the street number and street to send to the speech synthesizer.
      SpeakText(jsonObj.intersection.street1 + " and " + jsonObj.intersection.street2);
      m_strLastIntersection = jsonObj.intersection.street1 + " " + jsonObj.intersection.street2;
    }
  }
};

function convertKMtoFT(dblKM)
{
  return 3280.84 * dblKM;
};

function convertFTtoKM(dblFT)
{
  return dblFT / 3280.84;
};
function GetBearingFromPositions(aryPositionHistory, iMilliseconds)
{
  if(aryPositionHistory.length <= 1)
  {
    // Not enough information for a bearing
    return;
  }
  var toPosition = aryPositionHistory[aryPositionHistory.length - 1];
  var fromPosition = null;
  var iRecentTimeMs = toPosition.timestamp;

  for(i = aryPositionHistory.length - 2; i >= 0; i--)
  {
    if(toPosition.timestamp - aryPositionHistory[i].timestamp <= iMilliseconds)
    {
      fromPosition = aryPositionHistory[i];
    }
    else
    {
      break;
    }
  }

  fromPosition = aryPositionHistory[0];

  if(!fromPosition)
  {
    // Too old of a position to use for the bearing.
    return;
  }

  return GetBearing(fromPosition, toPosition);
};
<commit_msg>Cleaned, commented, speaks full addresses<commit_after>/**
 * index.page.js
 * Contains functions for updating the GUI and calling functions outside of here.
 *
 * Made for TOM Makeathon at Northwestern University
 *
 * @license MIT license
 * @version 1.0
 * @author  Daniel Bednarczyk, Darcy Green (Need Knower), Joe Cummings, Julie Davies, Megan Reid, Wong Song Wei
 * @updated 2017-05-16
 * @link    https://makeathon-nu.github.io/Street-Nav/
 *
 * If address or intersection aren't working:
 *  Be sure that the username is entered correctly, capitalization matters.
 *  GPS must be enabled for the app or web browser on the device.
 *  Try clearing the cache for the web browser.
 *  Allow the browser to know your location.
 *
 * If text to speech isn't working:
 *  Turn the ringer on. iOS needs the ringer on for text to speech.
 *
 * Callback functions for geofunctions.js:
 *  OnGetGeoCoordinates(position)
 *  OnGetCurrentPositionError(positionError)
 *  OnWatchPositionError(positionError)
 *  OnGetCurrentLocation(response)
 *  OnGetNearestIntersection(response)
 *
 */

// Distance in feet to speak approaching street.
var m_dblApproachDistanceKm = convertFTtoKM(200.0);

// Speak location when retrieved
var m_bSpeakLocation = false;

// Position history, last X items.
var m_aryPositionHistory = new Array();

// Amount of time to go back in the history to get a bearing
// It would be better if this was an amount of distance rather than time.
//   The reason for distance is if you are standing in one place, the bearing will change.
var m_iDirectionTimeMs = 10000;

// Last intersection spoken
var m_strLastIntersection = "";

// Last address spoken
var m_strLastAddress = "";

/**
  Initialization
*/
$(document).ready(function()
{
  // Decide if username information should be shown
  if(isCookieValid("username"))
  {
    // Hide username prompt
    displayMainPage();
  }
  else
  {
    // Hide main content
    displayUsernamePrompt();
  }

  // Display default values
  document.getElementById('edAddressTimeout').value = Number(m_iAddrFrequencyMs / 1000).toFixed(1);
  document.getElementById('edIntersectionTimeout').value = Number(m_iIntersectionFrequencyMs / 1000).toFixed(1);
  document.getElementById('edDirectionTime').value = Number(m_iDirectionTimeMs / 1000).toFixed(1);
  document.getElementById('edIntersectionApproach').value = Number(convertKMtoFT(m_dblApproachDistanceKm)).toFixed(1);

  // Show the user if text to speech or geolocation isn't available in the browser
  // This does not check if gps is on.
  if('speechSynthesis' in window)
  {
    // You're good to go!
  }
  else
  {
    alert("Text to Speech is not available in this browser");
  }

  if('geolocation' in navigator)
  {
    // You're good to go!
  }
  else
  {
    alert("Geolocation is not available in this browser");
  }

  // Click function for following the street intersections
  $("#btnFollowStreets").click(function(e)
  {
    // Stops our form from resetting and going to the top of the page.
    // If the form is just a div, preventDefault is not needed.
    e.preventDefault();

    if(m_idFollowStreets == 0)
    {
      // This is stupid, but ios needs some text spoken here.
      SpeakText("Start");

      // Start the process and display stop on the GUI.
      StartFollowingStreets();
      this.value = "Stop";
    }
    else
    {
      // This is stupid, but ios needs some text spoken here.
      SpeakText("Stop");

      // Stop the process and display start on the GUI
      StopFollowingStreets();
      this.value = "Start";

      // Reset our values
	  m_strLastIntersection = "";
      m_strLastAddress = "";
    }
  });

  // Click function for getting the current address
  $("#btnCurrentLocation").click(function(e)
  {
    // Stops our form from resetting and going to the top of the page.
    // If the form is just a div, preventDefault is not needed.
    e.preventDefault();

    // This is stupid, but ios needs some text spoken here.
    SpeakText("Location");

    // Guarantee the next location found will be spoken.
    m_bSpeakLocation = true;
    m_strLastAddress = "";

    // Get the current address
    GetCurrentLocation();
  });

  // Click function for applying settings
  $("#btnApplySettings").click(function(e)
  {
    // Update all the settings
    m_iIntersectionFrequencyMs = Math.max(document.getElementById('edIntersectionTimeout').value * 1000, 1500);
    m_iAddrFrequencyMs = document.getElementById('edAddressTimeout').value * 1000;
	m_iDirectionTimeMs = Math.max(document.getElementById('edDirectionTime').value * 1000, 5000);
    m_dblApproachDistanceKm = convertFTtoKM(document.getElementById('edIntersectionApproach').value);

    // Stop and start following the streets so the new settings take effect
    if(m_idFollowStreets != 0)
    {
      StopFollowingStreets();
      StartFollowingStreets();
    }
  });

  // Click function for displaying terms of use
  $("#spanDisclaimer").click(function(e)
  {
    $('#terms_of_use').show();
  });

  // Click function for entering a user name for geonames.org
  $('#submitUsername').click(function(e)
  {
    m_strUsername = document.getElementById('edUsername').value;
    if(m_strUsername.length == 0)
    {
      alert('This service may not work until you enter a valid username.\n\nPlease visit http://www.geonames.org/login to create an account.');
    }

    // Set the cookie to expire in 10 years.
    setCookie("username", m_strUsername, 10*365);

    // Show the main page and scroll back to the top
    displayMainPage();
    scroll(0, 0);
  });

  // Click function for resetting the user name for geonames.org
  $('#btnResetUsername').click(function(e)
  {
    // Show the username prompt and scroll back to the top
    displayUsernamePrompt();
    scroll(0, 0);
  });

  $('#ckInternational').click(function(e)
  {
    m_bInternational = this.checked;
  });

  // On Android, a video can play hidden, but the screen will not go to sleep.
  // Therefore, any code for the video has been removed.
//  if(/(iPad|iPhone|iPod)/g.test(navigator.userAgent) && !window.MSStream)
//  {
//    // This is an apple product that doesn't need to waste the data on the video.
//    $('#videoKeepAwake').remove();
//  }
});

//******************* GEOFUNCTION CALLBACKS ******************************//
/**
  Callback from geofunctions when coordinates have been given
*/
function OnGetGeoCoordinates(position)
{
  var lastPosition = null;

  if(m_aryPositionHistory.length > 0)
  {
    lastPosition = m_aryPositionHistory[m_aryPositionHistory.length - 1];

    // Add the coordinates to the history if it isn't the same as the last one.
    if(lastPosition.coords.latitude != position.coords.latitude
      && lastPosition.coords.longitude != position.coords.longitude)
    {
      // Only allow 20 items in the history array
      if(m_aryPositionHistory.length > 20)
      {
        m_aryPositionHistory.shift();
      }

      // Add the coordinates
      m_aryPositionHistory.push(position);
    }
  }
  else
  {
    // Add the coordinates
    m_aryPositionHistory.push(position);
  }

  var dblBearing = null;

  if(position.coords.heading)
  {
    // I have not seen this being set
    dblBearing = position.coords.heading;
  }
  else
  {
    // Get the bearing based on the history
    dblBearing = GetBearingFromPositions(m_aryPositionHistory, m_iDirectionTimeMs);
  }

  if(dblBearing)
  {
    // Make sure the bearing is positive
    if(dblBearing < 0)
    {
      dblBearing += 360.0;
    }

    // Update the direction in the GUI.
    var strDirection = getDirectionText(dblBearing);

    document.getElementById('tdSpeedDirection').innerHTML = strDirection;
  }

  // Update debug information for the coordinates
  document.getElementById('edDebug').value += "lat: " + position.coords.latitude.toString() + " lng: " + position.coords.longitude.toString() + " acc: " + Number(convertKMtoFT(position.coords.accuracy / 1000)).toFixed(3) + ' ft\n';
};

/**
  Callback from geofunctions when getting the coordinates errors out due to timeout or other
*/
function OnGetCurrentPositionError(positionError)
{
  // Update debug information with the error
  var date = new Date();
  var strError = date + ": Error getCurrentPosition (" + positionError.code + "): " + positionError.message;

  console.warn(strError);

  document.getElementById('edError'). value += strError + '\n';
};

/**
  Callback from geofunctions when getting the coordinates errors out due to timeout or other
*/
function OnWatchPositionError(positionError)
{
  // Update debug information with the error
  var date = new Date();
  var strError = date + ": Error watchPosition (" + positionError.code + "): " + positionError.message;

  console.warn(strError);

  document.getElementById('edError'). value += strError + '\n';
};

/**
  Callback from geofunctions when the current location is received
*/
function OnGetCurrentLocation(response)
{
  if (response.readyState == 4
    && response.status == 200)
  {
    // Request is finished and successful

    // Parse the response
    var jsonObj = JSON.parse(response.responseText);

    if(!jsonObj.address)
    {
      if(jsonObj.status && jsonObj.status.message)
      {
        // A message indicates there is no address.
        alert(jsonObj.status.message);
        return;
      }
    }

    // Piece together the address and update the GUI
    var strFullAddress = jsonObj.address.streetNumber + " " + jsonObj.address.street;
    strFullAddress += "
" + jsonObj.address.placename + ", " + jsonObj.address.adminName1 + " " + jsonObj.address.postalcode;
    strFullAddress += "
Within " + Number(convertKMtoFT(jsonObj.address.distance)).toFixed(1) + " ft";
    $("#tdAddress").html(strFullAddress);

    // Update debug information
    document.getElementById('edDebug').value += "addr: " + jsonObj.address.streetNumber + " " + jsonObj.address.street + '\n';

    // Speak the address
    if(m_bSpeakLocation)
    {
      // Get the street number and street to send to the speech synthesizer.
      SpeakText(jsonObj.address.streetNumber + " " + getSpeakingAddress(jsonObj.address.street));

      // Update the last address spoken
      m_strLastAddress = jsonObj.address.streetNumber + " " + jsonObj.address.street;
      m_bSpeakLocation = false;
    }
  }
};

/**
  Callback from geofunctions when the nearest intersection is received
*/
function OnGetNearestIntersection(response)
{
  if (response.readyState == 4
    && response.status == 200)
  {
    // Request is finished and successful

    // Parse the response
    var jsonObj = JSON.parse(response.responseText);

    if(!jsonObj.intersection)
    {
      if(jsonObj.status && jsonObj.status.message)
      {
        // A message indicates there is no intersection.
        alert(jsonObj.status.message);
      }
      return;
    }

    // Piece together the intersection and update the GUI
    var strIntersection = jsonObj.intersection.street1+ " / " + jsonObj.intersection.street2;
    strIntersection += "
Dist: " + Number(convertKMtoFT(jsonObj.intersection.distance)).toFixed(1) + " ft";
    $("#tdIntersection").html(strIntersection);

    var intersection = {street1:jsonObj.intersection.street1, street2: jsonObj.intersection.street2, distance: jsonObj.intersection.distance};

    // Speak the address if we are within range to speak
    if(intersection.distance <= m_dblApproachDistanceKm
      && (jsonObj.intersection.street1 + " " + jsonObj.intersection.street2) != m_strLastIntersection)
    {
      // Get the street number and street to send to the speech synthesizer.
      SpeakText(getSpeakingAddress(jsonObj.intersection.street1) + " and " + getSpeakingAddress(jsonObj.intersection.street2));

      // Update the last intersection spoken
      m_strLastIntersection = jsonObj.intersection.street1 + " " + jsonObj.intersection.street2;
    }
  }
};
//******************* END GEOFUNCTION CALLBACKS ******************************//

//******************* COOKIE FUNCTIONS ******************************//
/**
  Set a cookie with the given information
*/
function setCookie(strCookieName, strUsername, iExpiresDays)
{
  var date = new Date();
  date.setTime(date.getTime() + (iExpiresDays*24*60*60*1000));
  var strExpires = "expires="+ date.toUTCString();
  document.cookie = strCookieName + "=" + strUsername + ";" + strExpires;
}

/**
  Get the cookie
*/
function getCookieValue(strCookieName)
{
  strCookieName += "=";
  var decodedCookie = decodeURIComponent(document.cookie);
  var aryCookiePieces = decodedCookie.split(';');
  for(var i = 0; i < aryCookiePieces.length; i++)
  {
    var strCookiePiece = aryCookiePieces[i];
    while(strCookiePiece.charAt(0) == ' ')
    {
      strCookiePiece = strCookiePiece.substring(1);
    }
    if(strCookiePiece.indexOf(strCookieName) == 0)
    {
      return strCookiePiece.substring(strCookieName.length, strCookiePiece.length);
    }
  }

  return "";
}

/**
  Check if there is a username
*/
function isCookieValid(strCookieName)
{
  var strCookieValue = getCookieValue(strCookieName);
  return (strCookieValue != "");
}
//******************* END COOKIE FUNCTIONS ******************************//

/**
  Display username prompt
*/
function displayUsernamePrompt()
{
  $('#username_container').show();
  $('#terms_of_use').hide();
  $('#main_container').hide();
}

/**
  Display main page, hide username prompt
*/
function displayMainPage()
{
  $('#username_container').hide();
  $('#terms_of_use').hide();
  $('#main_container').show();
}

/**
  Convert kilometers to feet
*/
function convertKMtoFT(dblKM)
{
  return 3280.84 * dblKM;
};

/**
  Convert feet to kilometers
*/
function convertFTtoKM(dblFT)
{
  return dblFT / 3280.84;
};

/**
  Get the bearing based on the history
*/
function GetBearingFromPositions(aryPositionHistory, iMilliseconds)
{
  if(aryPositionHistory.length <= 1)
  {
    // Not enough information for a bearing
    return;
  }

  var toPosition = aryPositionHistory[aryPositionHistory.length - 1];
  var fromPosition = null;
  var iRecentTimeMs = toPosition.timestamp;

  for(i = aryPositionHistory.length - 2; i >= 0; i--)
  {
    // Check the timestamp to see if we are done
    if(toPosition.timestamp - aryPositionHistory[i].timestamp <= iMilliseconds)
    {
      fromPosition = aryPositionHistory[i];
    }
    else
    {
      break;
    }
  }

  fromPosition = aryPositionHistory[0];

  if(!fromPosition)
  {
    // Too old of a position to use for the bearing.
    return;
  }

  // Return the bearing from the coordinates
  return GetBearing(fromPosition, toPosition);
};

/**
  Get the direction text based on the bearing
*/
function getDirectionText(dblBearing)
{
  if(dblBearing < 23 || dblBearing > 337)
  {
    return "N";
  }
  else if(dblBearing < 67)
  {
    return "NE";
  }
  else if(dblBearing < 113)
  {
    return "E";
  }
  else if(dblBearing < 157)
  {
    return "SE";
  }
  else if(dblBearing < 203)
  {
    return "S";
  }
  else if(dblBearing < 248)
  {
    return "SW";
  }
  else if(dblBearing < 293)
  {
    return "W";
  }
  else
  {
    return "NW";
  }

  return "";
}

/**
  Get the speaking address.  Change abbreviations the the entire word so speech sounds correct.
  We heard dr as doctor, drive and the letters d-r.  This function converts dr to drive.
*/
function getSpeakingAddress(strAddress)
{
  var strSpeakAddress = "";
  var aryAddressPieces = strAddress.split(" ");

  // Get the direction from the first word
  switch(aryAddressPieces[0].toLowerCase())
  {
  case "n":
    strSpeakAddress = "North";
    break;
  case "ne":
    strSpeakAddress = "Northeast";
    break;
  case "nw":
    strSpeakAddress = "Northwest";
    break;
  case "e":
    strSpeakAddress = "East";
    break;
  case "w":
    strSpeakAddress = "West";
    break;
  case "s":
    strSpeakAddress = "South";
    break;
  case "se":
    strSpeakAddress = "Southeast";
    break;
  case "sw":
    strSpeakAddress = "Southwest";
    break;
  default:
    // The first word didn't match anything, add it to the address.
    strSpeakAddress = aryAddressPieces[0];
  }

  // Get the middle, everything but the last word
  for(i = 1; i < aryAddressPieces.length - 1; i++)
  {
    strSpeakAddress += " " + aryAddressPieces[i];
  }

  // Get the end of the address from the last word
  for(i = 0; i < m_aryAddrSuffixTable.length; i++)
  {
    var test = m_aryAddrSuffixTable[i][0];
    test = m_aryAddrSuffixTable[i][1];
    if(aryAddressPieces[aryAddressPieces.length - 1].toLowerCase() == m_aryAddrSuffixTable[i][0])
    {
      strSpeakAddress += " " + m_aryAddrSuffixTable[i][1];
      break;
    }
  }

  if(i == m_aryAddrSuffixTable.length)
  {
    // The last word didn't match anything in the street abbreviation table, add it to the address.
    strSpeakAddress += " " + aryAddressPieces[aryAddressPieces.length - 1];
  }

  return strSpeakAddress;
}
<|endoftext|>


<commit_before>var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ProgressBarPlugin = require('progress-bar-webpack-plugin');

var ROOT_PATH = path.resolve(__dirname);
var APP_PATH = path.resolve(ROOT_PATH, 'webapp');

module.exports = {
    devtool: 'cheap-module-eval-source-map',
    entry: {
        main: [
            'eventsource-polyfill',
            //'webpack-hot-middleware/client?path=/__weback_hmr&timeout=20000',
            'webpack-hot-middleware/client?reload=true',
            './webapp/index'
        ]
    },
    output: {
        publicPath: '/assets',
        path: path.resolve(__dirname, 'public/assets'),
        filename: '[name].js'
    },
    plugins: [
        new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')}),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin(),
        new ExtractTextPlugin('[name].css'),
        new ProgressBarPlugin(),
        new webpack.DllReferencePlugin({
            manifest: path.resolve(__dirname, 'public/assets/vendor.manifest.json')
        })
    ],
    module: {
        loaders: [
            {
                test: /\.scss$/,
                exclude: /^node_modules$/,
                loader: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: ['css-loader', 'autoprefixer-loader', 'sass-loader']
                }),
                include: [APP_PATH]
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                include: [APP_PATH],
                loader: 'babel-loader',
                query: {
                    'presets': ['es2015', 'react', 'stage-0'],
                    'env': {
                        'development': {
                            'presets': ['react-hmre']
                        }
                    }
                }
            },
            {
                test: /\.(eot|woff|svg|ttf|woff2|gif|appcache)(\?|$)/,
                exclude: /^node_modules$/,
                loader: 'file-loader?name=[name].[ext]',
                include: [APP_PATH]
            },
            {
                test: /\.(png|jpg)$/,
                exclude: /^node_modules$/,
                loader: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]',
                include: [APP_PATH]
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.jsx', '.scss', '.css']
    }
};
<commit_msg>plugin name<commit_after>var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ProgressBarPlugin = require('progress-bar-webpack-plugin');

var ROOT_PATH = path.resolve(__dirname);
var APP_PATH = path.resolve(ROOT_PATH, 'webapp');

module.exports = {
    devtool: 'cheap-module-eval-source-map',
    entry: {
        main: [
            'eventsource-polyfill',
            'webpack-hot-middleware/client?path=/__webpack_hmr&reload=true&timeout=20000',
            './webapp/index'
        ]
    },
    output: {
        publicPath: '/assets',
        path: path.resolve(__dirname, 'public/assets'),
        filename: '[name].js'
    },
    plugins: [
        new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')}),
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin(),
        new ExtractTextPlugin('[name].css'),
        new ProgressBarPlugin(),
        new webpack.DllReferencePlugin({
            manifest: path.resolve(__dirname, 'public/assets/vendor.manifest.json')
        })
    ],
    module: {
        loaders: [
            {
                test: /\.scss$/,
                exclude: /^node_modules$/,
                loader: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: ['css-loader', 'autoprefixer-loader', 'sass-loader']
                }),
                include: [APP_PATH]
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                include: [APP_PATH],
                loader: 'babel-loader',
                query: {
                    'presets': ['es2015', 'react', 'stage-0'],
                    'env': {
                        'development': {
                            'presets': ['react-hmre']
                        }
                    }
                }
            },
            {
                test: /\.(eot|woff|svg|ttf|woff2|gif|appcache)(\?|$)/,
                exclude: /^node_modules$/,
                loader: 'file-loader?name=[name].[ext]',
                include: [APP_PATH]
            },
            {
                test: /\.(png|jpg)$/,
                exclude: /^node_modules$/,
                loader: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]',
                include: [APP_PATH]
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.jsx', '.scss', '.css']
    }
};
<|endoftext|>


<commit_before>var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = Object.assign({}, {
  plugins: [
    new webpack.DefinePlugin(Object.assign({}, {
      'process.env.NODE_ENV': '"production"'
    })),
    new HtmlWebpackPlugin({
      inject: 'body',
      template: 'src/main.html'
    }),
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false
      }
    })
  ]
}, require('./config'));
<commit_msg>Disable uglify from the production build<commit_after>var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = Object.assign({}, {
  plugins: [
    new webpack.DefinePlugin(Object.assign({}, {
      'process.env.NODE_ENV': '"production"'
    })),
    new HtmlWebpackPlugin({
      inject: 'body',
      template: 'src/main.html'
    }),
    new webpack.optimize.OccurenceOrderPlugin()
    // new webpack.optimize.UglifyJsPlugin({
    //   compressor: {
    //     warnings: false
    //   }
    // })
  ]
}, require('./config'));
<|endoftext|>


<commit_before>const merge   = require("webpack-merge");
const webpack = require("webpack");

const autoprefix         = require("./parts/autoprefix");
const clean              = require("./parts/clean");
const commonConfig       = require("./common");
const extractBundles     = require("./parts/extractBundles");
const extractCSS         = require("./parts/extractCSS");
const generateSourceMaps = require("./parts/generateSourceMaps");
const loadImages         = require("./parts/loadImages");
const paths              = require("./parts/paths");

const productionConfig = merge([
	clean(paths.build),
	extractBundles([
		{
			name: "vendor",
			minChunks: ({ resource }) => (
				resource &&
				resource.indexOf("node_modules") >= 0 &&
				resource.match(/\.js$/)
			)
		}
	]),
	generateSourceMaps({
		type: "source-map"
	}),
	extractCSS({
		use: [
			"css-loader",
			autoprefix()
		]
	}),
	loadImages({
		options: {
			limit: 15000,
			name: "[name].[ext]"
		}
	})
]);

module.exports = merge(commonConfig, productionConfig);
<commit_msg>Added attachRevision to the prod config.<commit_after>const merge   = require("webpack-merge");
const webpack = require("webpack");

const attachRevision     = require("./parts/attachRevision");
const autoprefix         = require("./parts/autoprefix");
const clean              = require("./parts/clean");
const commonConfig       = require("./common");
const extractBundles     = require("./parts/extractBundles");
const extractCSS         = require("./parts/extractCSS");
const generateSourceMaps = require("./parts/generateSourceMaps");
const loadImages         = require("./parts/loadImages");
const paths              = require("./parts/paths");

const productionConfig = merge([
	clean(paths.build),
	extractBundles([
		{
			name: "vendor",
			minChunks: ({ resource }) => (
				resource &&
				resource.indexOf("node_modules") >= 0 &&
				resource.match(/\.js$/)
			)
		}
	]),
	generateSourceMaps({
		type: "source-map"
	}),
	extractCSS({
		use: [
			"css-loader",
			autoprefix()
		]
	}),
	loadImages({
		options: {
			limit: 15000,
			name: "[name].[ext]"
		}
	}),
	attachRevision()
]);

module.exports = merge(commonConfig, productionConfig);
<|endoftext|>


<commit_before>var fullscreen = false;
var video;

$(document).ready(function() {
    video = document.getElementById('video');

    if ($('#start-page').hasClass('active'))
        $('.content').addClass('small');
    else
        $('.content').removeClass('small');

    /* Connect to server */
    $('#connect').click(function() {
        $('#start-page').animate({'opacity': '.1', 'pointer-events': 'none'}, 200);
        $('#loader-page').fadeIn(200);
        $('#loader').addClass('load');

        if ($('#host').val() !== "")
            connect($('#host').val());
        else
            connect('http://op-en.se:5000');

        setTimeout(function() {
            $('#start-page').removeClass('active');
            $('#loader-page').fadeOut(200);
            $('.content').removeClass('small');
            setTimeout(function() {
                $('#loader').removeClass('load');
            }, 200);
            $('#video-page').addClass('active');
            $('#start-page').removeAttr('style');
        }, 500);
    });

    //var time = getTimestamps();
    //console.log(time);

    var timestamps = new Array(1.01, 2.08, 6.15, 7.19, 9.00, 10.06, 11.14);
    var coins = 0;
    console.log(timestamps[0]);
    console.log(timestamps[1]);
    console.log(timestamps[2]);

    var test = false;

    video.addEventListener('timeupdate', function() {
        if(this.currentTime >= timestamps[coins] + 0.15) {
            this.pause();
            if(++coins >= timestamps.length) {
                video.removeEventListener('timeupdate', arguments.callee);
                test = true;
            }
        }
    });

    /* On settings or statistics icon click */
    $('.toggle').click(function() {
        toggle(this);
    });

    /* Go back to start page */
    $('#back').on('click', function() {
        $('#video-page').removeClass('active');
        $('#start-page').addClass('active');
        $('.content').addClass('small');
    });

    /* Show/hide fullscreen icons and cursor on inactivity */
    var timer;
    document.getElementById('video-page').addEventListener('mousemove', function() {
        //document.body.style.cursor = 'default';
        $('#toggle-stats').show();
        $('#fullscreen').show();
        clearTimeout(timer);
        timer = setTimeout(function() {
            //document.body.style.cursor = 'none';
            if(fullscreen) $('#toggle-stats').fadeOut(200);
            $('#fullscreen').fadeOut(200);
        }, 1500 );
    });

    /* Set fullscreen on icon click or double click */
    $('#fullscreen').click(function() {
        toggleFullscreen();
        $('#toggle-stats').toggleClass('closed');
    });
    $('#video').dblclick(function() {
        toggleFullscreen();
    });

    /* Set fullscreen on f keyup */
    $(document).keyup(function(e) {
        if ($('*:focus').length === 0)
            if (e.keyCode == 70)
                toggleFullscreen();
    });

    /* Play video on space keydown */
    $(document).keydown(function(e) {
        if (e.keyCode == 32)
            video.play();
    });

    /* On fullscreen exit */
    $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange', function() {
        if (!(document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen)) {
            fullscreen = false;
            $('#fullscreen').css({'background-image': 'url(images/fullscreen.svg)', 'position': 'absolute'});
            $('#stats').removeClass('fullscreen');
        }
    });

    /* Disable right click on video */
    $("video").bind("contextmenu",function(){
        return false;
    });
});

/* Toggle fullscreen */
function toggleFullscreen() {
    if (!document.fullscreenElement && !document.mozFullScreenElement &&
        !document.webkitFullscreenElement && !document.msFullscreenElement ) {
        if (video.requestFullscreen) {
            video.requestFullscreen();
        } else if (video.webkitRequestFullscreen) {
            video.webkitRequestFullscreen();
        } else if (video.mozRequestFullScreen) {
            video.mozRequestFullScreen();
        }
        fullscreen = true;
        $('#stats-image').css({'background-image': 'url(images/arrow-reverse.png)'});
        $('#fullscreen').css({'background-image': 'url(images/fullscreen-exit.svg)', 'position': 'fixed'});
        if (!$('#stats-image').hasClass('closed'))
            $('#stats').addClass('bg');
    }
    else {
        if (document.exitFullscreen) {
            document.exitFullscreen();
        } else if (document.webkitExitFullscreen) {
            document.webkitExitFullscreen();
        } else if (document.msExitFullscreen) {
            document.msExitFullscreen();
        } else if (document.mozCancelFullScreen) {
            document.mozCancelFullScreen();
        }
        fullscreen = false;
        $('#stats-image').css({'background-image': 'url(images/arrow.png)'});
        $('#fullscreen').css({'background-image': 'url(images/fullscreen.svg)', 'position': 'absolute'});
        $('#stats').removeClass('bg');
    }
    $('#stats').toggleClass('fullscreen');
}

/* Toggle settings/statistics */
function toggle(elem) {
    var button, box, section;
    if (elem == document.getElementById('toggle-stats')) {
        button = $('#toggle-stats > div');
        box = $('#stats-box');
        section = $('#stats');
    }
    else if (elem == document.getElementById('toggle-settings')) {
        button = $('#toggle-settings > div');
        box = $('#settings-box');
        section = $('#settings');
    }
    button.css({transition: '.2s'});
    if (button.hasClass('closed')) {
        box.css({marginTop: '28px'});
        box.fadeIn(200).animate({marginTop: '-=15px'},200).dequeue();
        if (stats)
            button.css({transform: 'rotate(360deg)'});
        else
            button.css({transform: 'rotate(-360deg)'});
        button.removeClass('closed');
        setTimeout(function() {
            button.css({transition: '0s'});
            button.css({transform: 'rotate(0deg)'});
        }, 200);
    }
    else {
        box.fadeOut(100).animate({marginTop: '-=15px'},200).dequeue();
        setTimeout(function() {
            box.css({marginTop: '+=15px'});
        }, 200);
        if (stats)
            button.css({transform: 'rotate(180deg)'});
        else
            button.css({transform: 'rotate(-180deg)'});
        button.addClass('closed');
    }
    if (fullscreen)
        section.toggleClass('bg');

}

function getTimestamps() {
    var file = "timestamps",
        reader = (window.XMLHttpRequest !== null ) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
    reader.open("GET", file, false);
    reader.send();
    return reader.responseText.split(" ");
}
<commit_msg>Timestamps test<commit_after>var fullscreen = false;
var video;

$(document).ready(function() {
    video = document.getElementById('video');

    if ($('#start-page').hasClass('active'))
        $('.content').addClass('small');
    else
        $('.content').removeClass('small');

    /* Connect to server */
    $('#connect').click(function() {
        $('#start-page').animate({'opacity': '.1', 'pointer-events': 'none'}, 200);
        $('#loader-page').fadeIn(200);
        $('#loader').addClass('load');

        if ($('#host').val() !== "")
            connect($('#host').val());
        else
            connect('http://op-en.se:5000');

        setTimeout(function() {
            $('#start-page').removeClass('active');
            $('#loader-page').fadeOut(200);
            $('.content').removeClass('small');
            setTimeout(function() {
                $('#loader').removeClass('load');
            }, 200);
            $('#video-page').addClass('active');
            $('#start-page').removeAttr('style');
        }, 500);
    });

    //var time = getTimestamps();
    //console.log(time);

    //var timestamps = new Array(1.01, 2.08, 6.15, 7.19, 9.00, 10.06, 11.14);
    var timestamps = getTimestamps();
    console.log("LENGTH: " + timestamps.length);

    var coins = 0;
    //getTimestamps();
    console.log(timestamps[0]);
    console.log(timestamps[1]);
    console.log(timestamps[2]);

    var test = false;

    video.addEventListener('timeupdate', function() {
        if(this.currentTime >= timestamps[coins] + 0.15) {
            this.pause();
            if(++coins >= timestamps.length) {
                video.removeEventListener('timeupdate', arguments.callee);
                test = true;
            }
        }
    });

    /* On settings or statistics icon click */
    $('.toggle').click(function() {
        toggle(this);
    });

    /* Go back to start page */
    $('#back').on('click', function() {
        $('#video-page').removeClass('active');
        $('#start-page').addClass('active');
        $('.content').addClass('small');
    });

    /* Show/hide fullscreen icons and cursor on inactivity */
    var timer;
    document.getElementById('video-page').addEventListener('mousemove', function() {
        //document.body.style.cursor = 'default';
        $('#toggle-stats').show();
        $('#fullscreen').show();
        clearTimeout(timer);
        timer = setTimeout(function() {
            //document.body.style.cursor = 'none';
            if(fullscreen) $('#toggle-stats').fadeOut(200);
            $('#fullscreen').fadeOut(200);
        }, 1500 );
    });

    /* Set fullscreen on icon click or double click */
    $('#fullscreen').click(function() {
        toggleFullscreen();
        $('#toggle-stats').toggleClass('closed');
    });
    $('#video').dblclick(function() {
        toggleFullscreen();
    });

    /* Set fullscreen on f keyup */
    $(document).keyup(function(e) {
        if ($('*:focus').length === 0)
            if (e.keyCode == 70)
                toggleFullscreen();
    });

    /* Play video on space keydown */
    $(document).keydown(function(e) {
        if (e.keyCode == 32)
            video.play();
    });

    /* On fullscreen exit */
    $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange', function() {
        if (!(document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen)) {
            fullscreen = false;
            $('#fullscreen').css({'background-image': 'url(images/fullscreen.svg)', 'position': 'absolute'});
            $('#stats').removeClass('fullscreen');
        }
    });

    /* Disable right click on video */
    $("video").bind("contextmenu",function(){
        return false;
    });
});

/* Toggle fullscreen */
function toggleFullscreen() {
    if (!document.fullscreenElement && !document.mozFullScreenElement &&
        !document.webkitFullscreenElement && !document.msFullscreenElement ) {
        if (video.requestFullscreen) {
            video.requestFullscreen();
        } else if (video.webkitRequestFullscreen) {
            video.webkitRequestFullscreen();
        } else if (video.mozRequestFullScreen) {
            video.mozRequestFullScreen();
        }
        fullscreen = true;
        $('#stats-image').css({'background-image': 'url(images/arrow-reverse.png)'});
        $('#fullscreen').css({'background-image': 'url(images/fullscreen-exit.svg)', 'position': 'fixed'});
        if (!$('#stats-image').hasClass('closed'))
            $('#stats').addClass('bg');
    }
    else {
        if (document.exitFullscreen) {
            document.exitFullscreen();
        } else if (document.webkitExitFullscreen) {
            document.webkitExitFullscreen();
        } else if (document.msExitFullscreen) {
            document.msExitFullscreen();
        } else if (document.mozCancelFullScreen) {
            document.mozCancelFullScreen();
        }
        fullscreen = false;
        $('#stats-image').css({'background-image': 'url(images/arrow.png)'});
        $('#fullscreen').css({'background-image': 'url(images/fullscreen.svg)', 'position': 'absolute'});
        $('#stats').removeClass('bg');
    }
    $('#stats').toggleClass('fullscreen');
}

/* Toggle settings/statistics */
function toggle(elem) {
    var button, box, section;
    if (elem == document.getElementById('toggle-stats')) {
        button = $('#toggle-stats > div');
        box = $('#stats-box');
        section = $('#stats');
    }
    else if (elem == document.getElementById('toggle-settings')) {
        button = $('#toggle-settings > div');
        box = $('#settings-box');
        section = $('#settings');
    }
    button.css({transition: '.2s'});
    if (button.hasClass('closed')) {
        box.css({marginTop: '28px'});
        box.fadeIn(200).animate({marginTop: '-=15px'},200).dequeue();
        if (stats)
            button.css({transform: 'rotate(360deg)'});
        else
            button.css({transform: 'rotate(-360deg)'});
        button.removeClass('closed');
        setTimeout(function() {
            button.css({transition: '0s'});
            button.css({transform: 'rotate(0deg)'});
        }, 200);
    }
    else {
        box.fadeOut(100).animate({marginTop: '-=15px'},200).dequeue();
        setTimeout(function() {
            box.css({marginTop: '+=15px'});
        }, 200);
        if (stats)
            button.css({transform: 'rotate(180deg)'});
        else
            button.css({transform: 'rotate(-180deg)'});
        button.addClass('closed');
    }
    if (fullscreen)
        section.toggleClass('bg');

}

function getTimestamps() {
    var file = "http://stangen.asuscomm.com/timestamps",
        reader = (window.XMLHttpRequest !== null ) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
    reader.open("GET", file, false);
    reader.send();
    return reader.responseText.split(" ");
}
<|endoftext|>


<commit_before>// Separate Numbers with Commas in JavaScript **Pairing Challenge**

// I worked on this challenge with: Alicia Quezada.

// Pseudocode

// Initial Solution

// Refactored Solution

// Your Own Tests (OPTIONAL)

// Reflection<commit_msg>Add 7.5 challenge file<commit_after>// Separate Numbers with Commas in JavaScript **Pairing Challenge**

// I worked on this challenge with: Alicia Quezada.

// Pseudocode
/*
Input: Integer
Output: Return a comma separated integer as a string

Steps:
1. Define a function expression, giving the function an input (integer)
2. Convert integer into a string
3. Convert string into an array
4. Reverse the array elements
5. Slice the array into elements of 3
6. Insert comma at the end of each group of 3 elements
7. Join each of these group of 3 elements together
8. Return reverse of joined array
*/

// Initial Solution
var separateComma = function(integer) {

  var array = integer.toString().split("").reverse();
  for (var i = 3 ; i < array.length; i+=4) {
    array.splice(i,0,',');
  };
  var finalInteger = array.reverse().join('');
  console.log(finalInteger)
}

separateComma(123456);

// Refactored Solution
var separateComma = function(integer) {
  var array = integer.toString().split("").reverse();
  for (var i = 3 ; i < array.length; i+=4) {
    array.splice(i,0,',');
  };
  console.log(array.reverse().join(''));
}

// Your Own Tests (OPTIONAL)

// Reflection
/*
What was it like to approach the problem from the perspective of JavaScript? Did you approach the problem differently?
- It was definitely a different experience approaching the problem using JavaScript (as compared to Ruby)
- As we were not that familiar (yet) with some of the available methods in JavaScript, we took a bit of time to think of how to approach the problem
with our limited knowledge of JavScript.
- In the end, we were able to solve the problem successfully.

What did you learn about iterating over arrays in JavaScript?
- In JavaScript, there are no specific loop methods like .each to iterate over arrays (as compared to in Ruby)
- As such, I have to use a for loop to iterate over the length of the array

What was different about solving this problem in JavaScript?
- The method used was different in JavaScript. We used .splice method to help splice the array and add

What built-in methods did you find to incorporate in your refactored solution?
- We couldn't come up with too much refactoring in our refined solution since we had used the .splice method from the start, which already made the code concised and readable.
*/<|endoftext|>