<commit_before>const game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-demo', {
    preload,
    create,
    update,
    render
});

var player,
    playerHead,

    bar,
    barborder,

    cursors,
    score = 0,
    scoreText,

    bullets,
    bulletTimer = 0,

    fireButton,
    explosions,
    greenEnemies,
    enemyLaunchTimer,

    pauseKey,
    pauseImage,

    heart,
    hearts,
    livesCount = 3,
    gameOverText;

const PLAYER_STARTING_POSITION_X = 400,
    PLAYER_STARTING_POSITION_Y = 500,

    PLAYER_HEAD_STARTING_POSITION_X = 395,
    PLAYER_HEAD_STARTING_POSITION_Y = 455,

    BAR_BORDER_POSITION_X = 0,
    BAR_BORDER_POSITION_Y = 470,

    ACCLERATION = 300,
    DRAG = 400,
    MAX_SPEED = 400,
    EXPLOSION_SPEED = 12,
    FACTOR_DIFFICULTY = 1; //TODO: Set with score or etc.

function preload() {
    game.load.image('bar', 'assets/images/bar.png');
    game.load.image('player', 'assets/images/Bartender_80_88_invert.png');
    game.load.image('bullet', 'assets/images/green_olive_15_19.png');
    game.load.image('enemy-green', 'assets/images/glass_80_115_rotated.png');
    game.load.spritesheet('explosion', 'assets/images/explode.png', 133, 95, 6);
    game.load.image('barborder', './assets/images/barborder.png');
    game.load.image('playerhead', './assets/images/playerhead.png');
    game.load.image('paused', './assets/images/paused.png');
    game.load.image('heart', './assets/images/heart.png');
}

function create() {
    //Setting Arcade Physics system for all objects in the game
    game.physics.startSystem(Phaser.Physics.ARCADE);

    bar = game.add.tileSprite(0, 0, 800, 600, 'bar');
    barborder = game.add.sprite(BAR_BORDER_POSITION_X, BAR_BORDER_POSITION_Y, 'barborder');
    game.physics.enable(barborder, Phaser.Physics.ARCADE);
    barborder.body.immovable = true;
    //barborder.alpha = 0; // uncomment if you want the red line to disappear

    gameOverText = game.add.text(game.world.centerX, game.world.centerY, 'GAME OVER!', { font: '84px Arial', fill: '#fff' });
    gameOverText.anchor.setTo(0.5, 0.5);
    gameOverText.visible = false;

    scoreText = game.add.text(600, 550, 'score: 0', { fontSize: '32px', fill: '#F00' });

    pauseKey = this.input.keyboard.addKey(Phaser.Keyboard.P);
    pauseKey.onDown.add(togglePause, this);

    //Hearts group
    hearts = game.add.group();
    for (var i = 0; i < livesCount; i += 1) {
        heart = hearts.create(5 + i * 33, 560, 'heart');
    }

    //  Our bullet group
    bullets = game.add.group();
    bullets.enableBody = true;
    bullets.physicsBodyType = Phaser.Physics.ARCADE;
    bullets.createMultiple(10, 'bullet');
    bullets.setAll('anchor.x', 0.5);
    bullets.setAll('anchor.y', 1);
    bullets.setAll('outOfBoundsKill', true);
    bullets.setAll('checkWorldBounds', true);

    //  The hero!
    player = game.add.sprite(PLAYER_STARTING_POSITION_X, PLAYER_STARTING_POSITION_Y, 'player');
    player.anchor.setTo(0.5, 0.5);
    player.events.onKilled.add(endGame);

    game.physics.enable(player, Phaser.Physics.ARCADE);
    cursors = game.input.keyboard.createCursorKeys();
    fireButton = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);

    player.body.maxVelocity.setTo(MAX_SPEED, MAX_SPEED);
    //player.body.drag.setTo(DRAG, DRAG);

    // Setting the player head.
    playerHead = game.add.sprite(PLAYER_HEAD_STARTING_POSITION_X, PLAYER_HEAD_STARTING_POSITION_Y, 'playerhead');
    game.physics.enable(playerHead, Phaser.Physics.ARCADE);
    //playerHead.alpha = 0; // uncomment if you want the red line to disappear

    /*//  Add an emitter for the player's trail
     playerTrail = game.add.emitter(player.x, player.y + 10, 400);
     playerTrail.width = 10;
     playerTrail.makeParticles('bullet');
     playerTrail.setXSpeed(30, -30);
     playerTrail.setYSpeed(200, 180);
     playerTrail.setRotation(50, -50);
     playerTrail.setAlpha(1, 0.01, 800);
     playerTrail.setScale(0.05, 0.4, 0.05, 0.4, 2000, Phaser.Easing.Quintic.Out);
     playerTrail.start(false, 5000, 10);*/

    //  An explosion pool
    explosions = game.add.group();
    explosions.enableBody = true;
    explosions.physicsBodyType = Phaser.Physics.ARCADE;
    explosions.createMultiple(30, 'explosion');
    explosions.setAll('anchor.x', 0.5);
    explosions.setAll('anchor.y', 0.5);
    explosions.forEach(function(explosion) {
        explosion.animations.add('explosion');
    });

    //  The baddies!
    greenEnemies = game.add.group();
    greenEnemies.enableBody = true;
    greenEnemies.physicsBodyType = Phaser.Physics.ARCADE;
    greenEnemies.createMultiple(5 * FACTOR_DIFFICULTY, 'enemy-green'); //TODO: can add factor to number of enemies in dependence to difficutly level
    greenEnemies.setAll('anchor.x', 0.5); //places the anchor in the exact middle of the sprite, horizontally and vertically.
    greenEnemies.setAll('anchor.y', 0.5); //places the anchor in the exact middle of the sprite, horizontally and vertically.
    greenEnemies.setAll('scale.x', 0.5);
    greenEnemies.setAll('scale.y', 0.5);
    greenEnemies.setAll('angle', 180);
    greenEnemies.setAll('outOfBoundsKill', true); //the object is killed when out of the boundaries
    greenEnemies.setAll('checkWorldBounds', true); // it checks every time if it's out of the bounds

    greenEnemies.forEach(function(enemy) {
        enemy.body.setSize(enemy.width * 3 / 4, enemy.height * 3 / 4);
        enemy.events.onKilled.add(killEnemy);
    });

    (function launchGreenEnemy() {
        var MIN_ENEMY_SPACING = 1000 / FACTOR_DIFFICULTY, //TODO: can work with difficulty
            MAX_ENEMY_SPACING = 3000 / FACTOR_DIFFICULTY, //TODO: can work with difficulty
            ENEMY_SPEED = 100 * FACTOR_DIFFICULTY, //TODO: can work with difficulty
            enemy = greenEnemies.getFirstExists(false);
        if (enemy) {
            enemy.reset(game.rnd.integerInRange(+100, game.width - 100), 0); //The Reset component allows a Game Object to be reset
            //and repositioned to a new location.
            enemy.body.velocity.x = 0;
            enemy.body.velocity.y = ENEMY_SPEED;
            enemy.body.drag.x = 100;

            //  Send another enemy soon
            enemyLaunchTimer = game.time.events.add(game.rnd.integerInRange(MIN_ENEMY_SPACING, MAX_ENEMY_SPACING), launchGreenEnemy);
        }
    })();
}

function update() {
    //  Reset the player, then check for movement keys
    player.body.velocity.setTo(0, 0);
    //player.body.acceleration.x = 0;
    playerHead.body.velocity.setTo(0, 0);
    //playerHead.body.acceleration.x = 0;

    /*//  Move player towards MOUSE pointer
     if (game.input.x < game.width - 1 &&
     game.input.x > 1 &&
     game.input.y > 1 &&
     game.input.y < game.height - 1) {
     var minDist = 100;
     var dist = game.input.x - player.x;
     player.body.velocity.x = MAX_SPEED * game.math.clamp(dist / minDist, -1, 1);
     }*/
    //  Update function for each enemy player to update rotation etc

    //  Check collisions
    game.physics.arcade.overlap(player, greenEnemies, playerCollide, null, this);
    game.physics.arcade.overlap(greenEnemies, bullets, hitEnemy, null, this);
    game.physics.arcade.overlap(barborder, greenEnemies, barCollide, null, this);

    function fireBullet() {
        //Variant I
        //  Grab the first bullet we can from the pool
        /*var bullet = bullets.getFirstExists(false);

         if (bullet) {
         bullet.reset(player.x, player.y); //The Reset component allows a Game Object to be reset and repositioned to a new location.
         bullet.body.velocity.y = -500;

         //  Make bullet come out of tip of player with right angle
         var bulletOffset = 20 * Math.sin(game.math.degToRad(player.angle));
         bullet.reset(player.x + bulletOffset, player.y);
         bullet.angle = player.angle;
         game.physics.arcade.velocityFromAngle(bullet.angle - 90, BULLET_SPEED, bullet.body.velocity);
         bullet.body.velocity.x += player.body.velocity.x;*/

        //Variant II
        //  To avoid them being allowed to fire too fast we set a time limit
        if (game.time.now > bulletTimer) {
            var BULLET_SPEED = 400,
                BULLET_SPACING = 450,
                bullet = bullets.getFirstExists(false);

            if (bullet) {
                bullet.reset(player.x, player.y); //The Reset component allows a Game Object to be reset and repositioned to a new location.
                bullet.body.velocity.y = -500;

                bulletTimer = game.time.now + BULLET_SPACING;
            }
        }
    }

    if (cursors.left.isDown) {
        player.body.velocity.x = -MAX_SPEED; //without smootness of movement
        //player.body.acceleration.x = -ACCLERATION; //with up
        playerHead.body.velocity.x = -MAX_SPEED;
    } else if (cursors.right.isDown) {
        player.body.velocity.x = MAX_SPEED; //without smootness of movement
        //player.body.acceleration.x = ACCLERATION;
        playerHead.body.velocity.x = MAX_SPEED;
    }

    if (player.alive && (fireButton.isDown || game.input.activePointer.isDown)) {
        fireBullet();
    }

    //  Stop at screen edges
    if (player.x > game.width - 50) {
        player.x = game.width - 50;
        playerHead.x = player.x - 3;
        //player.body.acceleration.x = 0;//with smootness of movement
    }
    if (player.x < 50) {
        player.x = 50;
        playerHead.x = player.x - 3;
        //player.body.acceleration.x = 0;//with smootness of movement
    }
}

function render() {

}

function playerCollide(player, enemy) {
    hearts.callAll('kill');
    player.kill();
}

function barCollide(bar, enemy) {
    enemy.kill();
    hearts.children.pop().kill();

    livesCount -= 1;
    if (livesCount <= 0) {
        player.kill();
    }
}

function hitEnemy(enemy, bullet) {
    enemy.kill();
    bullet.kill();

    score += 10;
    scoreText.text = 'Score: ' + score;
}

function togglePause() {
    game.physics.arcade.isPaused = (game.physics.arcade.isPaused) ? false : true;
    if (game.physics.arcade.isPaused) {
        pauseImage = game.add.sprite(250, 100, 'paused');
    } else {
        pauseImage.destroy();
    }
}

function endGame() {
    gameOverText.visible = true;
    greenEnemies.callAll('kill');
    playerHead.kill();
    game.time.events.remove(enemyLaunchTimer);
}

function killEnemy(enemy) {
    var explosion = explosions.getFirstExists(false);
    explosion.reset(enemy.body.x + enemy.body.halfWidth, enemy.body.y + enemy.body.halfHeight);
    explosion.body.velocity.y = enemy.body.velocity.y;
    explosion.alpha = 0.7;
    explosion.play('explosion', EXPLOSION_SPEED, false, true);
}<commit_msg>Adding restart logic<commit_after>const game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-demo', {
    preload,
    create,
    update,
    render
});

var player,
    playerHead,

    bar,
    barborder,

    cursors,
    score = 0,
    scoreText,

    bullets,
    bulletTimer = 0,

    fireButton,
    explosions,
    greenEnemies,
    enemyLaunchTimer,

    pauseKey,
    pauseImage,

    hearts,
    livesCount = 3,

    gameOverMessage = 'GAME OVER!',
    gameOverText;

const PLAYER_STARTING_POSITION_X = 400,
    PLAYER_STARTING_POSITION_Y = 404,

    PLAYER_HEAD_STARTING_POSITION_X = 396,
    PLAYER_HEAD_STARTING_POSITION_Y = 360,

    BAR_BORDER_POSITION_X = 0,
    BAR_BORDER_POSITION_Y = 470,

    ACCLERATION = 300,
    DRAG = 400,
    MAX_SPEED = 400,
    EXPLOSION_SPEED = 12,
    FACTOR_DIFFICULTY = 1; //TODO: Set with score or etc.

function preload() {
    game.load.image('bar', 'assets/images/bar.png');
    game.load.image('player', 'assets/images/Bartender_80_88_invert.png');
    game.load.image('bullet', 'assets/images/green_olive_15_19.png');
    game.load.image('enemy-green', 'assets/images/glass_80_115_rotated.png');
    game.load.spritesheet('explosion', 'assets/images/explode.png', 133, 95, 6);
    game.load.image('barborder', './assets/images/barborder.png');
    game.load.image('playerhead', './assets/images/playerhead.png');
    game.load.image('paused', './assets/images/paused.png');
    game.load.image('heart', './assets/images/heart.png');
}

function create() {
    //Setting Arcade Physics system for all objects in the game
    game.physics.startSystem(Phaser.Physics.ARCADE);

    bar = game.add.tileSprite(0, 0, 800, 600, 'bar');
    barborder = game.add.sprite(BAR_BORDER_POSITION_X, BAR_BORDER_POSITION_Y, 'barborder');
    game.physics.enable(barborder, Phaser.Physics.ARCADE);
    barborder.body.immovable = true;
    //barborder.alpha = 0; // uncomment if you want the red line to disappear

    gameOverText = game.add.text(game.world.centerX, game.world.centerY, gameOverMessage, { font: '84px Arial', fill: '#fff' });
    gameOverText.anchor.setTo(0.5, 0.5);
    gameOverText.visible = false;

    scoreText = game.add.text(600, 550, 'score: 0', { fontSize: '32px', fill: '#F00' });

    pauseKey = this.input.keyboard.addKey(Phaser.Keyboard.P);
    pauseKey.onDown.add(togglePause, this);

    //Hearts group
    hearts = game.add.group();
    addHearts();

    //  Our bullet group
    bullets = game.add.group();
    bullets.enableBody = true;
    bullets.physicsBodyType = Phaser.Physics.ARCADE;
    bullets.createMultiple(10, 'bullet');
    bullets.setAll('anchor.x', 0.5);
    bullets.setAll('anchor.y', 1);
    bullets.setAll('outOfBoundsKill', true);
    bullets.setAll('checkWorldBounds', true);

    //  The hero!
    player = game.add.sprite(PLAYER_STARTING_POSITION_X, PLAYER_STARTING_POSITION_Y, 'player');
    player.anchor.setTo(0.5, 0.5);
    player.events.onKilled.add(endGame);

    game.physics.enable(player, Phaser.Physics.ARCADE);
    cursors = game.input.keyboard.createCursorKeys();
    fireButton = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);

    player.body.maxVelocity.setTo(MAX_SPEED, MAX_SPEED);
    //player.body.drag.setTo(DRAG, DRAG);

    // Setting the player head.
    playerHead = game.add.sprite(PLAYER_HEAD_STARTING_POSITION_X, PLAYER_HEAD_STARTING_POSITION_Y, 'playerhead');
    game.physics.enable(playerHead, Phaser.Physics.ARCADE);
    //playerHead.alpha = 0; // uncomment if you want the red line to disappear

    /*//  Add an emitter for the player's trail
     playerTrail = game.add.emitter(player.x, player.y + 10, 400);
     playerTrail.width = 10;
     playerTrail.makeParticles('bullet');
     playerTrail.setXSpeed(30, -30);
     playerTrail.setYSpeed(200, 180);
     playerTrail.setRotation(50, -50);
     playerTrail.setAlpha(1, 0.01, 800);
     playerTrail.setScale(0.05, 0.4, 0.05, 0.4, 2000, Phaser.Easing.Quintic.Out);
     playerTrail.start(false, 5000, 10);*/

    //  An explosion pool
    explosions = game.add.group();
    explosions.enableBody = true;
    explosions.physicsBodyType = Phaser.Physics.ARCADE;
    explosions.createMultiple(30, 'explosion');
    explosions.setAll('anchor.x', 0.5);
    explosions.setAll('anchor.y', 0.5);
    explosions.forEach(function(explosion) {
        explosion.animations.add('explosion');
    });

    //  The baddies!
    greenEnemies = game.add.group();
    greenEnemies.enableBody = true;
    greenEnemies.physicsBodyType = Phaser.Physics.ARCADE;
    greenEnemies.createMultiple(5 * FACTOR_DIFFICULTY, 'enemy-green'); //TODO: can add factor to number of enemies in dependence to difficutly level
    greenEnemies.setAll('anchor.x', 0.5); //places the anchor in the exact middle of the sprite, horizontally and vertically.
    greenEnemies.setAll('anchor.y', 0.5); //places the anchor in the exact middle of the sprite, horizontally and vertically.
    greenEnemies.setAll('scale.x', 0.5);
    greenEnemies.setAll('scale.y', 0.5);
    greenEnemies.setAll('angle', 180);
    greenEnemies.setAll('outOfBoundsKill', true); //the object is killed when out of the boundaries
    greenEnemies.setAll('checkWorldBounds', true); // it checks every time if it's out of the bounds

    greenEnemies.forEach(function(enemy) {
        enemy.body.setSize(enemy.width * 3 / 4, enemy.height * 3 / 4);
        enemy.events.onKilled.add(killEnemy);
    });

    launchGreenEnemy();
}

function update() {
    //  Reset the player, then check for movement keys
    player.body.velocity.setTo(0, 0);
    //player.body.acceleration.x = 0;
    playerHead.body.velocity.setTo(0, 0);
    //playerHead.body.acceleration.x = 0;

    /*//  Move player towards MOUSE pointer
     if (game.input.x < game.width - 1 &&
     game.input.x > 1 &&
     game.input.y > 1 &&
     game.input.y < game.height - 1) {
     var minDist = 100;
     var dist = game.input.x - player.x;
     player.body.velocity.x = MAX_SPEED * game.math.clamp(dist / minDist, -1, 1);
     }*/
    //  Update function for each enemy player to update rotation etc

    //  Check collisions
    game.physics.arcade.overlap(playerHead, greenEnemies, playerCollide, null, this);
    game.physics.arcade.overlap(greenEnemies, bullets, hitEnemy, null, this);
    game.physics.arcade.overlap(barborder, greenEnemies, barCollide, null, this);

    function fireBullet() {
        //Variant I
        //  Grab the first bullet we can from the pool
        /*var bullet = bullets.getFirstExists(false);

         if (bullet) {
         bullet.reset(player.x, player.y); //The Reset component allows a Game Object to be reset and repositioned to a new location.
         bullet.body.velocity.y = -500;

         //  Make bullet come out of tip of player with right angle
         var bulletOffset = 20 * Math.sin(game.math.degToRad(player.angle));
         bullet.reset(player.x + bulletOffset, player.y);
         bullet.angle = player.angle;
         game.physics.arcade.velocityFromAngle(bullet.angle - 90, BULLET_SPEED, bullet.body.velocity);
         bullet.body.velocity.x += player.body.velocity.x;*/

        //Variant II
        //  To avoid them being allowed to fire too fast we set a time limit
        if (game.time.now > bulletTimer) {
            var BULLET_SPEED = 400,
                BULLET_SPACING = 450,
                bullet = bullets.getFirstExists(false);

            if (bullet) {
                bullet.reset(player.x, player.y); //The Reset component allows a Game Object to be reset and repositioned to a new location.
                bullet.body.velocity.y = -500;

                bulletTimer = game.time.now + BULLET_SPACING;
            }
        }
    }

    if (cursors.left.isDown) {
        player.body.velocity.x = -MAX_SPEED; //without smootness of movement
        //player.body.acceleration.x = -ACCLERATION; //with up
        playerHead.body.velocity.x = -MAX_SPEED;
    } else if (cursors.right.isDown) {
        player.body.velocity.x = MAX_SPEED; //without smootness of movement
        //player.body.acceleration.x = ACCLERATION;
        playerHead.body.velocity.x = MAX_SPEED;
    }

    if (player.alive && (fireButton.isDown || game.input.activePointer.isDown)) {
        fireBullet();
    }

    //  Stop at screen edges
    if (player.x > game.width - 50) {
        player.x = game.width - 50;
        playerHead.x = player.x - 3;
        //player.body.acceleration.x = 0;//with smootness of movement
    }
    if (player.x < 50) {
        player.x = 50;
        playerHead.x = player.x - 3;
        //player.body.acceleration.x = 0;//with smootness of movement
    }
}

function render() {

}

function playerCollide(playerHead, enemy) {
    hearts.callAll('kill');
    player.kill();
}

function barCollide(bar, enemy) {
    enemy.kill();
    hearts.children.pop().kill();

    livesCount -= 1;
    if (livesCount <= 0) {
        player.kill();
    }
}

function hitEnemy(enemy, bullet) {
    enemy.kill();
    bullet.kill();

    score += 10;
    scoreText.text = 'Score: ' + score;
}

function killEnemy(enemy) {
    var explosion = explosions.getFirstExists(false);
    explosion.reset(enemy.body.x + enemy.body.halfWidth, enemy.body.y + enemy.body.halfHeight);
    explosion.body.velocity.y = enemy.body.velocity.y;
    explosion.alpha = 0.7;
    explosion.play('explosion', EXPLOSION_SPEED, false, true);
}

function launchGreenEnemy() {
    var MIN_ENEMY_SPACING = 1000 / FACTOR_DIFFICULTY, //TODO: can work with difficulty
        MAX_ENEMY_SPACING = 3000 / FACTOR_DIFFICULTY, //TODO: can work with difficulty
        ENEMY_SPEED = 100 * FACTOR_DIFFICULTY, //TODO: can work with difficulty
        enemy = greenEnemies.getFirstExists(false);

    if (enemy) {
        enemy.reset(game.rnd.integerInRange(+100, game.width - 100), 0); //The Reset component allows a Game Object to be reset
        //and repositioned to a new location.
        enemy.body.velocity.x = 0;
        enemy.body.velocity.y = ENEMY_SPEED;
        enemy.body.drag.x = 100;

        //  Send another enemy soon
        enemyLaunchTimer = game.time.events.add(game.rnd.integerInRange(MIN_ENEMY_SPACING, MAX_ENEMY_SPACING), launchGreenEnemy);
    }
}

function addHearts() {
    for (var i = 0; i < livesCount; i += 1) {
        hearts.create(5 + i * 33, 560, 'heart');
    }
}

function togglePause() {
    if (!player.isAlive) {
        return;
    }

    game.physics.arcade.isPaused = (game.physics.arcade.isPaused) ? false : true;
    if (game.physics.arcade.isPaused) {
        pauseImage = game.add.sprite(250, 100, 'paused');
    } else {
        pauseImage.destroy();
    }
}

function endGame() {
    gameOverText.visible = true;
    playerHead.kill();
    greenEnemies.callAll('kill');
    game.time.events.remove(enemyLaunchTimer);

    tapRestart = game.input.onTap.addOnce(restart, this);
    spaceRestart = fireButton.onDown.addOnce(restart, this);
}

function restart() {
    gameOverText.visible = false;

    launchGreenEnemy();
    player.revive();
    playerHead.revive();

    score = 0;
    scoreText.text = 'Score: 0';

    livesCount = 3;
    addHearts();
}<|endoftext|>


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

it('should return the name a OS', function () {
	assert(osName().length > 0);
	assert.strictEqual(osName('darwin', '14.0.0'), 'OS X Yosemite');
	assert.strictEqual(osName('linux', '3.13.0-24-generic'), 'Linux 3.13');
	assert.strictEqual(osName('win32', '5.1.2600'), 'Windows XP');
	assert.strictEqual(osName('win32'), 'Windows');
});
<commit_msg>fix test require<commit_after>'use strict';
var assert = require('assert');
var osName = require('./');

it('should return the name a OS', function () {
	assert(osName().length > 0);
	assert.strictEqual(osName('darwin', '14.0.0'), 'OS X Yosemite');
	assert.strictEqual(osName('linux', '3.13.0-24-generic'), 'Linux 3.13');
	assert.strictEqual(osName('win32', '5.1.2600'), 'Windows XP');
	assert.strictEqual(osName('win32'), 'Windows');
});
<|endoftext|>


<commit_before>/*global window: false */
/*jslint browser: true */
function loadScript(src, callback)
{
  var s,
      r,
      t;
  r = false;
  s = document.createElement('script');
  s.type = 'text/javascript';
  s.src = src;
  s.onload = s.onreadystatechange = function() {
    //console.log( this.readyState ); //uncomment this line to see which ready states are called.
    if ( !r && (!this.readyState || this.readyState == 'complete') )
    {
      r = true;
      callback();
    }
  };
  t = document.getElementsByTagName('script')[0];
  t.parentNode.insertBefore(s, t);
}

(function(Videos) {
"use strict";
  var dom;
  var successMsgs = ['Good job.', 'Nice work.', 'Good eye.', 'Well done.', 'Nicely done.'];
  var pauseMsgs = ['Looks fine there.', 'Seems ok.', 'All clear there.', 'Just splashing around.'];
  var player;
  var gameState;

  function init() {

    loadScript('http://code.jquery.com/jquery-1.11.3.min.js', function() {
      loadScript('observable.min.js', function() {
        wireDom();
        youtubeInit(onPlayerReady, onPlayerStateChange);

        loadScript('share.min.js', function() {
          new Share('.share', {
            title: 'Spot The Drowning Child',
            description: 'Can you spot the drowning child in this crowded wave pool?',
            url: 'http://spotthedrowningchild.com',
            ui: { button_text: '', flyout: 'top left'}
          });
          $('.status .share label').on('click', function() {
            amplitude.logEvent("video share clicked");
          });
        });
      });
    });
  }
  init();

  function onPlayerReady(event) {
    setupGame(gameState);
  }

  function youtubeInit(onPlayerReady, onPlayerStateChange) {
    Videos.getYoutubePlayer().then(
      function(player_gameState) {
        player = player_gameState[0];
        gameState = player_gameState[1];
        player.addEventListener('onStateChange', onPlayerStateChange);
        onPlayerReady();
      },
      function(error_event) {
        dom.showStatus('Sorry, there was an error playing this video, refresh to try again.');
        amplitude.logEvent("video error", {'error_data': error_event.data});
      }
    );
  }

  function wireDom() {
    dom = {
      findBox: $('#box'),
      statusBox: $('.status'),
      statusText: $('#status'),
      playAgain: $('.play-again'),
      tryAgain: $('.try-again'),
      statusLink: $('.statuslink'),
      scoreBox: $('#scorebox'),
      cursorLooks: $('.cursor-look'),
      cursorDot: $('#cursor-dot'),
      article: $('#article'),
      showStatus: function showStatus(text) {
        this.statusText.text(text);
      },
      showTime: function showTime(time) {
        var timeStr = time.toPrecision(2);
        if (time > 0) {
          timeStr = '+'+timeStr;
        } else {
          this.scoreBox.addClass('win-hue');
        }
        timeStr += 's';
        this.scoreBox.text(timeStr);
      },
      showPlayAgain: function showPlayAgain() {
        this.playAgain.show();
        this.statusLink.attr('style', '-webkit-animation: fadein 4s; animation: fadein 4s; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards;');

        this.playAgain.on('click', function() {
          amplitude.logEvent("video playagain clicked");
        });
      },
      showTryAgain: function showTryAgain() {
        this.tryAgain.attr('href', '#');
        this.tryAgain.show();
        this.statusLink.attr('style', '-webkit-animation: fadein 4s; animation: fadein 4s; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards;');

        this.tryAgain.on('click', function() {
          reset();
          amplitude.logEvent("video replay clicked");
        });
      },
      showCursorDot: function showCursorDot(x, y, win) {
        var positionStyle = 'display: block; position: absolute; top:'+(y-5)+'px;left:'+(x-5)+'px;';
        this.cursorDot.attr('style', positionStyle+'-webkit-animation: cursor-throb 1s infinite ease; animation: cursor-throb 1s infinite ease;');
        if (win) {
          this.cursorDot.addClass('win-hue');
          this.cursorDot.attr('style', positionStyle+'-webkit-animation: fadeout 10s; animation: fadeout 10s; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards;');
        }
      },
      hideCursorDot: function hideCursorDot() {
        this.cursorDot.attr('style', 'display: none;');
      },
      isMobile: function isMobile() {
        return navigator.userAgent.match(/(iPod|iPhone|iPad)/);
      }
    };

    dom.findBox.click(function(e) {
      if (gameState.status() === 'drowning' || gameState.status() === 'spotted') {
        dom.showCursorDot(e.pageX, e.pageY, true);
        success();
        dom.findBox.attr('style', 'display: none;');
      }
    });

    dom.cursorLooks.click(function(e) {
      if (player.getPlayerState() === YT.PlayerState.PAUSED) {
        player.playVideo();
      } else if (player.getPlayerState() === YT.PlayerState.PLAYING) {
        var status = gameState.status();
        if (status === 'drowning' || status === 'ok' || status === 'spotted') {
          if (!gameState.winTime) {
            dom.showCursorDot(e.pageX, e.pageY);
          }
        }
        player.pauseVideo();
      }
      ga('send', 'event', gameState.videoId, 'click', 'video clicked', {'dimension1': gameState.videoId});
    });

    dom.cursorDot.click(function() {
      player.playVideo();
    });
  }

  function setupGame(gameState) {
    gameState.status = observable();
    gameState.status('ok');
    gameState.pauseCount = 0;
    gameState.ongoingPlayStatus = 'Spot the drowning child.';
    dom.findBox.attr('style', gameState.findBoxStyle);
    player.playVideo();

    ga('set', 'dimension1', gameState.videoId);
    ga('send', 'event', 'game', 'setup', gameState.videoId);
    amplitude.setUserProperties({videoId: gameState.videoId});
    amplitude.logEvent("game setup");

    gameState.status(function(newStatus) {
      if (newStatus === 'drowning') {
        dom.findBox.attr('style', 'display: block;' + gameState.findBoxStyle);
        setTimeout(function() {
          if (!gameState.winTime) {
            gameState.ongoingPlayStatus = 'Spot the drowning child.';
            dom.showStatus(gameState.ongoingPlayStatus);
          }
        }, (gameState.whistleSecs - gameState.drowningStartSecs) * Math.random() * 1000);
      } else if (newStatus === 'saved') {
        if (gameState.frameRefresh) {
          clearInterval(gameState.frameRefresh);
        }
        if (!gameState.winTime) {
          // Just show the play again link, player can't click anymore.
          dom.showStatus('Try again. Click the video to help the lifeguard.');
          amplitude.logEvent("game over", {'pauses': gameState.pauseCount});
        }
      } else if (newStatus === 'spotted') {
        if (!gameState.winTime) {
          gameState.ongoingPlayStatus = 'Spot the drowning child.';
          dom.showStatus(gameState.ongoingPlayStatus);
        }
        end();
      }
    });

    if (gameState.frameRefresh)
      clearInterval(gameState.frameRefresh);
    gameState.frameRefresh = setInterval(function gameFrame() {
      if (!player || !player.getCurrentTime || player.getPlayerState() !== YT.PlayerState.PLAYING)
          return;
      var time = player.getCurrentTime();
      // State transitions: ok -> drowning -> spotted -> saved
      if (time > gameState.swimmerSavedSecs && gameState.status() === 'spotted') {
          gameState.status('saved');
      } else if (time > gameState.whistleSecs && gameState.status() === 'drowning') {
          gameState.status('spotted');
      } else if (time > gameState.drowningStartSecs && gameState.status() === 'ok') {
          gameState.status('drowning');
      }
    }, 100);
  }

  function reset() {
    dom.article.hide();
    player.setPlaybackRate(1);
    player.seekTo(0);
    dom.scoreBox.removeClass('win-hue'); // Dim previous win time.
    dom.cursorDot.removeClass('win-hue');
    dom.statusBox.removeClass('end');
    gameState.winTime = undefined;
    gameState.pauseCount = 0;
    gameState.ended = false;
    Article.getDom(dom).then(function(dom) {
      dom.winInfoBox.setAttribute('style', 'display: none;');
    });
    setupGame(gameState);

  }

  function success() {
    gameState.winTime = player.getCurrentTime();
    ga('send', 'event', 'game', 'success', gameState.videoId);
    ga('send', 'event', gameState.videoId, 'win', 'game time', gameState.winTime);
    amplitude.logEvent("drowner spotted", {'time': gameState.winTime, 'pauses': gameState.pauseCount});

    var status = gameState.status();
    gameState.status('spotted');
    if (!dom.isMobile()) {
      if (status === 'drowning') {
        player.seekTo(gameState.whistleSecs);
      }
      player.setPlaybackRate(2);
      player.playVideo();
    } else {
      setTimeout(function() {
        if (status === 'drowning') {
          player.seekTo(gameState.whistleSecs);
        }
        player.playVideo();
      }, 1000);
    }

    var time = gameState.winTime - gameState.whistleSecs;
    var msg = pickRandom(successMsgs);
    dom.showStatus(msg);
    dom.showTime(time);
    if (time <= 0) {
      ga('send', 'event', 'game', 'predicted', gameState.videoId);
    }
    dom.article.show();
    loadScript('article.js', function() {
      Article.getDom(dom).then(function(dom) {
        amplitude.logEvent("shown wininfo");
        dom.showWinInfo(time < 0);
      });
    });
  }

  function end() {
    if (gameState.ended)
      return;
    gameState.ended = true;
    function showPlayAgain() { dom.showPlayAgain(); }
    function showTryAgain() { dom.showTryAgain(); }
    ga('send', 'event', 'game', 'end', gameState.videoId);
    dom.statusBox.addClass('end');
    dom.article.show();
    loadScript('article.js', function() {
      Article.getDom(dom).then(function(dom) {
        amplitude.logEvent("shown info");
        showPlayAgain();
        showTryAgain();
        dom.showInfo();
      });
    });
  }

  // 4. The API will call this function when the video player is ready.

  function onPlayerStateChange(event) {
    var status = gameState.status();
    if (event.data === YT.PlayerState.ENDED) {
      end();
    } else if (event.data === YT.PlayerState.PAUSED) {
      gameState.pauseCount += 1;
      ga('send', 'event', 'game', 'paused', gameState.videoId, gameState.pauseCount);
      dom.cursorLooks.hide();
      if (status === 'drowning' || status === 'ok') {
        if (!dom.isMobile() || gameState.pauseCount > 1) {
          var pauseMsg = pickRandom(pauseMsgs);
          dom.showStatus(pauseMsg + ' Keep looking.');
        }
      } else if (status === 'spotted' || status === 'saved') {
        end();
      }
    } else if (event.data === YT.PlayerState.PLAYING) {
      ga('send', 'event', 'game', 'played', gameState.videoId);
      if (!dom.isMobile())
        dom.cursorLooks.show();
      if (status === 'drowning' || status === 'ok') {
        dom.hideCursorDot();
        if (!gameState.winTime) {
          dom.showStatus(gameState.ongoingPlayStatus);
        }
      }
    }
  }

  function pickRandom(items) {
    return items[Math.floor(Math.random()*items.length)];
  }
})(window.Videos);
<commit_msg>Add replay counter.<commit_after>/*global window: false */
/*jslint browser: true */
function loadScript(src, callback)
{
  var s,
      r,
      t;
  r = false;
  s = document.createElement('script');
  s.type = 'text/javascript';
  s.src = src;
  s.onload = s.onreadystatechange = function() {
    //console.log( this.readyState ); //uncomment this line to see which ready states are called.
    if ( !r && (!this.readyState || this.readyState == 'complete') )
    {
      r = true;
      callback();
    }
  };
  t = document.getElementsByTagName('script')[0];
  t.parentNode.insertBefore(s, t);
}

(function(Videos) {
"use strict";
  var dom;
  var successMsgs = ['Good job.', 'Nice work.', 'Good eye.', 'Well done.', 'Nicely done.'];
  var pauseMsgs = ['Looks fine there.', 'Seems ok.', 'All clear there.', 'Just splashing around.'];
  var player;
  var gameState;

  function init() {

    loadScript('http://code.jquery.com/jquery-1.11.3.min.js', function() {
      loadScript('observable.min.js', function() {
        wireDom();
        youtubeInit(onPlayerReady, onPlayerStateChange);

        loadScript('share.min.js', function() {
          new Share('.share', {
            title: 'Spot The Drowning Child',
            description: 'Can you spot the drowning child in this crowded wave pool?',
            url: 'http://spotthedrowningchild.com',
            ui: { button_text: '', flyout: 'top left'}
          });
          $('.status .share label').on('click', function() {
            amplitude.logEvent("video share clicked", {'replays': gameState.replays});
          });
        });
      });
    });
  }
  init();

  function onPlayerReady(event) {
    setupGame(gameState);
  }

  function youtubeInit(onPlayerReady, onPlayerStateChange) {
    Videos.getYoutubePlayer().then(
      function(player_gameState) {
        player = player_gameState[0];
        gameState = player_gameState[1];
        player.addEventListener('onStateChange', onPlayerStateChange);
        onPlayerReady();
      },
      function(error_event) {
        dom.showStatus('Sorry, there was an error playing this video, refresh to try again.');
        amplitude.logEvent("video error", {'error_data': error_event.data});
      }
    );
  }

  function wireDom() {
    dom = {
      findBox: $('#box'),
      statusBox: $('.status'),
      statusText: $('#status'),
      playAgain: $('.play-again'),
      tryAgain: $('.try-again'),
      statusLink: $('.statuslink'),
      scoreBox: $('#scorebox'),
      cursorLooks: $('.cursor-look'),
      cursorDot: $('#cursor-dot'),
      article: $('#article'),
      showStatus: function showStatus(text) {
        this.statusText.text(text);
      },
      showTime: function showTime(time) {
        var timeStr = time.toPrecision(2);
        if (time > 0) {
          timeStr = '+'+timeStr;
        } else {
          this.scoreBox.addClass('win-hue');
        }
        timeStr += 's';
        this.scoreBox.text(timeStr);
      },
      showPlayAgain: function showPlayAgain() {
        this.playAgain.show();
        this.statusLink.attr('style', '-webkit-animation: fadein 4s; animation: fadein 4s; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards;');

        this.playAgain.on('click', function() {
          amplitude.logEvent("video playagain clicked", {'replays': gameState.replays});
        });
      },
      showTryAgain: function showTryAgain() {
        this.tryAgain.attr('href', '#');
        this.tryAgain.show();
        this.statusLink.attr('style', '-webkit-animation: fadein 4s; animation: fadein 4s; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards;');

        this.tryAgain.on('click', function() {
          reset();
          amplitude.logEvent("video replay clicked", {'replays': gameState.replays});
        });
      },
      showCursorDot: function showCursorDot(x, y, win) {
        var positionStyle = 'display: block; position: absolute; top:'+(y-5)+'px;left:'+(x-5)+'px;';
        this.cursorDot.attr('style', positionStyle+'-webkit-animation: cursor-throb 1s infinite ease; animation: cursor-throb 1s infinite ease;');
        if (win) {
          this.cursorDot.addClass('win-hue');
          this.cursorDot.attr('style', positionStyle+'-webkit-animation: fadeout 10s; animation: fadeout 10s; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards;');
        }
      },
      hideCursorDot: function hideCursorDot() {
        this.cursorDot.attr('style', 'display: none;');
      },
      isMobile: function isMobile() {
        return navigator.userAgent.match(/(iPod|iPhone|iPad)/);
      }
    };

    dom.findBox.click(function(e) {
      if (gameState.status() === 'drowning' || gameState.status() === 'spotted') {
        dom.showCursorDot(e.pageX, e.pageY, true);
        success();
        dom.findBox.attr('style', 'display: none;');
      }
    });

    dom.cursorLooks.click(function(e) {
      if (player.getPlayerState() === YT.PlayerState.PAUSED) {
        player.playVideo();
      } else if (player.getPlayerState() === YT.PlayerState.PLAYING) {
        var status = gameState.status();
        if (status === 'drowning' || status === 'ok' || status === 'spotted') {
          if (!gameState.winTime) {
            dom.showCursorDot(e.pageX, e.pageY);
          }
        }
        player.pauseVideo();
      }
      ga('send', 'event', gameState.videoId, 'click', 'video clicked', {'dimension1': gameState.videoId});
    });

    dom.cursorDot.click(function() {
      player.playVideo();
    });
  }

  function setupGame(gameState) {
    gameState.status = observable();
    gameState.status('ok');
    gameState.pauseCount = 0;
    gameState.ongoingPlayStatus = 'Spot the drowning child.';
    dom.findBox.attr('style', gameState.findBoxStyle);
    player.playVideo();

    ga('set', 'dimension1', gameState.videoId);
    ga('send', 'event', 'game', 'setup', gameState.videoId);
    amplitude.setUserProperties({videoId: gameState.videoId});
    amplitude.logEvent("game setup", {'replays': gameState.replays});

    gameState.status(function(newStatus) {
      if (newStatus === 'drowning') {
        dom.findBox.attr('style', 'display: block;' + gameState.findBoxStyle);
        setTimeout(function() {
          if (!gameState.winTime) {
            gameState.ongoingPlayStatus = 'Spot the drowning child.';
            dom.showStatus(gameState.ongoingPlayStatus);
          }
        }, (gameState.whistleSecs - gameState.drowningStartSecs) * Math.random() * 1000);
      } else if (newStatus === 'saved') {
        if (gameState.frameRefresh) {
          clearInterval(gameState.frameRefresh);
        }
        if (!gameState.winTime) {
          // Just show the play again link, player can't click anymore.
          dom.showStatus('Try again. Click the video to help the lifeguard.');
          amplitude.logEvent("game over", {'pauses': gameState.pauseCount, 'replays': gameState.replays});
        }
      } else if (newStatus === 'spotted') {
        if (!gameState.winTime) {
          gameState.ongoingPlayStatus = 'Spot the drowning child.';
          dom.showStatus(gameState.ongoingPlayStatus);
        }
        end();
      }
    });

    if (gameState.frameRefresh)
      clearInterval(gameState.frameRefresh);
    gameState.frameRefresh = setInterval(function gameFrame() {
      if (!player || !player.getCurrentTime || player.getPlayerState() !== YT.PlayerState.PLAYING)
          return;
      var time = player.getCurrentTime();
      // State transitions: ok -> drowning -> spotted -> saved
      if (time > gameState.swimmerSavedSecs && gameState.status() === 'spotted') {
          gameState.status('saved');
      } else if (time > gameState.whistleSecs && gameState.status() === 'drowning') {
          gameState.status('spotted');
      } else if (time > gameState.drowningStartSecs && gameState.status() === 'ok') {
          gameState.status('drowning');
      }
    }, 100);
  }

  function reset() {
    dom.article.hide();
    player.setPlaybackRate(1);
    player.seekTo(0);
    dom.scoreBox.removeClass('win-hue'); // Dim previous win time.
    dom.cursorDot.removeClass('win-hue');
    dom.statusBox.removeClass('end');
    gameState.winTime = undefined;
    gameState.pauseCount = 0;
    gameState.ended = false;
    if (gameState.replays === undefined)
      gameState.replays = 0;
    gameState.replays += 1;
    Article.getDom(dom).then(function(dom) {
      dom.winInfoBox.setAttribute('style', 'display: none;');
    });
    setupGame(gameState);

  }

  function success() {
    gameState.winTime = player.getCurrentTime();
    ga('send', 'event', 'game', 'success', gameState.videoId);
    ga('send', 'event', gameState.videoId, 'win', 'game time', gameState.winTime);
    amplitude.logEvent("drowner spotted", {'time': gameState.winTime, 'pauses': gameState.pauseCount, 'replays': gameState.replays});

    var status = gameState.status();
    gameState.status('spotted');
    if (!dom.isMobile()) {
      if (status === 'drowning') {
        player.seekTo(gameState.whistleSecs);
      }
      player.setPlaybackRate(2);
      player.playVideo();
    } else {
      setTimeout(function() {
        if (status === 'drowning') {
          player.seekTo(gameState.whistleSecs);
        }
        player.playVideo();
      }, 1000);
    }

    var time = gameState.winTime - gameState.whistleSecs;
    var msg = pickRandom(successMsgs);
    dom.showStatus(msg);
    dom.showTime(time);
    if (time <= 0) {
      ga('send', 'event', 'game', 'predicted', gameState.videoId);
    }
    dom.article.show();
    loadScript('article.js', function() {
      Article.getDom(dom).then(function(dom) {
        amplitude.logEvent("shown wininfo", {'replays': gameState.replays});
        dom.showWinInfo(time < 0);
      });
    });
  }

  function end() {
    if (gameState.ended)
      return;
    gameState.ended = true;
    function showPlayAgain() { dom.showPlayAgain(); }
    function showTryAgain() { dom.showTryAgain(); }
    ga('send', 'event', 'game', 'end', gameState.videoId);
    dom.statusBox.addClass('end');
    dom.article.show();
    loadScript('article.js', function() {
      Article.getDom(dom).then(function(dom) {
        amplitude.logEvent("shown info", {'replays': gameState.replays});
        showPlayAgain();
        showTryAgain();
        dom.showInfo();
      });
    });
  }

  // 4. The API will call this function when the video player is ready.

  function onPlayerStateChange(event) {
    var status = gameState.status();
    if (event.data === YT.PlayerState.ENDED) {
      end();
    } else if (event.data === YT.PlayerState.PAUSED) {
      gameState.pauseCount += 1;
      ga('send', 'event', 'game', 'paused', gameState.videoId, gameState.pauseCount);
      dom.cursorLooks.hide();
      if (status === 'drowning' || status === 'ok') {
        if (!dom.isMobile() || gameState.pauseCount > 1) {
          var pauseMsg = pickRandom(pauseMsgs);
          dom.showStatus(pauseMsg + ' Keep looking.');
        }
      } else if (status === 'spotted' || status === 'saved') {
        end();
      }
    } else if (event.data === YT.PlayerState.PLAYING) {
      ga('send', 'event', 'game', 'played', gameState.videoId);
      if (!dom.isMobile())
        dom.cursorLooks.show();
      if (status === 'drowning' || status === 'ok') {
        dom.hideCursorDot();
        if (!gameState.winTime) {
          dom.showStatus(gameState.ongoingPlayStatus);
        }
      }
    }
  }

  function pickRandom(items) {
    return items[Math.floor(Math.random()*items.length)];
  }
})(window.Videos);
<|endoftext|>


<commit_before>var Promise = require('lie');
var apply = require('lie-apply');
var cast = require('lie-cast');
var pocket = require('./');
var tape = require('blue-tape');

function test (description, body) {
  tape(description, function (t) {
    return body.call(t, t, pocket());
  });
}

test('.get', function (t, p) {
  p.value('a', 1);
  t.strictEqual(p.get('a'), cast(p.get('a')), '.get returns a Promise');
  return join(
    p.get('a').then(t.equal.bind(t, 1)),
    p.get('b')
     .then(t.fail.bind(t, 'Missing dep succeeded'))
     .catch(t.pass.bind(t, 'missing dep returns error Promise'))
  );
});

test('.get(name, callback)', function (t, p) {
  p.value('a', 1);
  return new Promise(function (resolve) {
    p.get('a', function (err, value) {
      t.equal(err, null);
      t.equal(1, value);
      resolve();
    });
  });
});

test('.get(name, callback) with error', function (t, p) {
  return new Promise(function (resolve) {
    p.get('a', function (err) {
      t.ok(err);
      t.equal(1, arguments.length);
      resolve();
    });
  });
});

test('.run', function (t, p) {
  p.value('something', 3);
  return p.run(function (something) {
    t.equal(something, 3);
  });
});

test('.value', function (t, p) {
  t.test('.value type checking', function (t) {
    t.throws(function () { p.value(function () {}); },
             '.value requires a name');
    t.throws(function () { p.value(5); }, '.value is picky');
    t.end();
  });

  t.test('.value takes an object', function (t) {
    return p.pocket().value({
      one: 1,
      two: 2,
      three: function (one, two) { return one + two; }
    }).run(function (one, two, three) {
      t.equal(1, one);
      t.equal(2, two);
      t.equal(3, three);
    });
  });
});

test('.wrap', function (t, p) {
  p.value('theValue', 3);
  p.value('multiplier', 2);
  p.wrap('theValue', function (original, multiplier) {
    t.equal(original, 3);
    t.equal(multiplier, 2);
    return original * multiplier;
  });
  return p.get('theValue').then(t.equal.bind(t, 6));
});

test('.wrap works on lazy values', function (t, p) {
  p.value('theValue', function () { return 8; });
  p.value('multiplier', function () { return 3; });
  p.wrap('theValue', function (original, multiplier) {
    t.equal(original, 8);
    t.equal(multiplier, 3);
    return original * multiplier;
  });
  return p.get('theValue').then(t.equal.bind(t, 24));
});

test('.wrap validates arguments', function (t, p) {
  p.value('theValue', 3);
  p.value('multiplier', 2);
  t.throws(function () {
    p.wrap('theValue', 'tortilla');
  }, 'wrapper function must be a function');

  t.throws(function () {
    p.wrap('someOtherValue', function (original) {});
  }, 'wrapper must wrap a known name');

  t.throws(function () {
    p.wrap('theValue', function () {});
  }, 'wrapper must depend on "original"');
  t.end();
});

test('.nodeValue', function (t, p) {
  p.nodeValue(function getNodeStyle (callback) {
    callback(null, 'Node Style');
  });

  return p.run(function (nodeStyle) {
    t.equals(nodeStyle, 'Node Style');
  });
});

test('.missingNames', function (t, p) {
  p.value(function thing (a, b) { });
  t.deepEquals(['a', 'b'], p.missingNames());

  var child = p.pocket();
  p.value('b', 2);
  t.deepEquals(['a'], child.missingNames());
  t.end();
});

test('value caching', function (t, p) {
  var providerExecutionCount = 0;
  var myThing = {};
  p.value(function getThing () {
    providerExecutionCount++;
    return myThing;
  });

  return apply(assertions, p.get('thing'), p.get('thing'));
  function assertions (a, b) {
    t.equal(a, b);
    t.equal(providerExecutionCount, 1);
  }
});

test('parent/child relationships', function (t, p) {
  t.test('children can get deps from parent', function (t) {
    p.value('four', 4);
    p.value(function getFive () { return 5; });

    var child = p.pocket();
    child.value(function getTwenty (four, five) { return four * five; });
    return child.get('twenty').then(t.equal.bind(t, 20));
  });

  t.test('parent cannot retrieve deps from child', function (t) {
    t.assert(!p.has('twenty'));
    t.end();
  });
});

test('granchildren can get deps from their grandparents', function (t, gp) {
  gp.value('five', function () { return 5 });
  var parent = gp.pocket();
  var child = parent.pocket();
  t.ok(child.has('five'), 'Children "have" deps that grandparents "provide"');
  return child.get('five').then(t.equal.bind(t, 5));
});

test('.alias', function (t, p) {
  return p.pocket()
    .value('src', 99)
    .alias('al', 'src')
    .get('al')
    .then(t.equal.bind(t, 99));
});

test('.default', function (t, p) {
  p.default('number', 1);
  p.default('string', function () { return 'ok'; });
  p.default('replaceMe', 'fail');
  p.value('replaceMe', 'ok');
  return join(
    p.get('number').then(t.equal.bind(t, 1)),
    p.get('string').then(t.equal.bind(t, 'ok')),
    p.get('replaceMe').then(t.equal.bind(t, 'ok'))
  );
});

test('overwrite protection', function (t, p) {
  var p1 = p.pocket();
  p1.value('one', 1);
  t.throws(function () {
    p1.value(function one () {});
  });
  var p2 = p.pocket();
  p2.value(function one () {});
  t.throws(function () {
    p1.value('one', 1);
  });

  var p3 = p.pocket();
  p3.default(function one () {});
  t.throws(function () {
    p3.default('one', 1);
  });
  t.end();
});

test('signature parsing', function (t) {
  var parse = require('./signature');
  t.throws(function () {
    parse('blah');
  }, 'Can only parse functions');
  t.end();
});

function join () {
  var args = Array.prototype.slice.call(arguments);
  return Promise.all(args);
}
<commit_msg>update .wrap tests<commit_after>var Promise = require('lie');
var apply = require('lie-apply');
var cast = require('lie-cast');
var pocket = require('./');
var tape = require('blue-tape');

function test (description, body) {
  tape(description, function (t) {
    return body.call(t, t, pocket());
  });
}

test('.get', function (t, p) {
  p.value('a', 1);
  t.strictEqual(p.get('a'), cast(p.get('a')), '.get returns a Promise');
  return join(
    p.get('a').then(t.equal.bind(t, 1)),
    p.get('b')
     .then(t.fail.bind(t, 'Missing dep succeeded'))
     .catch(t.pass.bind(t, 'missing dep returns error Promise'))
  );
});

test('.get(name, callback)', function (t, p) {
  p.value('a', 1);
  return new Promise(function (resolve) {
    p.get('a', function (err, value) {
      t.equal(err, null);
      t.equal(1, value);
      resolve();
    });
  });
});

test('.get(name, callback) with error', function (t, p) {
  return new Promise(function (resolve) {
    p.get('a', function (err) {
      t.ok(err);
      t.equal(1, arguments.length);
      resolve();
    });
  });
});

test('.run', function (t, p) {
  p.value('something', 3);
  return p.run(function (something) {
    t.equal(something, 3);
  });
});

test('.value', function (t, p) {
  t.test('.value type checking', function (t) {
    t.throws(function () { p.value(function () {}); },
             '.value requires a name');
    t.throws(function () { p.value(5); }, '.value is picky');
    t.end();
  });

  t.test('.value takes an object', function (t) {
    return p.pocket().value({
      one: 1,
      two: 2,
      three: function (one, two) { return one + two; }
    }).run(function (one, two, three) {
      t.equal(1, one);
      t.equal(2, two);
      t.equal(3, three);
    });
  });
});

test('.wrap', function (t, p) {
  p.value('theValue', 3);
  p.value('multiplier', 2);
  p.wrap('theValue', function (theValue, multiplier) {
    t.equal(theValue, 3);
    t.equal(multiplier, 2);
    return theValue * multiplier;
  });
  return p.get('theValue').then(t.equal.bind(t, 6));
});

test('.wrap works on lazy values', function (t, p) {
  p.value('theValue', function () { return 8; });
  p.value('multiplier', function () { return 3; });
  p.wrap('theValue', function (theValue, multiplier) {
    t.equal(theValue, 8);
    t.equal(multiplier, 3);
    return theValue * multiplier;
  });
  return p.get('theValue').then(t.equal.bind(t, 24));
});

test('.wrap can be stacked', function (t, p) {
  p.value('theValue', function () { return 0; });
  p.wrap('theValue', function (theValue) {
    return theValue + 1;
  });
  p.wrap('theValue', function (theValue) {
    return theValue + 1;
  });
  return p.get('theValue').then(t.equal.bind(t, 2));
});

test('.wrap validates arguments', function (t, p) {
  p.value('theValue', 3);
  p.value('multiplier', 2);
  t.throws(function () {
    p.wrap('theValue', 'tortilla');
  }, 'wrapper function must be a function');

  t.throws(function () {
    p.wrap('someOtherValue', function (original) {});
  }, 'wrapper must wrap a known name');

  t.throws(function () {
    p.wrap('theValue', function () {});
  }, 'wrapper must depend on "original"');
  t.end();
});

test('.nodeValue', function (t, p) {
  p.nodeValue(function getNodeStyle (callback) {
    callback(null, 'Node Style');
  });

  return p.run(function (nodeStyle) {
    t.equals(nodeStyle, 'Node Style');
  });
});

test('.missingNames', function (t, p) {
  p.value(function thing (a, b) { });
  t.deepEquals(['a', 'b'], p.missingNames());

  var child = p.pocket();
  p.value('b', 2);
  t.deepEquals(['a'], child.missingNames());
  t.end();
});

test('value caching', function (t, p) {
  var providerExecutionCount = 0;
  var myThing = {};
  p.value(function getThing () {
    providerExecutionCount++;
    return myThing;
  });

  return apply(assertions, p.get('thing'), p.get('thing'));
  function assertions (a, b) {
    t.equal(a, b);
    t.equal(providerExecutionCount, 1);
  }
});

test('parent/child relationships', function (t, p) {
  t.test('children can get deps from parent', function (t) {
    p.value('four', 4);
    p.value(function getFive () { return 5; });

    var child = p.pocket();
    child.value(function getTwenty (four, five) { return four * five; });
    return child.get('twenty').then(t.equal.bind(t, 20));
  });

  t.test('parent cannot retrieve deps from child', function (t) {
    t.assert(!p.has('twenty'));
    t.end();
  });
});

test('granchildren can get deps from their grandparents', function (t, gp) {
  gp.value('five', function () { return 5 });
  var parent = gp.pocket();
  var child = parent.pocket();
  t.ok(child.has('five'), 'Children "have" deps that grandparents "provide"');
  return child.get('five').then(t.equal.bind(t, 5));
});

test('.alias', function (t, p) {
  return p.pocket()
    .value('src', 99)
    .alias('al', 'src')
    .get('al')
    .then(t.equal.bind(t, 99));
});

test('.default', function (t, p) {
  p.default('number', 1);
  p.default('string', function () { return 'ok'; });
  p.default('replaceMe', 'fail');
  p.value('replaceMe', 'ok');
  return join(
    p.get('number').then(t.equal.bind(t, 1)),
    p.get('string').then(t.equal.bind(t, 'ok')),
    p.get('replaceMe').then(t.equal.bind(t, 'ok'))
  );
});

test('overwrite protection', function (t, p) {
  var p1 = p.pocket();
  p1.value('one', 1);
  t.throws(function () {
    p1.value(function one () {});
  });
  var p2 = p.pocket();
  p2.value(function one () {});
  t.throws(function () {
    p1.value('one', 1);
  });

  var p3 = p.pocket();
  p3.default(function one () {});
  t.throws(function () {
    p3.default('one', 1);
  });
  t.end();
});

test('signature parsing', function (t) {
  var parse = require('./signature');
  t.throws(function () {
    parse('blah');
  }, 'Can only parse functions');
  t.end();
});

function join () {
  var args = Array.prototype.slice.call(arguments);
  return Promise.all(args);
}
<|endoftext|>


<commit_before>console.log('Loading a web page');
var page = require('webpage').create();
var url = 'https://123365.org.xycv.aert.xfv.d/';
page.open(url, function (status) {
  console.log("status callback: " + status);
  console.log("eval ret val:" + page.evaluate(function() {
    console.log("window.location.hostname = " + window.location.hostname);
    return window.location.hostname;
  }, function(retval) {
    console.log("retval: " + retval);
    phantom.exit();
  }));
});
console.log("exiting?");

setTimeout(function() { console.log("Timeout!"); }, 1000);
<commit_msg>Use phantomjs url<commit_after>console.log('Loading a web page');
var page = require('webpage').create();
var url = 'http://phantomjs.org';
page.open(url, function (status) {
  console.log("status callback: " + status);
  console.log("eval ret val:" + page.evaluate(function() {
    console.log("window.location.hostname = " + window.location.hostname);
    return window.location.hostname;
  }, function(retval) {
    console.log("retval: " + retval);
    phantom.exit();
  }));
});
console.log("exiting?");

setTimeout(function() { console.log("Timeout!"); }, 1000);
<|endoftext|>


<commit_before>'use strict';

//Top Board
var topOpenSpaces = [];
var topShipSpaces = [];
var topHits = [];
var topMisses = [];
var topHorizontalShips = [];
var topVerticalShips = [];
var topShipLengths = [2, 3, 3, 4, 5];
//Bottom Board
var bottomOpenSpaces = [];
var bottomShipSpaces = [];
var bottomHits = [];
var bottomMisses = [];
var bottomHorizontalShips = [];
var bottomVerticalShips = [];
var bottomShipLengths = [2, 3, 3, 4, 5];

function determineShipOrientation(shipArray, horizontalShips, verticalShips) {
  for (var i = 0; i < shipArray.length; i++){
    if (randomNumber(0, 1) === 0){
      verticalShips.push(shipArray[i]);
    } else {
      horizontalShips.push(shipArray[i]);
    }
  }
}

// Randomly generates the positions of the horizontal ships
// openSpaces will be the open spaces available to place a shipSpaces
// shipSpaces will be the squares that contain a ship
// horinzotalShips will contain the lengths of the horizontal ships (that we will place)
function generateHorizontalShipLocations(openSpaces, shipSpaces, horizontalShips) {

  for (var i = 0; i < horizontalShips.length; i++) {

    // since it is from the openSpaces array, the starting square will always be valid
    var startingSquare = openSpaces[randomNumber(0, openSpaces.length)];
    var endingSquare = startingSquare + (horizontalShips[i] - 1);

    // checks which row the startingSquare and endingSquare are on
    var startingSquareRow = Math.floor(startingSquare / 10);
    var endingSquareRow = Math.floor(endingSquare / 10);

    // gets the index of the starting and ending squares in the open spaces array
    var indexOfStartingSquare = openSpaces.indexOf(startingSquare);
    var indexOfEndingSquare = openSpaces.indexOf(endingSquare);

    // Fixes the position of the ship
    while (endingSquareRow - startingSquareRow !== 0 || shipSpaces.includes(startingSquareRow) || shipSpaces.includes(endingSquareRow) || indexOfEndingSquare - indexOfStartingSquare !== (horizontalShips[i] - 1) || typeof startingSquare !== 'number') {
      startingSquare = openSpaces[randomNumber(0, openSpaces.length)];
      endingSquare = startingSquare + (horizontalShips[i] - 1);
      startingSquareRow = Math.floor(startingSquare / 10);
      endingSquareRow = Math.floor(endingSquare / 10);
      indexOfStartingSquare = openSpaces.indexOf(startingSquare);
      indexOfEndingSquare = openSpaces.indexOf(endingSquare);
    }

    // Adds the ship's coordinates to the shipSpaces array and removes them from the open spaces array
    for (var j = 0; j < horizontalShips[i]; j++) {
      var tempShipCoordinate = startingSquare + j;
      shipSpaces.push(tempShipCoordinate);
      openSpaces.splice(openSpaces.indexOf(tempShipCoordinate), 1);
    }
  }
}

// Randomly generates the positions of the vertical ships
// openSpaces will be the open spaces available to place a shipSpaces
// shipSpaces will be the squares that contain a ship
// verticalShips will contain the lengths of the vertical ships (that we will place)
function generateVerticalShipLocations(openSpaces, shipSpaces, verticalShips) {

  for (var i = 0; i < verticalShips.length; i++) {

    // since it is from the openSpaces array, the starting square will always be valid
    var startingVerticalSquare = openSpaces[randomNumber(0, openSpaces.length)];

    while(startingVerticalSquare >= 80) {
      startingVerticalSquare = openSpaces[randomNumber(0, openSpaces.length)];
    }

    var endingVerticalSquare = startingVerticalSquare + ((verticalShips[i] - 1) * 10);

    var thisShipCoordinates = [];

    for (var j = 0; j < verticalShips[i]; j++) {
      thisShipCoordinates[j] = startingVerticalSquare + (10 * j);
    }

    // helper function to check if any of this vertical ship coordinates are already taken
    var checkIfContains = function(haystack, arr) {
      return arr.some(function (v) {
        return haystack.indexOf(v) >= 0;
      });
    };

    while (endingVerticalSquare >= 99 || checkIfContains(shipSpaces, thisShipCoordinates) || typeof startingVerticalSquare !== 'number') {
      startingVerticalSquare = openSpaces[randomNumber(0, openSpaces.length)];
      endingVerticalSquare = startingVerticalSquare + ((verticalShips[i] - 1) * 10);
      for (var k = 0; k < verticalShips[i]; k++) {
        thisShipCoordinates[k] = startingVerticalSquare + (10 * k);
      }
    }

    // Adds the ship's coordinates to the shipSpaces array and removes them from the open spaces array
    for (var p = 0; p < verticalShips[i]; p++) {
      var tempShipCoordinate = startingVerticalSquare + (p * 10);
      shipSpaces.push(tempShipCoordinate);
      openSpaces.splice(openSpaces.indexOf(tempShipCoordinate), 1);
    }
  }
}

function randomNumber(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function createOpenSpaces() {
  for (var i = 0; i <= 99; i++) {
    topOpenSpaces.push(i);
    bottomOpenSpaces.push(i);
  }
}

function renderBottomShips() {
  for (var i = 0; i < bottomShipSpaces.length; i++) {

    // get the td element id
    var tdIdentifier = 'b' + bottomShipSpaces[i];

    // give the corresponding squares color
    var tdEl = document.getElementById(tdIdentifier);
    tdEl.style.backgroundColor = 'gray';
  }
}

createOpenSpaces();

determineShipOrientation(topShipLengths, topHorizontalShips, topVerticalShips);
determineShipOrientation(bottomShipLengths, bottomHorizontalShips, bottomVerticalShips);

generateVerticalShipLocations(topOpenSpaces, topShipSpaces, topVerticalShips);
generateHorizontalShipLocations(topOpenSpaces, topShipSpaces, topHorizontalShips);

generateVerticalShipLocations(bottomOpenSpaces, bottomShipSpaces, bottomVerticalShips);
generateHorizontalShipLocations(bottomOpenSpaces, bottomShipSpaces, bottomHorizontalShips);

renderBottomShips();
<commit_msg>added constructor for battleship board object<commit_after>'use strict';

function BattleshipBoard(ships) {
  this.openSquares = [];
  this.shipSquares = [];
  this.hits = [];
  this.misses = [];
  this.horizontalShips = [];
  this.verticalShips = [];
  this.shipSizes = ships;
}

//Top Board
var topOpenSpaces = [];
var topShipSpaces = [];
var topHits = [];
var topMisses = [];
var topHorizontalShips = [];
var topVerticalShips = [];
var topShipLengths = [2, 3, 3, 4, 5];
//Bottom Board
var bottomOpenSpaces = [];
var bottomShipSpaces = [];
var bottomHits = [];
var bottomMisses = [];
var bottomHorizontalShips = [];
var bottomVerticalShips = [];
var bottomShipLengths = [2, 3, 3, 4, 5];

function determineShipOrientation(shipArray, horizontalShips, verticalShips) {
  for (var i = 0; i < shipArray.length; i++){
    if (randomNumber(0, 1) === 0){
      verticalShips.push(shipArray[i]);
    } else {
      horizontalShips.push(shipArray[i]);
    }
  }
}

// Randomly generates the positions of the horizontal ships
// openSpaces will be the open spaces available to place a shipSpaces
// shipSpaces will be the squares that contain a ship
// horinzotalShips will contain the lengths of the horizontal ships (that we will place)
function generateHorizontalShipLocations(openSpaces, shipSpaces, horizontalShips) {

  for (var i = 0; i < horizontalShips.length; i++) {

    // since it is from the openSpaces array, the starting square will always be valid
    var startingSquare = openSpaces[randomNumber(0, openSpaces.length)];
    var endingSquare = startingSquare + (horizontalShips[i] - 1);

    // checks which row the startingSquare and endingSquare are on
    var startingSquareRow = Math.floor(startingSquare / 10);
    var endingSquareRow = Math.floor(endingSquare / 10);

    // gets the index of the starting and ending squares in the open spaces array
    var indexOfStartingSquare = openSpaces.indexOf(startingSquare);
    var indexOfEndingSquare = openSpaces.indexOf(endingSquare);

    // Fixes the position of the ship
    while (endingSquareRow - startingSquareRow !== 0 || shipSpaces.includes(startingSquareRow) || shipSpaces.includes(endingSquareRow) || indexOfEndingSquare - indexOfStartingSquare !== (horizontalShips[i] - 1) || typeof startingSquare !== 'number') {
      startingSquare = openSpaces[randomNumber(0, openSpaces.length)];
      endingSquare = startingSquare + (horizontalShips[i] - 1);
      startingSquareRow = Math.floor(startingSquare / 10);
      endingSquareRow = Math.floor(endingSquare / 10);
      indexOfStartingSquare = openSpaces.indexOf(startingSquare);
      indexOfEndingSquare = openSpaces.indexOf(endingSquare);
    }

    // Adds the ship's coordinates to the shipSpaces array and removes them from the open spaces array
    for (var j = 0; j < horizontalShips[i]; j++) {
      var tempShipCoordinate = startingSquare + j;
      shipSpaces.push(tempShipCoordinate);
      openSpaces.splice(openSpaces.indexOf(tempShipCoordinate), 1);
    }
  }
}

// Randomly generates the positions of the vertical ships
// openSpaces will be the open spaces available to place a shipSpaces
// shipSpaces will be the squares that contain a ship
// verticalShips will contain the lengths of the vertical ships (that we will place)
function generateVerticalShipLocations(openSpaces, shipSpaces, verticalShips) {

  for (var i = 0; i < verticalShips.length; i++) {

    // since it is from the openSpaces array, the starting square will always be valid
    var startingVerticalSquare = openSpaces[randomNumber(0, openSpaces.length)];

    while(startingVerticalSquare >= 80) {
      startingVerticalSquare = openSpaces[randomNumber(0, openSpaces.length)];
    }

    var endingVerticalSquare = startingVerticalSquare + ((verticalShips[i] - 1) * 10);

    var thisShipCoordinates = [];

    for (var j = 0; j < verticalShips[i]; j++) {
      thisShipCoordinates[j] = startingVerticalSquare + (10 * j);
    }

    // helper function to check if any of this vertical ship coordinates are already taken
    var checkIfContains = function(haystack, arr) {
      return arr.some(function (v) {
        return haystack.indexOf(v) >= 0;
      });
    };

    while (endingVerticalSquare >= 99 || checkIfContains(shipSpaces, thisShipCoordinates) || typeof startingVerticalSquare !== 'number') {
      startingVerticalSquare = openSpaces[randomNumber(0, openSpaces.length)];
      endingVerticalSquare = startingVerticalSquare + ((verticalShips[i] - 1) * 10);
      for (var k = 0; k < verticalShips[i]; k++) {
        thisShipCoordinates[k] = startingVerticalSquare + (10 * k);
      }
    }

    // Adds the ship's coordinates to the shipSpaces array and removes them from the open spaces array
    for (var p = 0; p < verticalShips[i]; p++) {
      var tempShipCoordinate = startingVerticalSquare + (p * 10);
      shipSpaces.push(tempShipCoordinate);
      openSpaces.splice(openSpaces.indexOf(tempShipCoordinate), 1);
    }
  }
}

function randomNumber(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function createOpenSpaces() {
  for (var i = 0; i <= 99; i++) {
    topOpenSpaces.push(i);
    bottomOpenSpaces.push(i);
  }
}

function renderBottomShips() {
  for (var i = 0; i < bottomShipSpaces.length; i++) {

    // get the td element id
    var tdIdentifier = 'b' + bottomShipSpaces[i];

    // give the corresponding squares color
    var tdEl = document.getElementById(tdIdentifier);
    tdEl.style.backgroundColor = 'gray';
  }
}

createOpenSpaces();

determineShipOrientation(topShipLengths, topHorizontalShips, topVerticalShips);
determineShipOrientation(bottomShipLengths, bottomHorizontalShips, bottomVerticalShips);

generateVerticalShipLocations(topOpenSpaces, topShipSpaces, topVerticalShips);
generateHorizontalShipLocations(topOpenSpaces, topShipSpaces, topHorizontalShips);

generateVerticalShipLocations(bottomOpenSpaces, bottomShipSpaces, bottomVerticalShips);
generateHorizontalShipLocations(bottomOpenSpaces, bottomShipSpaces, bottomHorizontalShips);

renderBottomShips();
<|endoftext|>


<commit_before>var TEMPORAL_ANTIALIASING = false; // Doesn't look so good. Don't use!

var EMPTY_BLOCK_COLOR = "#bbbbbb"
var BLOCK_COLORS = ["#bb0000", "#00bb00", "#bbbb00", "#bb00bb", "#00bbbb"];

var FLOAT_PERIOD = 0.4 // In seconds, how long the block will remain unmoving when swapped into midair.
var CLEAR_PERIOD = 1 // How long blocks will remain after being cleared.
var DROP_SPEED = 50 // Blocks per second.

var BOARD_HEIGHT = 12 // In blocks
var BOARD_LENGTH = 6 // In blocks

var Game = function() {
	this.board = new Board();
}
Game.prototype.draw = function(accumulator) {

	// start with a screen clear
	ctx.fillStyle = "#334D66";
	ctx.fillRect( 0 , 0 , window.innerWidth , window.innerHeight );

	// Draw the board background.
	b_c = Game.get_board_coordinates();
	ctx.fillStyle = EMPTY_BLOCK_COLOR;
	ctx.fillRect(b_c.left, b_c.top, b_c.length, b_c.height);

	bot = b_c.top + b_c.height;

	block_height = b_c.height / BOARD_HEIGHT;
	block_length = b_c.length / BOARD_LENGTH;
	// Draw the blocks.
	for (var i = 0; i < BOARD_HEIGHT; i++) {
		for (var j = 0; j < BOARD_LENGTH; j++) {
			if (!this.board.block[i][j].empty()) {
				var block = this.board.block[i][j].color;
				if (this.board.block[i][j].get_state() == Block.StateEnum.CLEAR) {
					block = block.replace("b", "f").replace("0", "2");
				}
				var percent_fall = 0;
				if (this.board.block[i][j].get_state() == Block.StateEnum.FALL) {
					if (!TEMPORAL_ANTIALIASING) {
						accumulator = 0;
					}
					percent_fall = 1 - ((this.board.block[i][j].state_timer - accumulator) / (1.0 / DROP_SPEED));
					if (percent_fall > 1) { percent_fall = 1;}
				}
				ctx.fillStyle = block;
				ctx.fillRect(
					b_c.left + j * block_length,
					bot - (i + 1 - percent_fall) * block_height,
					block_length, block_height);
			}
		}
	}

	// Draw cursor
	ctx.lineWidth = 5;
	ctx.fillStyle = "#000000";
	ctx.strokeRect(
				b_c.left + this.board.cursor.x * block_length,
				bot - (this.board.cursor.y + 1) * block_height,
				block_length * 2, block_height);

}
Game.get_board_coordinates = function() {

	// First, find the exact center of the screen!
	center = {"x": window.innerWidth / 2, "y": window.innerHeight / 2}

	// Now, find the biggest box dimensions that can fit.
	if (window.innerHeight / window.innerWidth < BOARD_HEIGHT / BOARD_LENGTH) // Limited by screen height.
	{
		box_height = window.innerHeight * 0.9;
		box_length = box_height / 2;
	} else {
		box_length = window.innerWidth * 0.9;
		box_height = box_length * 2;
	}

	// Return JSON object containing proper canvas coordinates to draw board.
	return {
		"left": center.x - box_length / 2,
		"top" : center.y - box_height / 2,
		"length" : box_length,
		"height" : box_height
	};
}
Game.prototype.keydown_handler = function(key) {
	switch (key) {
		case "W":
		case "&":
			if (this.board.cursor.y < BOARD_HEIGHT - 1)
				this.board.cursor.y += 1;
			break;
		case "S":
		case "(":
			if (this.board.cursor.y > 0)
				this.board.cursor.y -= 1;
			break;
		case "A":
		case "%":
			if (this.board.cursor.x > 0)
				this.board.cursor.x -= 1;
			break;
		case "D":
		case "'":
			if (this.board.cursor.x < BOARD_LENGTH - 2)
				this.board.cursor.x += 1;
			break;
		case " ":
			this.board.swap();
			break;
		default:
			this.board.raise();
			break;
	}
}
Game.prototype.update = function(time_step) {
	this.board.update();
}

var matrix_make = function(height, width, default_val) {
	var my_matrix = new Array();
	for (var row = 0; row < height; row++) {
		var new_row = new Array();
		for (var col = 0; col < width; col++) {
			new_row.push(default_val);
		}
		my_matrix.push(new_row);
	}
	return my_matrix
}
<commit_msg>Added some obnoxious sounds<commit_after>var TEMPORAL_ANTIALIASING = false; // Doesn't look so good. Don't use!

var EMPTY_BLOCK_COLOR = "#bbbbbb"
var BLOCK_COLORS = ["#bb0000", "#00bb00", "#bbbb00", "#bb00bb", "#00bbbb"];

var FLOAT_PERIOD = 0.4; // In seconds, how long the block will remain unmoving when swapped into midair.
var CLEAR_PERIOD = 1; // How long blocks will remain after being cleared.
var DROP_SPEED = 50; // Blocks per second.

var BOARD_HEIGHT = 12; // In blocks
var BOARD_LENGTH = 6;  // In blocks

var CANVAS_BACKGROUND_COLOR = "#334D66"; // A pretty shade of blue!

var CLEAR_SOUNDS = ["sound/Clear1.wav", "sound/Clear2.wav", "sound/Clear3.wav"];
var CHAIN_SOUNDS = ["sound/Chain1.wav", "sound/Chain2.wav", "sound/Chain3.wav"];

var Game = function() {
	this.board = new Board();
}

/**
 * TODO: Please, PLEASE make this look prettier.
 * Draws the entire game.
 */
Game.prototype.draw = function(accumulator) {

	// start with a screen clear
	ctx.fillStyle = CANVAS_BACKGROUND_COLOR;
	ctx.fillRect( 0 , 0 , window.innerWidth , window.innerHeight );

	// Draw the board background.
	b_c = Game.get_board_coordinates();
	ctx.fillStyle = EMPTY_BLOCK_COLOR;
	ctx.fillRect(b_c.left, b_c.top, b_c.length, b_c.height);

	bot = b_c.top + b_c.height;

	block_height = b_c.height / BOARD_HEIGHT;
	block_length = b_c.length / BOARD_LENGTH;
	// Draw the blocks.
	for (var row = 0; row < BOARD_HEIGHT; row++) {
		for (var col = 0; col < BOARD_LENGTH; col++) {
			if (!this.board.block[row][col].empty()) {
				var block = this.board.block[row][col].color;
				if (this.board.block[row][col].get_state() == Block.StateEnum.CLEAR) {
					block = block.replace("b", "f").replace("0", "2");
				}
				var percent_fall = 0;
				if (this.board.block[row][col].get_state() == Block.StateEnum.FALL) {
					if (!TEMPORAL_ANTIALIASING) {
						accumulator = 0;
					}
					percent_fall = 1 - ((this.board.block[row][col].state_timer - accumulator) / (1.0 / DROP_SPEED));
					if (percent_fall > 1) { percent_fall = 1;}
				}
				ctx.fillStyle = block;
				ctx.fillRect(
					b_c.left + col * block_length,
					bot - (row + 1 - percent_fall) * block_height,
					block_length, block_height);
			}
		}
	}

	// Draw cursor
	var cursor_width = 5;
	ctx.lineWidth = cursor_width;
	ctx.fillStyle = "#000000";
	ctx.strokeRect(
				b_c.left + this.board.cursor.x * block_length - cursor_width / 2,
				bot - (this.board.cursor.y + 1) * block_height - cursor_width / 2,
				block_length * 2 + cursor_width, block_height + cursor_width);

}

/**
 * Gets canvas coordinates of where the top left of the board should be.
 */
Game.get_board_coordinates = function() {

	// First, find the exact center of the screen!
	center = {"x": window.innerWidth / 2, "y": window.innerHeight / 2}

	// Now, find the biggest box dimensions that can fit.
	if (window.innerHeight / window.innerWidth < BOARD_HEIGHT / BOARD_LENGTH) // Limited by screen height.
	{
		box_height = window.innerHeight * 0.9;
		box_length = box_height / BOARD_HEIGHT * BOARD_LENGTH;
	} else {
		box_length = window.innerWidth * 0.9;
		box_height = box_length / BOARD_LENGTH * BOARD_HEIGHT;
	}

	// Return JSON object containing proper canvas coordinates to draw board.
	return {
		"left": center.x - box_length / 2,
		"top" : center.y - box_height / 2,
		"length" : box_length,
		"height" : box_height
	};
}

/**
 * Ugly way to match key presses to functions.
 * TODO: Make less ugly!
 */
Game.prototype.keydown_handler = function(key) {
	switch (key) {
		case "W":
		case "&":
			if (this.board.cursor.y < BOARD_HEIGHT - 1)
				this.board.cursor.y += 1;
				var move = new Audio("sound/Move.wav");
				move.play();
			break;
		case "S":
		case "(":
			if (this.board.cursor.y > 0)
				this.board.cursor.y -= 1;
				var move = new Audio("sound/Move.wav");
				move.play();
			break;
		case "A":
		case "%":
			if (this.board.cursor.x > 0)
				this.board.cursor.x -= 1;
				var move = new Audio("sound/Move.wav");
				move.play();
			break;
		case "D":
		case "'":
			if (this.board.cursor.x < BOARD_LENGTH - 2)
				this.board.cursor.x += 1;
				var move = new Audio("sound/Move.wav");
				move.play();
			break;
		case " ":
			var swap = new Audio("sound/Swap.wav");
			swap.play();
			this.board.swap();
			break;
		default:
			this.board.raise();
			var move = new Audio("sound/Move.wav");
			move.play();
			break;
	}
}

/**
 * Advance the game timer forward a tick! Not much to see here ... yet!
 */
Game.prototype.update = function(time_step) {
	this.board.update();
}

var matrix_make = function(height, width, default_val) {
	var my_matrix = new Array();
	for (var row = 0; row < height; row++) {
		var new_row = new Array();
		for (var col = 0; col < width; col++) {
			new_row.push(default_val);
		}
		my_matrix.push(new_row);
	}
	return my_matrix
}
<|endoftext|>


<commit_before>"use strict";

function last(array) {
    return array[array.length - 1];
}

var NodeTypes = {
    ROAD: 0,
    DOT: 1
};

class Node {

    constructor(type, color) {
        this.type = type;
        this.color = color;
    }

}

class PathNode extends Node {

    constructor(type, color, x, y) {
        super(type, color);
        this.x = x;
        this.y = y;
    }
}

class Level {

    constructor(levelInfo) {
        this.levelInfo = levelInfo;
        let field = levelInfo.puzzle;
        this.field = new Array(field.length);
        for (let i = 0; i < field.length; ++i) {
            let row = new Array(field[i].length);
            for (let j = 0; j < field[i].length; ++j)
                row[j] = new Node(field[i][j] ? NodeTypes.DOT : NodeTypes.ROAD, field[i][j]);
            this.field[i] = row;
        }
        this.paths = [];
    }

    nodeColor(x, y) {
        return this.field[y] && this.field[y][x] ? this.field[y][x].color : null;
    }

    placeColor(x, y, color) {
        if (!this.field[y] || !this.field[y][x])
            return;
        this.field[y][x].color = color;
    }

    canStartEnd(x, y) {
        return this.field[y] && this.field[y][x] && this.field[y][x].type == NodeTypes.DOT;
    }

    pathIndex(color) {
        for (let i = 0; i < this.paths.length; ++i)
            if (this.paths[i] && this.paths[i].length && this.paths[i][0].color == color)
                return i;
        return -1;
    }

    clearPath(path) {
        if (!path)
            return;
        for (let i = 0; i < path.length; ++i)
            if (path[i].type == NodeTypes.ROAD)
                this.field[path[i].y][path[i].x].color = 0;
    }

    checkPath(color) {
        let path = this.paths[this.pathIndex(color)];
        return path && path.length > 1 && last(path).type == NodeTypes.DOT;
    }

    addPath(path) {
        this.paths.push(path);
    }

    checkAnswer() {
        for (let i = 0; i < this.field.length; ++i)
            for (let j = 0; j < this.field[i].length; ++j)
                if (this.canStartEnd(j, i) && !this.checkPath(this.field[i][j].color))
                    return false;
        return true;
    }

    extractPath(color) {
        let index = this.pathIndex(color);
        if (index < 0)
            return null;
        let path = this.paths[index];
        this.paths.splice(index, 1);
        return path;
    }

}

class Game {

    constructor() {
        this.pathsRestarts = 0;
        this.isMouseDown = false;
        this.isGameFinished = false;
        this.generator = new Generator();
        this.levelWidth = this.levelHeight = 10;
        this.levelNumber = 0;
        this.currentPath = [];
        this.clearCompletedLevels();
    }

    clearCompletedLevels() {
        this.levelsCompleted = [];
        for (let i = 0; i < storage.levelCount(); ++i)
            this.levelsCompleted.push(false);
    }

    updateLevelsCompletion(completed) {
        for (let i = 0; i < this.levelsCompleted.length && completed[i]; ++i)
            this.levelsCompleted[i] = true;
    }

    setScene(scene) {
        this.scene = scene;
    }

    changeLevelDimensions(width, height) {
        this.levelWidth = width;
        this.levelHeight = height;
    }

    selectLevel(levelNumber) {
        this.levelNumber = levelNumber;
    }

    startNewGame() {
        this.isGameFinished = false;
        this.currentPath = [];
        this.level = new Level(this.levelNumber >= storage.levelCount() ?
            this.generator.generate(this.levelWidth, this.levelHeight) :
            storage.level(this.levelNumber));
        this.scene.initLevel(this.level);
    }

    cutPath(x, y, path) {
        let cut = [];
        while (path.length > 1 && (last(path).x != x || last(path).y != y)) {
            if (!this.level.canStartEnd(last(path).x, last(path).y))
                this.level.placeColor(last(path).x, last(path).y, 0);
            cut.push(last(path));
            path.pop();
        }
        if (path.length == 1) {
            cut.push(path[0]);
            path.pop();
        }
        return cut;
    }

    startPath(x, y) {
        let color = this.level.nodeColor(x, y);
        let path = this.level.extractPath(color);
        if (path) {
            if (Game.isInPath(x, y, path) && !this.level.canStartEnd(x, y)) {
                this.currentPath = path;
                this.scene.updateLevel();
                this.cutPath(x, y, path);
                this.currentPath = path;
                this.scene.updateLevel();
            }
            else {
                this.pathsRestarts += 1;
                this.scene.clearPath(this.cutPath(-1, -1, path));
                this.currentPath = [new PathNode(NodeTypes.DOT, this.level.nodeColor(x, y), x, y)];
            }
            return true;
        }
        if (!this.level.canStartEnd(x, y))
            return false;
        this.currentPath.push(new PathNode(NodeTypes.DOT, this.level.nodeColor(x, y), x, y));
        return true;
    }

    canContinue(x, y) {
        if (this.currentPath.length > 1 && last(this.currentPath).type == NodeTypes.DOT)
            return false;
        for (let i = 0; i < 4; ++i) {
            let nx = x + dx[i], ny = y + dy[i];
            if (nx == last(this.currentPath).x && ny == last(this.currentPath).y)
                return true;
        }
        return false;
    }

    static isInPath(x, y, path) {
        for (let i = 0; i < path.length; ++i)
            if (x == path[i].x && y == path[i].y)
                return true;
        return false;
    }

    continuePath(x, y) {
        let color = this.level.nodeColor(x, y);
        if ((x == last(this.currentPath).x && y == last(this.currentPath).y)
            || (color && color != last(this.currentPath).color) || color == null)
            return false;
        if (color == 0) {
            if (!this.canContinue(x, y))
                return;
            this.level.placeColor(x, y, this.currentPath[0].color);
            this.currentPath.push(new PathNode(NodeTypes.ROAD, this.currentPath[0].color, x, y));
            return true;
        }
        if (this.currentPath.length == 1 && !this.level.canStartEnd(x, y))
            return false;
        if (this.level.canStartEnd(x, y) && (x != this.currentPath[0].x || y != this.currentPath[0].y)
            && this.canContinue(x, y)) {
            this.currentPath.push(new PathNode(NodeTypes.DOT, this.currentPath[0].color, x, y));
            return true;
        }
        if (!Game.isInPath(x, y, this.currentPath))
            return false;
        while (this.currentPath.length > 1 && (last(this.currentPath).x != x || last(this.currentPath).y != y)) {
            if (!this.level.canStartEnd(last(this.currentPath).x, last(this.currentPath).y))
                this.level.placeColor(last(this.currentPath).x, last(this.currentPath).y, 0);
            this.currentPath.pop();
        }
        return true;
    }

    getScore() {
        let res = 0;
        for (let i = 0; i < this.level.field.length; ++i)
            for (let j = 0; j < this.level.field[i].length; ++j)
                if (this.level.field[i][j].color && this.level.field[i][j].type != NodeTypes.DOT)
                    res += 1;
        let max = 0;
        for (let i = 0; i < this.level.paths.length; ++i)
            if (this.level.checkPath(this.level.paths[i][0].color))
                max = Math.max(max, this.level.paths[i].length);
        res += Math.ceil((max * 10) * Math.pow(0.95, this.pathsRestarts));
        return res;
    }

    endPath() {
        this.level.addPath(this.currentPath);
    }

    fieldMouseDown(x, y) {
        if (!this.isGameFinished && this.startPath(x, y)) {
            this.isMouseDown = true;
            menu.setScore(this.getScore());
            this.scene.updateLevel();
        }
    }

    fieldMouseMove(x, y) {
        if (this.isMouseDown && this.continuePath(x, y)) {
            menu.setScore(this.getScore());
            this.scene.updateLevel();
        }
    }

    resetLevel() {
        if (this.isGameFinished)
            return;
        for (let i = 0; i < this.level.paths.length; ++i)
            this.scene.clearPath(this.cutPath(-1, -1, this.level.paths[i]));
        this.pathsRestarts = 0;
        menu.setScore(this.getScore());
    }

    fieldMouseUp() {
        this.endPath();
        if (this.isMouseDown && last(this.currentPath).type == NodeTypes.DOT && this.level.checkAnswer()) {
            this.isGameFinished = true;
            this.isMouseDown = false;
            this.currentPath = [];
            menu.completeLevel();
            this.scene.updateLevel();
            $('header').style = '';
        }
        menu.setScore(this.getScore());
        this.currentPath = [];
        this.isMouseDown = false;
    }
}<commit_msg>[GAME] Add a possibility to reset level after completion<commit_after>"use strict";

function last(array) {
    return array[array.length - 1];
}

var NodeTypes = {
    ROAD: 0,
    DOT: 1
};

class Node {

    constructor(type, color) {
        this.type = type;
        this.color = color;
    }

}

class PathNode extends Node {

    constructor(type, color, x, y) {
        super(type, color);
        this.x = x;
        this.y = y;
    }
}

class Level {

    constructor(levelInfo) {
        this.levelInfo = levelInfo;
        let field = levelInfo.puzzle;
        this.field = new Array(field.length);
        for (let i = 0; i < field.length; ++i) {
            let row = new Array(field[i].length);
            for (let j = 0; j < field[i].length; ++j)
                row[j] = new Node(field[i][j] ? NodeTypes.DOT : NodeTypes.ROAD, field[i][j]);
            this.field[i] = row;
        }
        this.paths = [];
    }

    nodeColor(x, y) {
        return this.field[y] && this.field[y][x] ? this.field[y][x].color : null;
    }

    placeColor(x, y, color) {
        if (!this.field[y] || !this.field[y][x])
            return;
        this.field[y][x].color = color;
    }

    canStartEnd(x, y) {
        return this.field[y] && this.field[y][x] && this.field[y][x].type == NodeTypes.DOT;
    }

    pathIndex(color) {
        for (let i = 0; i < this.paths.length; ++i)
            if (this.paths[i] && this.paths[i].length && this.paths[i][0].color == color)
                return i;
        return -1;
    }

    clearPath(path) {
        if (!path)
            return;
        for (let i = 0; i < path.length; ++i)
            if (path[i].type == NodeTypes.ROAD)
                this.field[path[i].y][path[i].x].color = 0;
    }

    checkPath(color) {
        let path = this.paths[this.pathIndex(color)];
        return path && path.length > 1 && last(path).type == NodeTypes.DOT;
    }

    addPath(path) {
        this.paths.push(path);
    }

    checkAnswer() {
        for (let i = 0; i < this.field.length; ++i)
            for (let j = 0; j < this.field[i].length; ++j)
                if (this.canStartEnd(j, i) && !this.checkPath(this.field[i][j].color))
                    return false;
        return true;
    }

    extractPath(color) {
        let index = this.pathIndex(color);
        if (index < 0)
            return null;
        let path = this.paths[index];
        this.paths.splice(index, 1);
        return path;
    }

}

class Game {

    constructor() {
        this.pathsRestarts = 0;
        this.isMouseDown = false;
        this.isGameFinished = false;
        this.generator = new Generator();
        this.levelWidth = this.levelHeight = 10;
        this.levelNumber = 0;
        this.currentPath = [];
        this.clearCompletedLevels();
    }

    clearCompletedLevels() {
        this.levelsCompleted = [];
        for (let i = 0; i < storage.levelCount(); ++i)
            this.levelsCompleted.push(false);
    }

    updateLevelsCompletion(completed) {
        for (let i = 0; i < this.levelsCompleted.length && completed[i]; ++i)
            this.levelsCompleted[i] = true;
    }

    setScene(scene) {
        this.scene = scene;
    }

    changeLevelDimensions(width, height) {
        this.levelWidth = width;
        this.levelHeight = height;
    }

    selectLevel(levelNumber) {
        this.levelNumber = levelNumber;
    }

    startNewGame() {
        this.isGameFinished = false;
        this.currentPath = [];
        this.level = new Level(this.levelNumber >= storage.levelCount() ?
            this.generator.generate(this.levelWidth, this.levelHeight) :
            storage.level(this.levelNumber));
        this.scene.initLevel(this.level);
    }

    cutPath(x, y, path) {
        let cut = [];
        while (path.length > 1 && (last(path).x != x || last(path).y != y)) {
            if (!this.level.canStartEnd(last(path).x, last(path).y))
                this.level.placeColor(last(path).x, last(path).y, 0);
            cut.push(last(path));
            path.pop();
        }
        if (path.length == 1) {
            cut.push(path[0]);
            path.pop();
        }
        return cut;
    }

    startPath(x, y) {
        let color = this.level.nodeColor(x, y);
        let path = this.level.extractPath(color);
        if (path) {
            if (Game.isInPath(x, y, path) && !this.level.canStartEnd(x, y)) {
                this.currentPath = path;
                this.scene.updateLevel();
                this.cutPath(x, y, path);
                this.currentPath = path;
                this.scene.updateLevel();
            }
            else {
                this.pathsRestarts += 1;
                this.scene.clearPath(this.cutPath(-1, -1, path));
                this.currentPath = [new PathNode(NodeTypes.DOT, this.level.nodeColor(x, y), x, y)];
            }
            return true;
        }
        if (!this.level.canStartEnd(x, y))
            return false;
        this.currentPath.push(new PathNode(NodeTypes.DOT, this.level.nodeColor(x, y), x, y));
        return true;
    }

    canContinue(x, y) {
        if (this.currentPath.length > 1 && last(this.currentPath).type == NodeTypes.DOT)
            return false;
        for (let i = 0; i < 4; ++i) {
            let nx = x + dx[i], ny = y + dy[i];
            if (nx == last(this.currentPath).x && ny == last(this.currentPath).y)
                return true;
        }
        return false;
    }

    static isInPath(x, y, path) {
        for (let i = 0; i < path.length; ++i)
            if (x == path[i].x && y == path[i].y)
                return true;
        return false;
    }

    continuePath(x, y) {
        let color = this.level.nodeColor(x, y);
        if ((x == last(this.currentPath).x && y == last(this.currentPath).y)
            || (color && color != last(this.currentPath).color) || color == null)
            return false;
        if (color == 0) {
            if (!this.canContinue(x, y))
                return;
            this.level.placeColor(x, y, this.currentPath[0].color);
            this.currentPath.push(new PathNode(NodeTypes.ROAD, this.currentPath[0].color, x, y));
            return true;
        }
        if (this.currentPath.length == 1 && !this.level.canStartEnd(x, y))
            return false;
        if (this.level.canStartEnd(x, y) && (x != this.currentPath[0].x || y != this.currentPath[0].y)
            && this.canContinue(x, y)) {
            this.currentPath.push(new PathNode(NodeTypes.DOT, this.currentPath[0].color, x, y));
            return true;
        }
        if (!Game.isInPath(x, y, this.currentPath))
            return false;
        while (this.currentPath.length > 1 && (last(this.currentPath).x != x || last(this.currentPath).y != y)) {
            if (!this.level.canStartEnd(last(this.currentPath).x, last(this.currentPath).y))
                this.level.placeColor(last(this.currentPath).x, last(this.currentPath).y, 0);
            this.currentPath.pop();
        }
        return true;
    }

    getScore() {
        let res = 0;
        for (let i = 0; i < this.level.field.length; ++i)
            for (let j = 0; j < this.level.field[i].length; ++j)
                if (this.level.field[i][j].color && this.level.field[i][j].type != NodeTypes.DOT)
                    res += 1;
        let max = 0;
        for (let i = 0; i < this.level.paths.length; ++i)
            if (this.level.paths[i][0] && this.level.checkPath(this.level.paths[i][0].color))
                max = Math.max(max, this.level.paths[i].length);
        res += Math.ceil((max * 10) * Math.pow(0.95, this.pathsRestarts));
        return res;
    }

    endPath() {
        this.level.addPath(this.currentPath);
    }

    fieldMouseDown(x, y) {
        if (!this.isGameFinished && this.startPath(x, y)) {
            this.isMouseDown = true;
            menu.setScore(this.getScore());
            this.scene.updateLevel();
        }
    }

    fieldMouseMove(x, y) {
        if (this.isMouseDown && this.continuePath(x, y)) {
            menu.setScore(this.getScore());
            this.scene.updateLevel();
        }
    }

    resetLevel() {
        for (let i = 0; i < this.level.paths.length; ++i)
            this.scene.clearPath(this.cutPath(-1, -1, this.level.paths[i]));
        $('header').style = 'display: none';
        this.pathsRestarts = 0;
        this.isGameFinished = false;
        menu.setScore(this.getScore());
    }

    fieldMouseUp() {
        this.endPath();
        if (this.isMouseDown && last(this.currentPath).type == NodeTypes.DOT && this.level.checkAnswer()) {
            this.isGameFinished = true;
            this.isMouseDown = false;
            this.currentPath = [];
            menu.completeLevel();
            this.scene.updateLevel();
            $('header').style = '';
        }
        menu.setScore(this.getScore());
        this.currentPath = [];
        this.isMouseDown = false;
    }
}<|endoftext|>