<commit_before>function ongehoordQuiz() {
	this.init();
}

ongehoordQuiz.prototype = {

	questions: [
		{
			'question': 'Wat doet dit varken?',
			'answers': [
				'niks',
				'heel veel',
				'een heleboel'
			],
			'correct': 1,
			'feedback': 'Omdat daarom!'
		},
		{
			'question': 'Wat doet dit varken? 2',
			'answers': [
				'niks',
				'heel veel',
				'een heleboel'
			],
			'correct': 1,
			'feedback': 'Omdat daarom!'
		},
		{
			'question': 'Wat doet dit varken? 3',
			'answers': [
				'niks',
				'heel veel',
				'een heleboel'
			],
			'correct': 1,
			'feedback': 'Omdat daarom!'
		},
		{
			'question': 'Wat doet dit varken? 4',
			'answers': [
				'niks',
				'heel veel',
				'een heleboel'
			],
			'correct': 1,
			'feedback': 'Omdat daarom!'
		}
	],

	elements: {
		'quiz': $('#quiz'),
		'question': $('#quiz-question'),
		'answers': $('#quiz-answers')
	},

	currentQuestion: 0,

	score: 0,

	init: function() {

		this.loadCurrentQuestion();
	},

	show: function() {

		$('.element-main').hide();

		this.elements.quiz.show();
	},

	loadCurrentQuestion: function() {

		this.show();

		this.elements.question.html(this.getCurrentQuestion().question);

		this.elements.answers.html('');

		$.each(this.getCurrentQuestion().answers, function(key, answer) {

			var $answer = $('
'
								+''
								+''
								+''
								+''
								+''+ answer +''
								+''
								+'
')
							.appendTo(this.elements.answers);

			var $button = $answer.find('.button');

			$button.bind('click', function(event) {

				event.preventDefault();

				var right = (key + 1) == this.getCurrentQuestion().correct;

				this.score++;

				this.loadFeedback(right);

			}.bind(this));

		}.bind(this));
	},

	getCurrentQuestion: function() {

		return this.questions[this.currentQuestion];
	},

	loadFeedback: function(right) {

		$('.element-main').hide();
		$('#quiz-feedback').show();

		$('#quiz-feedback')
			.toggleClass('answer-right', right)
			.toggleClass('answer-wrong', !right)
		;

		$('#quiz-feedback h1').html(right ? 'Right!' : 'Wrong!');
		$('#quiz-feedback h3').html(this.getCurrentQuestion().feedback);

		var $video = $('<video id="quiz-feedback-video" '
						+ 'class="video-js vjs-default-skin" '
						+ 'controls preload="auto" '
						+ 'width="640" '
						+ 'height="264" '
						+ 'poster="http://video-js.zencoder.com/oceans-clip.png" '
						+ 'data-setup=\'{"example_option":true}\'>'
						+ ' <source src="movies/'+ this.currentQuestion +'.webm" type="video/webm" />'
						+ '</video>')
			.appendTo('#quiz-feedback-video-container')
		;

		videojs("quiz-feedback-video", {}, function(){
			this.play();
		});

		this.addNextButton();

		$('#quiz-feedback').remove();

	},

	addNextButton: function() {

		var last = (this.currentQuestion + 1) == this.questions.length;

		$('#quiz-feedback .button.next').remove();

		var $buttonNext = $(''
							+ last ? 'Finish' : 'Next'
							+ '')
			.appendTo('#quiz-feedback');

		$buttonNext.click(function(event) {

			event.preventDefault();

			if (last) {

				this.last();
			} else {
				this.next();
			}
		}.bind(this));
	},

	last: function() {

		console.log('last');
	},

	next: function() {

		this.currentQuestion++;

		this.loadCurrentQuestion();

	}
}

$(function() {

	$('#welcome').show();

	$('#quiz-start-button').bind('click', function(event) {

		event.preventDefault();

		var quiz = new ongehoordQuiz();
	})

});<commit_msg>first stage of push button support<commit_after>function Application() {

	this.init();
}

Application.prototype = {

	buttonColors: [
		'green',
		'red',
		'yellow'
	],

	init: function() {

		$('#welcome').show();

		$('#quiz-start-button').bind('click', function(event) {

			event.preventDefault();

			var quiz = new ongehoordQuiz();
		}.bind(this));

		this.bindEvents();
	},

	bindEvents: function() {

		$(document).keyup(function(event) {

			console.log(event.which);

			switch (event.which) {
				case 13:
					//enter
				break;
				case 49:
					//enter
				break;
				case 50:
					//enter
				break;
				case 51:
					//enter
				break;
			}
		});
		// this.triggerButton('green');
	},

	triggerButton: function(color) {

		$('.button.'+ color +':visible').trigger('click');
	}
}

function ongehoordQuiz(application) {

	this.parent = application;
	this.init();
}

ongehoordQuiz.prototype = {

	questions: [
		{
			'question': 'Wat doet dit varken?',
			'answers': [
				'niks',
				'heel veel',
				'een heleboel'
			],
			'correct': 1,
			'feedback': 'Omdat daarom!'
		},
		{
			'question': 'Wat doet dit varken? 2',
			'answers': [
				'niks',
				'heel veel',
				'een heleboel'
			],
			'correct': 1,
			'feedback': 'Omdat daarom!'
		},
		{
			'question': 'Wat doet dit varken? 3',
			'answers': [
				'niks',
				'heel veel',
				'een heleboel'
			],
			'correct': 1,
			'feedback': 'Omdat daarom!'
		},
		{
			'question': 'Wat doet dit varken? 4',
			'answers': [
				'niks',
				'heel veel',
				'een heleboel'
			],
			'correct': 1,
			'feedback': 'Omdat daarom!'
		}
	],

	elements: {
		'quiz': $('#quiz'),
		'question': $('#quiz-question'),
		'answers': $('#quiz-answers')
	},

	currentQuestion: 0,

	score: 0,

	init: function() {

		this.loadCurrentQuestion();
	},

	show: function() {

		$('.element-main').hide();

		this.elements.quiz.show();
	},

	loadCurrentQuestion: function() {

		this.show();

		this.elements.question.html(this.getCurrentQuestion().question);

		this.elements.answers.html('');

		$.each(this.getCurrentQuestion().answers, function(key, answer) {

			var $answer = $('
'
								+''
								+''
								+''
								+''
								+''+ answer +''
								+''
								+'
')
							.appendTo(this.elements.answers);

			var $button = $answer.find('.button');

			$button.bind('click', function(event) {

				event.preventDefault();

				var right = (key + 1) == this.getCurrentQuestion().correct;

				this.score++;

				this.loadFeedback(right);

			}.bind(this));

		}.bind(this));
	},

	getCurrentQuestion: function() {

		return this.questions[this.currentQuestion];
	},

	loadFeedback: function(right) {

		$('.element-main').hide();
		$('#quiz-feedback').show();

		$('#quiz-feedback')
			.toggleClass('answer-right', right)
			.toggleClass('answer-wrong', !right)
		;

		$('#quiz-feedback h1').html(right ? 'Right!' : 'Wrong!');
		$('#quiz-feedback h3').html(this.getCurrentQuestion().feedback);

		$('#quiz-feedback-video').remove();

		var $video = $('<video id="quiz-feedback-video" '
						+ 'class="video-js vjs-default-skin" '
						+ 'controls preload="auto" '
						+ 'width="640" '
						+ 'height="264" '

						+ '>'
						+ ' <source src="movies/'+ this.currentQuestion +'.webm" type="video/webm" />'
						+ '</video>')
			.appendTo('#quiz-feedback-video-container')
		;

		videojs("quiz-feedback-video", {}, function(){
			this.play();
		});

		this.addNextButton();

	},

	addNextButton: function() {

		var last = (this.currentQuestion + 1) == this.questions.length;

		$('#quiz-feedback .button.next').remove();

		var $buttonNext = $(''
							+ (last ? 'Finish' : 'Next')
							+ '')
			.appendTo('#quiz-feedback');

		$buttonNext.click(function(event) {

			event.preventDefault();

			if (last) {

				this.last();
			} else {
				this.next();
			}
		}.bind(this));
	},

	last: function() {

		console.log('last');
	},

	next: function() {

		this.currentQuestion++;

		this.loadCurrentQuestion();

	}
}

$(function() {

	application = new Application();

});<|endoftext|>


<commit_before>(function() {

var stage;
var tikis; // save all canvas objects of tikis

var canvasWidth = 0, canvasHeight = 0;
var tikiWidth = 0, tikiHeight = 0;
var tikiColor = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728',
    '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22'];

var selectedTikiIdx;
var hasSelected; // Boolean
var selectMark;

var upCardRemain, killCardRemain;

var graAgent; // Agent in graphic mode
var graMissions;

$(document).ready(function() {
    //initParams();
    createCanvasStage();
    createCards();
    setupOthers();
    //setupAnimVar();
    resetGame();

    //displayResult($('#result-area'), [16, 9], 2)
    setupTest();
    //$('#tabs').find('li:nth-child(2) a').click();
});

/*
 * Human pk Agent
 */
// Initialize parameters in main.js
function initParams() {
    selectedTikiIdx = null;
    hasSelected = false;
    upCardRemain = 2;
    killCardRemain = 2;
}

// Initialize global variables in animation.js
function setupAnimVar() {
    animStage = stage;
    animTikis = tikis;
    animTikiWidth = tikiWidth;
    animTikiHeight = tikiHeight;
}

/*function startGame() {
    var

    setupGame(2, graMissions);
}*/

function resetGame() {
    stage.removeAllChildren();
    initParams();

    var tikiOrder = createTikiOrder();
    graMissions = createPKMissions(2);
    displayMissions(graMissions);

    setupGame(2, graMissions, tikiOrder);
    graAgent = new Agent();
    var $setting = $('#setting');
    graAgent.init($setting.find('select[name=agent]')[0].value, 1, graMissions[1]);
    //graAgent.setEval($setting.find('select[name=eval]')[0].value);

    createTikis(tikiOrder);
    setupCards();
    setupAnimVar();
}

function createCanvasStage() {
    // Scale canvas with its actually width and height
    var gameCanvas = $('#game-canvas');
    canvasWidth = gameCanvas.width();
    canvasHeight = gameCanvas.height();
    gameCanvas.attr('width', canvasWidth)
            .attr('height', canvasHeight)

    // Initial stage by referencing canvas
    stage = new createjs.Stage(gameCanvas[0]);
    stage.enableMouseOver(20);
}

function createCards() {
    $('#card-wrapper li').append('

');
}

function setupOthers() {
    var comMissionBoard = $('#mission-wrapper div:nth-child(2)');
    //console.log(comMissionBoard);

    var $setting = $('#setting');

    $setting.find('input').change(function() {
        comMissionBoard.fadeToggle();
    });
    $setting.find('select[name=agent]').on('change', function() {
        graAgent = new Agent();
        graAgent.init(this.value, 1, graMissions[1]);
    });
    $setting.find('select[name=eval]').on('change', function() {
        graAgent.setEval(this.value);
    });
    $setting.find('#replay').click(resetGame);
}

function displayMissions(missions) {
    var orderStr = ['9pt', '5pt', '2pt'];
    var missionBoard = $('#mission-wrapper .mission-board:first-child');
    for (var i = 0; i < missions[0].length; ++i) {
        var mission = missionBoard.children(':nth-child(' + (i+2) + ')');
        mission.html(orderStr[i] + ': ' + missions[0][i]);
    }
    missionBoard = missionBoard.next();
    for (var i = 0; i < missions[1].length; ++i) {
        var mission = missionBoard.children(':nth-child(' + (i+2) + ')');
        mission.html(orderStr[i] + ': ' + missions[1][i]);
    }
}

function createTikis(tikiOrder) {
    //var tikiOrder = shuffle([0, 1, 2, 3, 4, 5, 6, 7, 8]);
    state.tikiOrder = tikiOrder;

    tikis = new Array();
    tikiHeight = canvasHeight / tikiColor.length - 10;
    tikiWidth = tikiHeight * 2 / 3;
    var tikiX = canvasWidth / 2 - tikiWidth / 2;
    var tikiY = 10;

    var circleMark = new createjs.Graphics();
    circleMark.setStrokeStyle(1).beginFill('#FFFFFF').drawCircle(0, 0, 3);
    selectMark = new createjs.Shape(circleMark);

    for (var i = 0, o = tikiOrder[i]; i < tikiOrder.length; ++i, o = tikiOrder[i]) {
        var tiki = new createjs.Shape();
        tiki.graphics.beginFill(tikiColor[o])
            .drawRoundRect(0, 0, tikiWidth, tikiHeight, 5);
        var id = new createjs.Text('' + o, 'bold 2em Arial', '#FFFFFF');
        //tiki.x = tikiX;
        //tiki.y = tikiY;
        id.x = 10;
        id.y = 10;

        var container = new createjs.Container();
        container.x = tikiX;
        container.y = tikiY;
        container.addChild(tiki, id);

        tikiY += tikiHeight + 5;

        container.addEventListener('mouseover', function(evt) {
            //evt.target.alpha = 0.6;
            //console.log(!hasSelected);
            if (!hasSelected) {
                selectMark.x = evt.target.x + 10;
                selectMark.y = evt.target.y + 10;
                stage.addChild(selectMark);
                stage.update();
            }
        });
        container.addEventListener('mouseout', function(evt) {
            //evt.target.alpha = 1;
            if (!hasSelected) {
                stage.removeChild(selectMark);
                stage.update();
            }
        });
        container.addEventListener('click', function(evt) {
            if (!hasSelected) {
                selectedTikiIdx = tikis.indexOf(evt.target);
                hasSelected = true;
            }
            else {
                stage.removeChild(selectMark);
                if (evt.target === tikis[selectedTikiIdx]) {
                    selectedTikiIdx = null;
                    hasSelected = false;
                }
                else {
                    selectedTikiIdx = tikis.indexOf(evt.target);
                    selectMark.x = evt.target.x + 10;
                    selectMark.y = evt.target.y + 10;
                    stage.addChild(selectMark);
                }
            }
            stage.update();
        });

        tikis.push(container);
        stage.addChild(container);
    }

    stage.update();
}

function setupCards() {
    var cards = $('#card-wrapper .cards').css('opacity', '');

    cards.eq(0).text('Up 1').on('click', function() {
        if (!hasSelected) return;
        if (0 >= selectedTikiIdx) {
            alert('Cannot move the first Tiki!');
            return;
        }

        //humanAnim = true;
        updateState(0, selectedTikiIdx, 0);
        tikis = moveUp(selectedTikiIdx, 1);

        upCardRemain--;
        if (0 === upCardRemain) {
            $(this).css('opacity', '0').unbind('click');
        }

        stage.removeChild(selectMark);
        stage.update();
        hasSelected = false;
        selectedTikiIdx = null;

        if (handleEnd()) return;

        setTimeout(function() {
            graAgent.move();
            handleEnd();
        }, 1000);
    });
    cards.eq(1).text('Up 2').on('click', function() {
        if (!hasSelected) return;
        if (1 >= selectedTikiIdx) {
            alert('Cannot move Tiki!');
            return;
        }

        updateState(1, selectedTikiIdx, 0);
        tikis = moveUp(selectedTikiIdx, 2);

        $(this).css('opacity', '0').unbind('click');

        stage.removeChild(selectMark);
        stage.update();
        hasSelected = false;
        selectedTikiIdx = null;

        if (handleEnd()) return;

        setTimeout(function() {
            graAgent.move();
            handleEnd();
        }, 1000);
    });
    cards.eq(2).text('Up 3').on('click', function() {
        if (!hasSelected) return;
        if (2 >= selectedTikiIdx) {
            alert('Cannot move Tiki!');
            return;
        }

        updateState(2, selectedTikiIdx, 0);
        tikis = moveUp(selectedTikiIdx, 3);

        $(this).css('opacity', '0').unbind('click');

        stage.removeChild(selectMark);
        stage.update();
        hasSelected = false;
        selectedTikiIdx = null;

        if (handleEnd()) return;

        setTimeout(function() {
            graAgent.move();
            handleEnd();
        }, 1000);
    })
    cards.eq(3).text('Push!').on('click', function() {
        if (!hasSelected) return;
        if (-1 === selectedTikiIdx) {
            alert('Please select again');
            return;
        }
        updateState(3, selectedTikiIdx, 0);
        moveToBottom(selectedTikiIdx);

        $(this).css('opacity', '0').unbind('click');
        stage.removeChild(selectMark);
        stage.update();
        hasSelected = false;
        selectedTikiIdx = null;

        if (handleEnd()) return;

        setTimeout(function() {
            graAgent.move();
            handleEnd();
        }, 1000);
    })
    cards.eq(4).text('Kill!').on('click', function() {
        killCardRemain--;

        updateState(4, tikis.length - 1, 0);
        killLast();

        if (0 === killCardRemain) {
            $(this).css('opacity', '0').unbind('click');
        }
        if (hasSelected) {
            stage.removeChild(selectMark);
            stage.update();
            hasSelected = false;
            selectedTikiIdx = null;
        }

        if (handleEnd()) return;

        setTimeout(function() {
            graAgent.move();
            handleEnd();
        }, 1000);
    });
}

function handleEnd() {
    var result = askJudge();
    if (null !== result) {
        var humScore = result[0],
            comScore = result[1];
        var winner = (comScore > humScore)? 'Computer' : 'You';
        alert('Your score: ' + humScore +
            '\nComputer\'s score: ' + comScore +
            '\n' + winner + ' Wins');
        return true;
    }
    return false;
}

/*
 * Agent PK Agent
 */

function agentPk() {
    var configDiv = $('#test-wrapper #config-div');
    var inputEl = configDiv.children('input');
    var iter = inputEl.first()[0].value;
    var showStep = inputEl.last()[0].checked;
    if (isNaN(iter)) {
        alert('Iterations value invalid.');
        inputEl.first()[0].value = '';
        return;
    }

    var agentOptions = configDiv.find('select[name=agent]');
    var agentNames = [];
    for (var i = 0; i < agentOptions.length; ++i) {
        if ('none' != agentOptions[i].value) {
            agentNames.push(agentOptions[i].value);
        }
    }

    var results = [];
    //var resultArea = $('#result-area').html('');
    for (var i = 0; i < iter; ++i) {
        var missions = createPKMissions(agentNames.length);
        allMissions = missions; // Set up global var in game.js

        // Create Agents
        var agents = new Array();
        for (var j = 0; j < agentNames.length; ++j) {
            agents[j] = new Agent();
            agents[j].init(agentNames[j], j, missions[j]);
        }

        // PK!!!
        setupGame(agentNames.length, missions.slice(), createTikiOrder());

        /*if (showStep) {
            $('body').on('keyup', function(e) {
                e.preventDefault();
            })

        } else {*/
        while(1) {
            var endingResult;
            for (var j = 0; j < agents.length; j++) {
                if (showStep) {
                    plotTikiOrder();
                }
                agents[j].move();
                endingResult = askJudge();
                if (null !== endingResult) {
                    break;
                }
            }
            if (null !== endingResult) {
                showResult(i, endingResult);
                results.push(endingResult);
                //displayResult(resultArea, endingResult, i);
                break;
            }
        }
        //}
    }
}

function showResult(iter, result) {
    var score = '';
    for (var i = 0; i < result.length; i++) {
        score += ('A' + (i+1) + ': ' + result[i] + ' ');
    };
    console.log('#', iter+1, score);
}
/*
function displayResult(area, results, iter) {
    area.html(function(idx, oldhtml) {
        var content = 'Iter #' + iter + '
';
        for (var i = 0; i < results.length; i++) {
            content += 'Agent ' + i + ' score: '
                             + results[i] + '';
        };
        return oldhtml + content + '
';
    });
}
*/

function setupTest() {
    var pagedivs = $('.tabpage');

    var tabsAnchor = $('#tabs li a');
    tabsAnchor.first().addClass('selected');
    tabsAnchor.on('click', function(e) {
        e.preventDefault();
        var $this = $(this);
        $this.addClass('selected')
            .parent().siblings().find('a').removeClass('selected');
        var activeTab = $this.attr('href').slice(1);
        pagedivs.removeClass('hide').addClass('hide');
        $('#'+activeTab).removeClass('hide');

        UI_Mode = ~~(activeTab === 'graphic');
    });

    var $configDiv = $('#config-div');
    var $goBtn = $configDiv.find('#go-btn2');
    $goBtn.on('click', agentPk);
    $configDiv.find('input').on('keyup', function(e) {
        if (13 === e.keyCode) {
            $goBtn.click();
        }
    });

}

function plotTikiOrder() {
    var curState = getState();
    var curOrder = curState.tikiOrder;
    var $orderList = $('#result-area ul');

    var ulWidth = $orderList.width();
    $orderList.width((parseInt(ulWidth)+130) + 'px');

    var divEl = '';
    for (var i = 0; i < curOrder.length; i++) {
        divEl += '
' + curOrder[i] + '
\n';
    }

    $orderList.append('
' + divEl + '
');//.html(curOrder);
    var testTikis = $orderList.children('li').last().find('div');
    for (var i = 0; i < testTikis.length; i++) {
        $(testTikis[i]).css('background-color',
            tikiColor[curOrder[i]]);
    };
}

})();
<commit_msg>Add multi-agent vs human v1<commit_after>(function() {

var stage;
var tikis; // save all canvas objects of tikis

var canvasWidth = 0, canvasHeight = 0;
var tikiWidth = 0, tikiHeight = 0;
var tikiColor = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728',
    '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22'];

var selectedTikiIdx;
var hasSelected; // Boolean
var selectMark;

var upCardRemain, killCardRemain;

var graAgent = []; // Agent in graphic mode
var graMissions = [];

$(document).ready(function() {
    //initParams();
    createCanvasStage();
    createCards();
    setupOthers();
    //setupAnimVar();
    resetGame();

    //displayResult($('#result-area'), [16, 9], 2)
    setupTest();
    //$('#tabs').find('li:nth-child(2) a').click();
});

/*
 * Human pk Agent
 */
// Initialize parameters in main.js
function initParams() {
    selectedTikiIdx = null;
    hasSelected = false;
    upCardRemain = 2;
    killCardRemain = 2;
}

// Initialize global variables in animation.js
function setupAnimVar() {
    animStage = stage;
    animTikis = tikis;
    animTikiWidth = tikiWidth;
    animTikiHeight = tikiHeight;
}

/*function startGame() {
    var

    setupGame(2, graMissions);
}*/

function resetGame() {
    stage.removeAllChildren();
    initParams();

    var tikiOrder = createTikiOrder();
    var $setting = $('#setting');
    var agentOptions = $setting.find('select[name=agent]');
    var agentNames = [];
    for (var i = 0; i < agentOptions.length; ++i) {
        if ('none' != agentOptions[i].value) {
            agentNames.push(agentOptions[i].value);
        }
    }
    graMissions = createPKMissions(agentNames.length+1);
    displayMissions(graMissions);

    setupGame(agentNames.length+1, graMissions, tikiOrder);
    for (var i = 0; i < agentNames.length; i++) {
        var agent = new Agent();
        agent.init(agentNames[i], i+1, graMissions[i+1];
        graAgent.push(agent);
    };
    //graAgent = new Agent();
    //graAgent.init($setting.find('select[name=agent]')[0].value, 1, graMissions[1]);
    //graAgent.setEval($setting.find('select[name=eval]')[0].value);

    createTikis(tikiOrder);
    setupCards();
    setupAnimVar();
}

function createCanvasStage() {
    // Scale canvas with its actually width and height
    var gameCanvas = $('#game-canvas');
    canvasWidth = gameCanvas.width();
    canvasHeight = gameCanvas.height();
    gameCanvas.attr('width', canvasWidth)
            .attr('height', canvasHeight)

    // Initial stage by referencing canvas
    stage = new createjs.Stage(gameCanvas[0]);
    stage.enableMouseOver(20);
}

function createCards() {
    $('#card-wrapper li').append('

');
}

function setupOthers() {
    var comMissionBoard = $('#mission-wrapper div:nth-child(2)');
    //console.log(comMissionBoard);

    var $setting = $('#setting');

    $setting.find('input').change(function() {
        comMissionBoard.fadeToggle();
    });
    $setting.find('select[name=agent]').on('change', function() {
        var idx = $setting.children(select).index($(this))+1;
        graAgent[idx] = new Agent();
        graAgent[idx].init(this.value, idx, graMissions[idx]);
    });
    $setting.find('select[name=eval]').on('change', function() {
        graAgent.setEval(this.value);
    });
    $setting.find('#replay').click(resetGame);
}

function displayMissions(missions) {
    var orderStr = ['9pt', '5pt', '2pt'];
    var missionBoard = $('#mission-wrapper .mission-board:first-child');
    for (var i = 0; i < missions[0].length; ++i) {
        var mission = missionBoard.children(':nth-child(' + (i+2) + ')');
        mission.html(orderStr[i] + ': ' + missions[0][i]);
    }
    missionBoard = missionBoard.next();
    for (var i = 0; i < missions[1].length; ++i) {
        var mission = missionBoard.children(':nth-child(' + (i+2) + ')');
        mission.html(orderStr[i] + ': ' + missions[1][i]);
    }
}

function createTikis(tikiOrder) {
    //var tikiOrder = shuffle([0, 1, 2, 3, 4, 5, 6, 7, 8]);
    state.tikiOrder = tikiOrder;

    tikis = new Array();
    tikiHeight = canvasHeight / tikiColor.length - 10;
    tikiWidth = tikiHeight * 2 / 3;
    var tikiX = canvasWidth / 2 - tikiWidth / 2;
    var tikiY = 10;

    var circleMark = new createjs.Graphics();
    circleMark.setStrokeStyle(1).beginFill('#FFFFFF').drawCircle(0, 0, 3);
    selectMark = new createjs.Shape(circleMark);

    for (var i = 0, o = tikiOrder[i]; i < tikiOrder.length; ++i, o = tikiOrder[i]) {
        var tiki = new createjs.Shape();
        tiki.graphics.beginFill(tikiColor[o])
            .drawRoundRect(0, 0, tikiWidth, tikiHeight, 5);
        var id = new createjs.Text('' + o, 'bold 2em Arial', '#FFFFFF');
        //tiki.x = tikiX;
        //tiki.y = tikiY;
        id.x = 10;
        id.y = 10;

        var container = new createjs.Container();
        container.x = tikiX;
        container.y = tikiY;
        container.addChild(tiki, id);

        tikiY += tikiHeight + 5;

        container.addEventListener('mouseover', function(evt) {
            //evt.target.alpha = 0.6;
            //console.log(!hasSelected);
            if (!hasSelected) {
                selectMark.x = evt.target.x + 10;
                selectMark.y = evt.target.y + 10;
                stage.addChild(selectMark);
                stage.update();
            }
        });
        container.addEventListener('mouseout', function(evt) {
            //evt.target.alpha = 1;
            if (!hasSelected) {
                stage.removeChild(selectMark);
                stage.update();
            }
        });
        container.addEventListener('click', function(evt) {
            if (!hasSelected) {
                selectedTikiIdx = tikis.indexOf(evt.target);
                hasSelected = true;
            }
            else {
                stage.removeChild(selectMark);
                if (evt.target === tikis[selectedTikiIdx]) {
                    selectedTikiIdx = null;
                    hasSelected = false;
                }
                else {
                    selectedTikiIdx = tikis.indexOf(evt.target);
                    selectMark.x = evt.target.x + 10;
                    selectMark.y = evt.target.y + 10;
                    stage.addChild(selectMark);
                }
            }
            stage.update();
        });

        tikis.push(container);
        stage.addChild(container);
    }

    stage.update();
}

function setupCards() {
    var cards = $('#card-wrapper .cards').css('opacity', '');

    cards.eq(0).text('Up 1').on('click', function() {
        if (!hasSelected) return;
        if (0 >= selectedTikiIdx) {
            alert('Cannot move the first Tiki!');
            return;
        }

        //humanAnim = true;
        updateState(0, selectedTikiIdx, 0);
        tikis = moveUp(selectedTikiIdx, 1);

        upCardRemain--;
        if (0 === upCardRemain) {
            $(this).css('opacity', '0').unbind('click');
        }

        stage.removeChild(selectMark);
        stage.update();
        hasSelected = false;
        selectedTikiIdx = null;

        if (handleEnd()) return;

        for (var i = 0; i < graAgent.length; i++) {
            setTimeout(function () {
                graAgent[i].move();
                if (handleEnd()) break;
            }, 1000);
        }

    });
    cards.eq(1).text('Up 2').on('click', function() {
        if (!hasSelected) return;
        if (1 >= selectedTikiIdx) {
            alert('Cannot move Tiki!');
            return;
        }

        updateState(1, selectedTikiIdx, 0);
        tikis = moveUp(selectedTikiIdx, 2);

        $(this).css('opacity', '0').unbind('click');

        stage.removeChild(selectMark);
        stage.update();
        hasSelected = false;
        selectedTikiIdx = null;

        if (handleEnd()) return;
        for (var i = 0; i < graAgent.length; i++) {
            setTimeout(function () {
                graAgent[i].move();
                if (handleEnd()) break;
            }, 1000);
        }

/*
        setTimeout(function() {
            graAgent.move();
            handleEnd();
        }, 1000);*/
    });
    cards.eq(2).text('Up 3').on('click', function() {
        if (!hasSelected) return;
        if (2 >= selectedTikiIdx) {
            alert('Cannot move Tiki!');
            return;
        }

        updateState(2, selectedTikiIdx, 0);
        tikis = moveUp(selectedTikiIdx, 3);

        $(this).css('opacity', '0').unbind('click');

        stage.removeChild(selectMark);
        stage.update();
        hasSelected = false;
        selectedTikiIdx = null;

        if (handleEnd()) return;
        for (var i = 0; i < graAgent.length; i++) {
            setTimeout(function () {
                graAgent[i].move();
                if (handleEnd()) break;
            }, 1000);
        }
/*
        setTimeout(function() {
            graAgent.move();
            handleEnd();
        }, 1000);*/
    })
    cards.eq(3).text('Push!').on('click', function() {
        if (!hasSelected) return;
        if (-1 === selectedTikiIdx) {
            alert('Please select again');
            return;
        }
        updateState(3, selectedTikiIdx, 0);
        moveToBottom(selectedTikiIdx);

        $(this).css('opacity', '0').unbind('click');
        stage.removeChild(selectMark);
        stage.update();
        hasSelected = false;
        selectedTikiIdx = null;

        if (handleEnd()) return;
        for (var i = 0; i < graAgent.length; i++) {
            setTimeout(function () {
                graAgent[i].move();
                if (handleEnd()) break;
            }, 1000);
        }
/*
        setTimeout(function() {
            graAgent.move();
            handleEnd();
        }, 1000);*/
    })
    cards.eq(4).text('Kill!').on('click', function() {
        killCardRemain--;

        updateState(4, tikis.length - 1, 0);
        killLast();

        if (0 === killCardRemain) {
            $(this).css('opacity', '0').unbind('click');
        }
        if (hasSelected) {
            stage.removeChild(selectMark);
            stage.update();
            hasSelected = false;
            selectedTikiIdx = null;
        }

        if (handleEnd()) return;

        for (var i = 0; i < graAgent.length; i++) {
            setTimeout(function () {
                graAgent[i].move();
                if (handleEnd()) break;
            }, 1000);
        }

        /*setTimeout(function() {
            graAgent.move();
            handleEnd();
        }, 1000);*/
    });
}

function handleEnd() {
    var result = askJudge();
    if (null !== result) {
        var humScore = result[0],
            comScore = result[1];
        var winner = (comScore > humScore)? 'Computer' : 'You';
        alert('Your score: ' + humScore +
            '\nComputer\'s score: ' + comScore +
            '\n' + winner + ' Wins');
        return true;
    }
    return false;
}

/*
 * Agent PK Agent
 */

function agentPk() {
    var configDiv = $('#test-wrapper #config-div');
    var inputEl = configDiv.children('input');
    var iter = inputEl.first()[0].value;
    var showStep = inputEl.last()[0].checked;
    if (isNaN(iter)) {
        alert('Iterations value invalid.');
        inputEl.first()[0].value = '';
        return;
    }

    var agentOptions = configDiv.find('select[name=agent]');
    var agentNames = [];
    for (var i = 0; i < agentOptions.length; ++i) {
        if ('none' != agentOptions[i].value) {
            agentNames.push(agentOptions[i].value);
        }
    }

    var results = [];
    //var resultArea = $('#result-area').html('');
    for (var i = 0; i < iter; ++i) {
        var missions = createPKMissions(agentNames.length);
        allMissions = missions; // Set up global var in game.js

        // Create Agents
        var agents = new Array();
        for (var j = 0; j < agentNames.length; ++j) {
            agents[j] = new Agent();
            agents[j].init(agentNames[j], j, missions[j]);
        }

        // PK!!!
        setupGame(agentNames.length, missions.slice(), createTikiOrder());

        /*if (showStep) {
            $('body').on('keyup', function(e) {
                e.preventDefault();
            })

        } else {*/
        while(1) {
            var endingResult;
            for (var j = 0; j < agents.length; j++) {
                if (showStep) {
                    plotTikiOrder();
                }
                agents[j].move();
                endingResult = askJudge();
                if (null !== endingResult) {
                    break;
                }
            }
            if (null !== endingResult) {
                showResult(i, endingResult);
                results.push(endingResult);
                //displayResult(resultArea, endingResult, i);
                break;
            }
        }
        //}
    }
}

function showResult(iter, result) {
    var score = '';
    for (var i = 0; i < result.length; i++) {
        score += ('A' + (i+1) + ': ' + result[i] + ' ');
    };
    console.log('#', iter+1, score);
}
/*
function displayResult(area, results, iter) {
    area.html(function(idx, oldhtml) {
        var content = 'Iter #' + iter + '
';
        for (var i = 0; i < results.length; i++) {
            content += 'Agent ' + i + ' score: '
                             + results[i] + '';
        };
        return oldhtml + content + '
';
    });
}
*/

function setupTest() {
    var pagedivs = $('.tabpage');

    var tabsAnchor = $('#tabs li a');
    tabsAnchor.first().addClass('selected');
    tabsAnchor.on('click', function(e) {
        e.preventDefault();
        var $this = $(this);
        $this.addClass('selected')
            .parent().siblings().find('a').removeClass('selected');
        var activeTab = $this.attr('href').slice(1);
        pagedivs.removeClass('hide').addClass('hide');
        $('#'+activeTab).removeClass('hide');

        UI_Mode = ~~(activeTab === 'graphic');
    });

    var $configDiv = $('#config-div');
    var $goBtn = $configDiv.find('#go-btn2');
    $goBtn.on('click', agentPk);
    $configDiv.find('input').on('keyup', function(e) {
        if (13 === e.keyCode) {
            $goBtn.click();
        }
    });

}

function plotTikiOrder() {
    var curState = getState();
    var curOrder = curState.tikiOrder;
    var $orderList = $('#result-area ul');

    var ulWidth = $orderList.width();
    $orderList.width((parseInt(ulWidth)+130) + 'px');

    var divEl = '';
    for (var i = 0; i < curOrder.length; i++) {
        divEl += '
' + curOrder[i] + '
\n';
    }

    $orderList.append('
' + divEl + '
');//.html(curOrder);
    var testTikis = $orderList.children('li').last().find('div');
    for (var i = 0; i < testTikis.length; i++) {
        $(testTikis[i]).css('background-color',
            tikiColor[curOrder[i]]);
    };
}

})();
<|endoftext|>


<commit_before>(function bouncer() {
  "use strict";

  var Game = window.Game;

  var $ = document.getElementById.bind(document);
  var screen = $("screen");
  var eltMessage = $("message");
  var width = window.innerWidth;
  var height = window.innerHeight;
  var eltScore = $("score");
  var eltMultiplier = $("multiplier");
  var eltHealth = $("health");

  /**
   * The time at which some events happened, in milliseconds since the epoch.
   */
  var timeStamps = {
    /**
     * The start of the game
     */
    gameStart: Date.now(),

    /**
     * Instant at which the previous frame started being prepared
     */
    previousFrame: Date.now() - 15,

    /**
     * Instant at which the current frame started being prepared
     */
    currentFrame: Date.now(),

    /**
     * Instant at which we launched the latest ball
     */
    latestBallLaunch: 0,

    /**
     * Instant at the lastest score multiplier update
     */
    lastestMultiplierUpdate: Date.now(),
 };

  /**
   * The different scores and the multiplier of the current game
   */
  var score = {
    /**
     * The score of the older frame
     */
    previous: -1,

    /**
     * The score in the current frame
     */
    current: 0,

    /**
     * The score multiplier, increase when the game lasts longer
     */
    multiplier: 1,
  };

  /**
   * The different values for health in current game
   */
  var health = {
    /**
     * The health of the older frame
     */
    previous: 0,

    /**
     * The health in the current frame
     */
    current: Game.Config.Health.defaultStarting,
  };

  var Sprite = Game.Sprite;
  var Ball = Game.Ball;

  // Shortcut: an array with all the pads
  var pads = [];

  // Initialize sprites
  var padNorth = new Sprite("pad_north");
  var padSouth = new Sprite("pad_south");
  var padEast = new Sprite("pad_east");
  var padWest = new Sprite("pad_west");

  padNorth.setPosition("center", "top");
  padSouth.setPosition("center", "bottom");
  padEast.setPosition("left", "center");
  padWest.setPosition("right", "center");
  for (var pad of [padNorth, padSouth, padEast, padWest]) {
    pads.push(pad);
    Sprite.all.add(pad);
  }

  Sprite.all.forEach(function (sprite) {
    sprite.writeToDOM();
  });

  // Handle events

  function onmove(e) {
    for (var pad of pads) {
      pad.event.pageX = e.pageX;
      pad.event.pageY = e.pageY;
    }
    e.stopPropagation();
    e.preventDefault();
  }
  function ontouch(e) {
    onmove(e);
    Pause.resume();
  }
  window.addEventListener("mousemove", onmove);
  window.addEventListener("mouseup", ontouch);
  window.addEventListener("touchstart", ontouch);
  window.addEventListener("touchmove", ontouch);

  /**
   * An object centralizing pause information.
   */
  var Pause = Game.Pause = {
    /**
     * true if the game is on pause, false otherwise
     */
    isPaused: false,

    /**
     * Put the game on pause.
     *
     * Has no effect if the game is already on pause.
     */
    start: function() {
      Pause.isPaused = true;
      eltMessage.classList.add("visible");
      eltMessage.textContent = "Pause";
    },

    /**
     * Resume the game.
     *
     * Has no effect if the game is not on pause.
     */
    resume: function() {
      if (!Pause.isPaused) {
        return;
      }
      Pause.isPaused = false;
      eltMessage.classList.remove("visible");

      // Make sure that the game doesn't freak out by launching balls,
      // increasing speed, etc.
      var now = Date.now();
      timeStamps.previousFrame = now - 15;
      timeStamps.currentFrame = now;
      timeStamps.latestBallLaunch = now;

      // Resume game
      requestAnimationFrame(loop);
    },

    /**
     * Switch between on pause/out of pause.
     */
    revert: function() {
      if (Pause.isPaused) {
        Pause.resume();
      } else {
        Pause.start();
      }
    }
  };
  window.addEventListener("keydown", function(event) {
    var code = event.keyCode || event.which || null;
    if (code == null) {
      // No code information, this must be an old version of
      // Internet Explorer
      return;
    }
    if (code != window.KeyEvent.DOM_VK_SPACE) {
      // Not the space key
      return;
    }
    event.preventDefault();
    event.stopPropagation();
    Pause.revert();
  });
  window.addEventListener("blur", function() {
    Pause.start();
  });

  var nextFrame = function() {

    // -------- Read from DOM -------------

    // All reads from DOM *must* happen before the writes to DOM.
    // Otherwise, we end up recomputing the layout several times
    // for a frame, which is very much not good.

    Sprite.all.forEach(function (sprite) {
      sprite.readFromDOM();
    });

    Ball.flushPending(pads);

    Sprite.width = width = window.innerWidth;
    Sprite.height = height = window.innerHeight;

    // --------- Done reading from DOM ----

    var deltaT = timeStamps.currentFrame - timeStamps.previousFrame;

    // Return pause
    if (Pause.isPaused) {
      return false;
    }

    // Handle ball bouncing
    for (var ball of Ball.balls) {

      if (ball.event.dx < 0) {
        ball.bounceX.check(ball.x <= 0, "E", padEast);
      } else if (ball.event.dx > 0) {
        ball.bounceX.check(ball.E >= width, "W", padWest);
      }

      if (ball.event.dy < 0) {
        ball.bounceY.check(ball.y <= 0, "S", padSouth);
      } else if (ball.event.dy > 0) {
        ball.bounceY.check(ball.S >= height, "N", padNorth);
      }

      var collisionWithWall = ball.bounceX.bounceOnWall ||
        ball.bounceY.bounceOnWall;

      var collisionWithPad = !collisionWithWall &&
        ball.bounceX.bounceOnPad ||
        ball.bounceY.bounceOnPad;

      ball.updateVector();

      // Update the current score and current health
      if (collisionWithPad) {
        if (timeStamps.currentFrame - timeStamps.lastestMultiplierUpdate >= 10000) {
          score.multiplier += 0.5;
          timeStamps.lastestMultiplierUpdate = timeStamps.currentFrame;
        }
        score.current += Game.Config.Score.bounceOnPad * score.multiplier;
        health.current += Game.Config.Health.regenerate;
      } else if (collisionWithWall) {
        score.current += Game.Config.Score.bounceOnWall;
        health.current += Game.Config.Health.hurt;
      }
    }

    // Update position of sprites
    // Note that we set both x and y, even for sprites that can move only
    // laterally/vertically, to ensure that we keep the game flowing even
    // in case of screen resize or orientation change.
    padNorth.nextX = padNorth.event.pageX - padNorth.width / 2;
    padNorth.nextX = Game.Utils.restrictToSegment(padNorth.nextX, 0, width - padNorth.width);
    padNorth.ypos = "top";

    padSouth.nextX = padSouth.event.pageX - padSouth.width / 2;
    padSouth.nextX = Game.Utils.restrictToSegment(padSouth.nextX, 0, width - padSouth.width);
    padSouth.ypos = "bottom";

    padEast.nextY = padEast.event.pageY - padEast.height / 2;
    padEast.nextY = Game.Utils.restrictToSegment(padEast.nextY, 0, height - padEast.height);
    padEast.xpos = "right";

    padWest.nextY = padWest.event.pageY - padWest.height / 2;
    padWest.nextY = Game.Utils.restrictToSegment(padWest.nextY, 0, height - padWest.height);
    padWest.xpos = "left";

    for (ball of Ball.balls) {
      ball.nextX = ball.x + Math.round(ball.event.dx * ball.event.speed * deltaT);
      ball.nextY = ball.y + Math.round(ball.event.dy * ball.event.speed * deltaT);
    }

    // FIXME: Handle health, win/lose

    // FIXME: Handle game speed

    // FIXME: Handle score

    // -------- Write to DOM -------------

    // Prepare new balls
    if (timeStamps.currentFrame - timeStamps.latestBallLaunch >=
      Game.Config.intervalBetweenBalls) {
      Ball.prepare(screen);
      timeStamps.latestBallLaunch = timeStamps.currentFrame;
    }

    // Update ball colors
    for (ball of Ball.balls) {
      if (ball.bounceX.bounceOnPad || ball.bounceY.bounceOnPad) {
        ball.changeBallColor();
      }
    }
    Sprite.all.forEach(function (sprite) {
      sprite.writeToDOM();
    });
    screen.style.width = width;
    screen.style.height = height;

    // Update the score if it has changed
    if (score.current != score.previous) {
      eltScore.textContent = score.current + " pts";
      score.previous = score.current;
    }

    // Update the score multiplier if it has changed
    if (timeStamps.lastestMultiplierUpdate == timeStamps.currentFrame && score.multiplier > 1) {
      eltMultiplier.textContent = "x " + score.multiplier;
    }

    // Update the health if it has changed
    if (health.current != health.previous) {
      eltHealth.textContent = health.current + " ❤";
      health.previous = health.current;
    }

    // -------- Write to DOM -------------

    return true;
  };

  nextFrame();

  // Main loop
  function loop() {
    timeStamps.previousFrame = timeStamps.currentFrame;
    timeStamps.currentFrame = Date.now();

    if (health.current <= 0) {
      eltHealth.textContent = 0 + " ❤";

      if (score.current > 0) {
        eltMessage.textContent = 'Congratulation, you have ' + score.current + " points !";
        eltMessage.classList.add("visible");
      } else {
        eltMessage.textContent = 'You lose :-(';
        eltMessage.classList.add("visible");
      }
    } else {
      nextFrame();
      requestAnimationFrame(loop);
    }
  };
  requestAnimationFrame(loop);
})();

<commit_msg>[Fix] CongratulationS is always plural and always needs an s at the end<commit_after>(function bouncer() {
  "use strict";

  var Game = window.Game;

  var $ = document.getElementById.bind(document);
  var screen = $("screen");
  var eltMessage = $("message");
  var width = window.innerWidth;
  var height = window.innerHeight;
  var eltScore = $("score");
  var eltMultiplier = $("multiplier");
  var eltHealth = $("health");

  /**
   * The time at which some events happened, in milliseconds since the epoch.
   */
  var timeStamps = {
    /**
     * The start of the game
     */
    gameStart: Date.now(),

    /**
     * Instant at which the previous frame started being prepared
     */
    previousFrame: Date.now() - 15,

    /**
     * Instant at which the current frame started being prepared
     */
    currentFrame: Date.now(),

    /**
     * Instant at which we launched the latest ball
     */
    latestBallLaunch: 0,

    /**
     * Instant at the lastest score multiplier update
     */
    lastestMultiplierUpdate: Date.now(),
 };

  /**
   * The different scores and the multiplier of the current game
   */
  var score = {
    /**
     * The score of the older frame
     */
    previous: -1,

    /**
     * The score in the current frame
     */
    current: 0,

    /**
     * The score multiplier, increase when the game lasts longer
     */
    multiplier: 1,
  };

  /**
   * The different values for health in current game
   */
  var health = {
    /**
     * The health of the older frame
     */
    previous: 0,

    /**
     * The health in the current frame
     */
    current: Game.Config.Health.defaultStarting,
  };

  var Sprite = Game.Sprite;
  var Ball = Game.Ball;

  // Shortcut: an array with all the pads
  var pads = [];

  // Initialize sprites
  var padNorth = new Sprite("pad_north");
  var padSouth = new Sprite("pad_south");
  var padEast = new Sprite("pad_east");
  var padWest = new Sprite("pad_west");

  padNorth.setPosition("center", "top");
  padSouth.setPosition("center", "bottom");
  padEast.setPosition("left", "center");
  padWest.setPosition("right", "center");
  for (var pad of [padNorth, padSouth, padEast, padWest]) {
    pads.push(pad);
    Sprite.all.add(pad);
  }

  Sprite.all.forEach(function (sprite) {
    sprite.writeToDOM();
  });

  // Handle events

  function onmove(e) {
    for (var pad of pads) {
      pad.event.pageX = e.pageX;
      pad.event.pageY = e.pageY;
    }
    e.stopPropagation();
    e.preventDefault();
  }
  function ontouch(e) {
    onmove(e);
    Pause.resume();
  }
  window.addEventListener("mousemove", onmove);
  window.addEventListener("mouseup", ontouch);
  window.addEventListener("touchstart", ontouch);
  window.addEventListener("touchmove", ontouch);

  /**
   * An object centralizing pause information.
   */
  var Pause = Game.Pause = {
    /**
     * true if the game is on pause, false otherwise
     */
    isPaused: false,

    /**
     * Put the game on pause.
     *
     * Has no effect if the game is already on pause.
     */
    start: function() {
      Pause.isPaused = true;
      eltMessage.classList.add("visible");
      eltMessage.textContent = "Pause";
    },

    /**
     * Resume the game.
     *
     * Has no effect if the game is not on pause.
     */
    resume: function() {
      if (!Pause.isPaused) {
        return;
      }
      Pause.isPaused = false;
      eltMessage.classList.remove("visible");

      // Make sure that the game doesn't freak out by launching balls,
      // increasing speed, etc.
      var now = Date.now();
      timeStamps.previousFrame = now - 15;
      timeStamps.currentFrame = now;
      timeStamps.latestBallLaunch = now;

      // Resume game
      requestAnimationFrame(loop);
    },

    /**
     * Switch between on pause/out of pause.
     */
    revert: function() {
      if (Pause.isPaused) {
        Pause.resume();
      } else {
        Pause.start();
      }
    }
  };
  window.addEventListener("keydown", function(event) {
    var code = event.keyCode || event.which || null;
    if (code == null) {
      // No code information, this must be an old version of
      // Internet Explorer
      return;
    }
    if (code != window.KeyEvent.DOM_VK_SPACE) {
      // Not the space key
      return;
    }
    event.preventDefault();
    event.stopPropagation();
    Pause.revert();
  });
  window.addEventListener("blur", function() {
    Pause.start();
  });

  var nextFrame = function() {

    // -------- Read from DOM -------------

    // All reads from DOM *must* happen before the writes to DOM.
    // Otherwise, we end up recomputing the layout several times
    // for a frame, which is very much not good.

    Sprite.all.forEach(function (sprite) {
      sprite.readFromDOM();
    });

    Ball.flushPending(pads);

    Sprite.width = width = window.innerWidth;
    Sprite.height = height = window.innerHeight;

    // --------- Done reading from DOM ----

    var deltaT = timeStamps.currentFrame - timeStamps.previousFrame;

    // Return pause
    if (Pause.isPaused) {
      return false;
    }

    // Handle ball bouncing
    for (var ball of Ball.balls) {

      if (ball.event.dx < 0) {
        ball.bounceX.check(ball.x <= 0, "E", padEast);
      } else if (ball.event.dx > 0) {
        ball.bounceX.check(ball.E >= width, "W", padWest);
      }

      if (ball.event.dy < 0) {
        ball.bounceY.check(ball.y <= 0, "S", padSouth);
      } else if (ball.event.dy > 0) {
        ball.bounceY.check(ball.S >= height, "N", padNorth);
      }

      var collisionWithWall = ball.bounceX.bounceOnWall ||
        ball.bounceY.bounceOnWall;

      var collisionWithPad = !collisionWithWall &&
        ball.bounceX.bounceOnPad ||
        ball.bounceY.bounceOnPad;

      ball.updateVector();

      // Update the current score and current health
      if (collisionWithPad) {
        if (timeStamps.currentFrame - timeStamps.lastestMultiplierUpdate >= 10000) {
          score.multiplier += 0.5;
          timeStamps.lastestMultiplierUpdate = timeStamps.currentFrame;
        }
        score.current += Game.Config.Score.bounceOnPad * score.multiplier;
        health.current += Game.Config.Health.regenerate;
      } else if (collisionWithWall) {
        score.current += Game.Config.Score.bounceOnWall;
        health.current += Game.Config.Health.hurt;
      }
    }

    // Update position of sprites
    // Note that we set both x and y, even for sprites that can move only
    // laterally/vertically, to ensure that we keep the game flowing even
    // in case of screen resize or orientation change.
    padNorth.nextX = padNorth.event.pageX - padNorth.width / 2;
    padNorth.nextX = Game.Utils.restrictToSegment(padNorth.nextX, 0, width - padNorth.width);
    padNorth.ypos = "top";

    padSouth.nextX = padSouth.event.pageX - padSouth.width / 2;
    padSouth.nextX = Game.Utils.restrictToSegment(padSouth.nextX, 0, width - padSouth.width);
    padSouth.ypos = "bottom";

    padEast.nextY = padEast.event.pageY - padEast.height / 2;
    padEast.nextY = Game.Utils.restrictToSegment(padEast.nextY, 0, height - padEast.height);
    padEast.xpos = "right";

    padWest.nextY = padWest.event.pageY - padWest.height / 2;
    padWest.nextY = Game.Utils.restrictToSegment(padWest.nextY, 0, height - padWest.height);
    padWest.xpos = "left";

    for (ball of Ball.balls) {
      ball.nextX = ball.x + Math.round(ball.event.dx * ball.event.speed * deltaT);
      ball.nextY = ball.y + Math.round(ball.event.dy * ball.event.speed * deltaT);
    }

    // FIXME: Handle health, win/lose

    // FIXME: Handle game speed

    // FIXME: Handle score

    // -------- Write to DOM -------------

    // Prepare new balls
    if (timeStamps.currentFrame - timeStamps.latestBallLaunch >=
      Game.Config.intervalBetweenBalls) {
      Ball.prepare(screen);
      timeStamps.latestBallLaunch = timeStamps.currentFrame;
    }

    // Update ball colors
    for (ball of Ball.balls) {
      if (ball.bounceX.bounceOnPad || ball.bounceY.bounceOnPad) {
        ball.changeBallColor();
      }
    }
    Sprite.all.forEach(function (sprite) {
      sprite.writeToDOM();
    });
    screen.style.width = width;
    screen.style.height = height;

    // Update the score if it has changed
    if (score.current != score.previous) {
      eltScore.textContent = score.current + " pts";
      score.previous = score.current;
    }

    // Update the score multiplier if it has changed
    if (timeStamps.lastestMultiplierUpdate == timeStamps.currentFrame && score.multiplier > 1) {
      eltMultiplier.textContent = "x " + score.multiplier;
    }

    // Update the health if it has changed
    if (health.current != health.previous) {
      eltHealth.textContent = health.current + " ❤";
      health.previous = health.current;
    }

    // -------- Write to DOM -------------

    return true;
  };

  nextFrame();

  // Main loop
  function loop() {
    timeStamps.previousFrame = timeStamps.currentFrame;
    timeStamps.currentFrame = Date.now();

    if (health.current <= 0) {
      eltHealth.textContent = 0 + " ❤";

      if (score.current > 0) {
        eltMessage.textContent = 'Congratulations, you have ' + score.current + " points !";
        eltMessage.classList.add("visible");
      } else {
        eltMessage.textContent = 'You lose :-(';
        eltMessage.classList.add("visible");
      }
    } else {
      nextFrame();
      requestAnimationFrame(loop);
    }
  };
  requestAnimationFrame(loop);
})();

<|endoftext|>


<commit_before>// ==========================================================================
//                            DG.LegendView
//
//  Author:   William Finzer
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

sc_require('components/graph/utilities/graph_drop_target');
sc_require('views/raphael_base');

/** @class  DG.LegendView - The base class view for a graph legend.

  @extends DG.RaphaelBaseView
*/
DG.LegendView = DG.RaphaelBaseView.extend( DG.GraphDropTarget,

  (function()
  {
    var kVMargin = 3,
        kHMargin = 6;

    /** @scope DG.LegendView.prototype */
    return {
      displayProperties: ['model.attributeDescription.attribute'],

      classNames: ['dg-legend-view'],

      /**
        The model on which this view is based.
        @property { DG.LegendModel }
      */
      model: null,

      /**
        A legend view is always horizontal
        @property { String }
      */
      orientation: 'horizontal',

      /**
       * @property {DG.CategoriesView}
       */
      categoriesView: null,

      /**
       * @property {DG.ChoroplethView}
       */
      choroplethView: null,

      /**
       * @property {DG.Attribute}
       */
      plottedAttribute: function() {
        return this.getPath('model.attributeDescription.attribute');
      }.property(),

      /**
       * For a numeric legend we just need a single row for the color gradient rectangle.
       * For a categorical legend, we'll put two categories in each row.
       *
        @property { Number }
      */
      desiredExtent: function() {
        var tLabelHeight = this.get('labelExtent').y,
            tExtent = tLabelHeight + 2 * kVMargin;
        switch( this.get('attributeType')) {
          case DG.Analysis.EAttributeType.eNumeric:
            tExtent += this.get('chloroplethView').desiredExtent( tLabelHeight);
            break;
          case DG.Analysis.EAttributeType.eCategorical:
            tExtent += this.get('categoriesView').desiredExtent( tLabelHeight);
            break;
          case DG.Analysis.EAttributeType.eColor:
            // Only the label displays
            break;
        }
        return tExtent;
      }.property(),
      desiredExtentDidChange: function() {
        this.notifyPropertyChange('desiredExtent');
      }.observes('labelNode', '*model.numberOfCells'),

      /**
      Return the extent of the label
        @property {Point as in { x, y }}
      */
      labelExtent: function() {
        var	kMinHeight = DG.RenderingUtilities.kCaptionFontHeight,
            tLabelNode = this.get('labelNode'),
            tBox;
        if( !SC.none( tLabelNode)) {
          tBox = tLabelNode.get('bBox');
          return { x: isNaN(tBox.width) ? kMinHeight : Math.max( kMinHeight, tBox.width),
                   y: isNaN(tBox.height) ? kMinHeight : Math.max( kMinHeight, Math.ceil( tBox.height / 2) * 2) };
        }
        return { x: 0, y: kMinHeight};
      }.property('labelNode').cacheable(),

      /**
      The Raphael element used to display the label.
        @property {Raphael element}
      */
      labelNode: function() {
        var tChangeHappened = false,
            tText, tDescription;
        if( SC.none( this._paper))
          return;

        if( SC.none( this._labelNode)) {
          this._labelNode = DG.LabelNode.create({ paper: this._paper, rotation: 0,
            colorIndex: 0, numColors: 1,
            anchor: 'start'});
          this._labelNode.setDragLabelHandler( DG.DragLabelHandler.create({
            labelNode: this._labelNode,
            labelView: this._hiddenDragView,
            viewToAddTo: this,
            attributeDescription: this.getPath('model.attributeDescription'),
            attributeName: this.getPath('model.attributeDescription.attribute.name'),
            dataContext: this.getPath('model.dataConfiguration.dataContext')
          }) );

          tChangeHappened = true;
        }
        tText = this.getPath('model.label');
        // If the text has changed, we set it and notify
        if( tText !== this._labelNode.get('text')) {
          this._labelNode.set('text', tText );
          tChangeHappened = true;
        }
        tDescription = this.getPath('model.attributeDescription.attribute.description') + '—' +
                                    'DG.LegendView.attributeTooltip'.loc();
        if( tDescription !== this._labelNode.get('description')) {
          this._labelNode.set('description', tDescription );
          tChangeHappened = true;
        }
        if( tChangeHappened)
          this.notifyPropertyChange( 'labelNode', this._labelNode);

        if( SC.empty( tText))
          return null;
        else
          return this._labelNode;
      }.property(),

      labelNodeDidChange: function() {
        this.notifyPropertyChange('labelNode');
      }.observes('*model.label'),

      /**
       * Clients expect to be able to get an array, even though we only ever have one labelNode.
       * @return {Array}
       */
      labelNodes: function() {
        var tLabelNode = this.get('labelNode');
        if( tLabelNode)
          return [ tLabelNode ];
        else
          return [];
      }.property('labelNode'),

      /**
       * @private
       * @property {Raphael element}
       */
      _labelNode: null,

      /**
       * @private
       * @property {Raphael element} Used to display continuous scale as a color gradient
       */
      _hiddenDragView: null,

      init: function() {
        sc_super();

        this.categoriesView = DG.CategoriesView.create( {
          classNames: 'dg-categories'.w(),
          layout: { left: kHMargin, right: kHMargin, top: kVMargin, bottom: kVMargin },
          isVisible: false,
          model: this.get('model'),
          rowHeight: DG.RenderingUtilities.kDefaultFontHeight
        });
        this.appendChild( this.categoriesView);

        this.choroplethView = DG.ChoroplethView.create( {
          classNames: 'dg-choropleth'.w(),
          layout: { left: kHMargin, right: kHMargin, top: kVMargin, bottom: kVMargin },
          isVisible: false,
          model: this.get('model')
        });
        this.appendChild( this.choroplethView);

        this._hiddenDragView = SC.LabelView.create({
          classNames: 'dg-drag-label'.w(),
          layout: {width: 100, height: 20, top: -50, left: 0},
          value: ''
        });
        this.appendChild( this._hiddenDragView);
      },

      displayDidChange: function() {
        sc_super();
        this.get('choroplethView').displayDidChange();
        this.get('categoriesView').displayDidChange();
      },

      doDraw: function doDraw() {

        /**
         * renderLabel - Render the attribute name centered
         */
        var renderLabel = function() {
          var tLabelNode = this.get('labelNode'),
              tLabelExtent = this.get('labelExtent'),
              tDescription = this.getPath('model.attributeDescription.attribute.description') + '—' +
                  'DG.LegendView.attributeTooltip'.loc();
          if( SC.none( tLabelNode))
            return;

          tLabelNode.get('_textElement').attr({ text: this.getPath('model.label'),
                            x: kHMargin, y: tLabelExtent.y / 2});
          tLabelNode.get('_textElement').attr({ title: tDescription});
        }.bind( this);

        var tCategoriesView = this.get('categoriesView'),
            tChoroplethView = this.get('choroplethView');
        renderLabel();
        switch( this.get('attributeType')) {
          case DG.Analysis.EAttributeType.eNumeric:
            tChoroplethView.set('isVisible', true);
            tCategoriesView.set('isVisible', false);
            tChoroplethView.adjust('top', kVMargin + this.get('labelExtent').y);
            break;
          case DG.Analysis.EAttributeType.eCategorical:
            tCategoriesView.adjust('top', kVMargin + this.get('labelExtent').y);
            tCategoriesView.set('isVisible', true);
            tChoroplethView.set('isVisible', false);
            break;
        }
      },

      /**
        Graph controller observes this property to detect that a drag has taken place.
        @property {collection:{DG.CollectionRecord}, attribute:{DG.Attribute}, text:{String}}
      */
        dragData: null,

      /**
        Attempt to assign the given attribute to this legend view.
        @param {SC.Drag} 'data' property contains 'collection', 'attribute', 'text' properties
        @param {SC.DRAG_LINK}
      */
      performDragOperation: function( iDragObject, iDragOp) {
        this.hideDropHint();
        this.set('dragData', iDragObject.data);
        return SC.DRAG_LINK;
      },

      /**
        @property { Number }  Takes into account any borders the parent views may have
        [SCBUG]
      */
      drawWidth: function() {
        return Math.max( 0, this.get('frame').width - 2 * DG.ViewUtilities.kBorderWidth);
      }.property('frame'),

      /**
       * isNumeric
       * @property {Boolean}
       */
      isNumeric: function() {
        return this.getPath('model.isNumeric');
      }.property(),

      isNumericDidChange: function() {
        // TODO: Check whether this function is necessary.
        // Is anyone listening for 'isNumeric' notifications from the view?
        // If so, they should be listening to the model instead.
        this.notifyPropertyChange('isNumeric');
      }.observes('*model.isNumeric'),

      /**
       * attributeType
       * @property {DG.Analysis.EAttributeType}
       */
      attributeType: function() {
        return this.getPath('model.attributeDescription.attributeType');
      }.property(),

      attributeTypeDidChange: function() {
        this.notifyPropertyChange('attributeType');
        this.displayDidChange();
      }.observes('*model.attributeDescription.attributeStats.attributeType'),

      selectionDidChange: function() {
        if( this.get('isNumeric')) {
          // not doing anything yet
        }
        else {
          var tSelectionMap = this.getPath('model.selectionMap'),
              tRectangles = this.get('rectangles');
          if( SC.none( tSelectionMap) || SC.none( tRectangles))
              return;
          DG.ObjectMap.forEach( tRectangles, function( iKey, iRect) {
            if( tSelectionMap[ iKey]) {
              iRect.addClass(DG.PlotUtilities.kLegendKeySelected);
            }
            else {
              iRect.removeClass(DG.PlotUtilities.kLegendKeySelected);
            }
          });
        }
      }.observes('model.selectionMap')

    };
  }()));

<commit_msg>Correct misspelling of 'choropleth'<commit_after>// ==========================================================================
//                            DG.LegendView
//
//  Author:   William Finzer
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

sc_require('components/graph/utilities/graph_drop_target');
sc_require('views/raphael_base');

/** @class  DG.LegendView - The base class view for a graph legend.

  @extends DG.RaphaelBaseView
*/
DG.LegendView = DG.RaphaelBaseView.extend( DG.GraphDropTarget,

  (function()
  {
    var kVMargin = 3,
        kHMargin = 6;

    /** @scope DG.LegendView.prototype */
    return {
      displayProperties: ['model.attributeDescription.attribute'],

      classNames: ['dg-legend-view'],

      /**
        The model on which this view is based.
        @property { DG.LegendModel }
      */
      model: null,

      /**
        A legend view is always horizontal
        @property { String }
      */
      orientation: 'horizontal',

      /**
       * @property {DG.CategoriesView}
       */
      categoriesView: null,

      /**
       * @property {DG.ChoroplethView}
       */
      choroplethView: null,

      /**
       * @property {DG.Attribute}
       */
      plottedAttribute: function() {
        return this.getPath('model.attributeDescription.attribute');
      }.property(),

      /**
       * For a numeric legend we just need a single row for the color gradient rectangle.
       * For a categorical legend, we'll put two categories in each row.
       *
        @property { Number }
      */
      desiredExtent: function() {
        var tLabelHeight = this.get('labelExtent').y,
            tExtent = tLabelHeight + 2 * kVMargin;
        switch( this.get('attributeType')) {
          case DG.Analysis.EAttributeType.eNumeric:
            tExtent += this.get('choroplethView').desiredExtent( tLabelHeight);
            break;
          case DG.Analysis.EAttributeType.eCategorical:
            tExtent += this.get('categoriesView').desiredExtent( tLabelHeight);
            break;
          case DG.Analysis.EAttributeType.eColor:
            // Only the label displays
            break;
        }
        return tExtent;
      }.property(),
      desiredExtentDidChange: function() {
        this.notifyPropertyChange('desiredExtent');
      }.observes('labelNode', '*model.numberOfCells'),

      /**
      Return the extent of the label
        @property {Point as in { x, y }}
      */
      labelExtent: function() {
        var	kMinHeight = DG.RenderingUtilities.kCaptionFontHeight,
            tLabelNode = this.get('labelNode'),
            tBox;
        if( !SC.none( tLabelNode)) {
          tBox = tLabelNode.get('bBox');
          return { x: isNaN(tBox.width) ? kMinHeight : Math.max( kMinHeight, tBox.width),
                   y: isNaN(tBox.height) ? kMinHeight : Math.max( kMinHeight, Math.ceil( tBox.height / 2) * 2) };
        }
        return { x: 0, y: kMinHeight};
      }.property('labelNode').cacheable(),

      /**
      The Raphael element used to display the label.
        @property {Raphael element}
      */
      labelNode: function() {
        var tChangeHappened = false,
            tText, tDescription;
        if( SC.none( this._paper))
          return;

        if( SC.none( this._labelNode)) {
          this._labelNode = DG.LabelNode.create({ paper: this._paper, rotation: 0,
            colorIndex: 0, numColors: 1,
            anchor: 'start'});
          this._labelNode.setDragLabelHandler( DG.DragLabelHandler.create({
            labelNode: this._labelNode,
            labelView: this._hiddenDragView,
            viewToAddTo: this,
            attributeDescription: this.getPath('model.attributeDescription'),
            attributeName: this.getPath('model.attributeDescription.attribute.name'),
            dataContext: this.getPath('model.dataConfiguration.dataContext')
          }) );

          tChangeHappened = true;
        }
        tText = this.getPath('model.label');
        // If the text has changed, we set it and notify
        if( tText !== this._labelNode.get('text')) {
          this._labelNode.set('text', tText );
          tChangeHappened = true;
        }
        tDescription = this.getPath('model.attributeDescription.attribute.description') + '—' +
                                    'DG.LegendView.attributeTooltip'.loc();
        if( tDescription !== this._labelNode.get('description')) {
          this._labelNode.set('description', tDescription );
          tChangeHappened = true;
        }
        if( tChangeHappened)
          this.notifyPropertyChange( 'labelNode', this._labelNode);

        if( SC.empty( tText))
          return null;
        else
          return this._labelNode;
      }.property(),

      labelNodeDidChange: function() {
        this.notifyPropertyChange('labelNode');
      }.observes('*model.label'),

      /**
       * Clients expect to be able to get an array, even though we only ever have one labelNode.
       * @return {Array}
       */
      labelNodes: function() {
        var tLabelNode = this.get('labelNode');
        if( tLabelNode)
          return [ tLabelNode ];
        else
          return [];
      }.property('labelNode'),

      /**
       * @private
       * @property {Raphael element}
       */
      _labelNode: null,

      /**
       * @private
       * @property {Raphael element} Used to display continuous scale as a color gradient
       */
      _hiddenDragView: null,

      init: function() {
        sc_super();

        this.categoriesView = DG.CategoriesView.create( {
          classNames: 'dg-categories'.w(),
          layout: { left: kHMargin, right: kHMargin, top: kVMargin, bottom: kVMargin },
          isVisible: false,
          model: this.get('model'),
          rowHeight: DG.RenderingUtilities.kDefaultFontHeight
        });
        this.appendChild( this.categoriesView);

        this.choroplethView = DG.ChoroplethView.create( {
          classNames: 'dg-choropleth'.w(),
          layout: { left: kHMargin, right: kHMargin, top: kVMargin, bottom: kVMargin },
          isVisible: false,
          model: this.get('model')
        });
        this.appendChild( this.choroplethView);

        this._hiddenDragView = SC.LabelView.create({
          classNames: 'dg-drag-label'.w(),
          layout: {width: 100, height: 20, top: -50, left: 0},
          value: ''
        });
        this.appendChild( this._hiddenDragView);
      },

      displayDidChange: function() {
        sc_super();
        this.get('choroplethView').displayDidChange();
        this.get('categoriesView').displayDidChange();
      },

      doDraw: function doDraw() {

        /**
         * renderLabel - Render the attribute name centered
         */
        var renderLabel = function() {
          var tLabelNode = this.get('labelNode'),
              tLabelExtent = this.get('labelExtent'),
              tDescription = this.getPath('model.attributeDescription.attribute.description') + '—' +
                  'DG.LegendView.attributeTooltip'.loc();
          if( SC.none( tLabelNode))
            return;

          tLabelNode.get('_textElement').attr({ text: this.getPath('model.label'),
                            x: kHMargin, y: tLabelExtent.y / 2});
          tLabelNode.get('_textElement').attr({ title: tDescription});
        }.bind( this);

        var tCategoriesView = this.get('categoriesView'),
            tChoroplethView = this.get('choroplethView');
        renderLabel();
        switch( this.get('attributeType')) {
          case DG.Analysis.EAttributeType.eNumeric:
            tChoroplethView.set('isVisible', true);
            tCategoriesView.set('isVisible', false);
            tChoroplethView.adjust('top', kVMargin + this.get('labelExtent').y);
            break;
          case DG.Analysis.EAttributeType.eCategorical:
            tCategoriesView.adjust('top', kVMargin + this.get('labelExtent').y);
            tCategoriesView.set('isVisible', true);
            tChoroplethView.set('isVisible', false);
            break;
        }
      },

      /**
        Graph controller observes this property to detect that a drag has taken place.
        @property {collection:{DG.CollectionRecord}, attribute:{DG.Attribute}, text:{String}}
      */
        dragData: null,

      /**
        Attempt to assign the given attribute to this legend view.
        @param {SC.Drag} 'data' property contains 'collection', 'attribute', 'text' properties
        @param {SC.DRAG_LINK}
      */
      performDragOperation: function( iDragObject, iDragOp) {
        this.hideDropHint();
        this.set('dragData', iDragObject.data);
        return SC.DRAG_LINK;
      },

      /**
        @property { Number }  Takes into account any borders the parent views may have
        [SCBUG]
      */
      drawWidth: function() {
        return Math.max( 0, this.get('frame').width - 2 * DG.ViewUtilities.kBorderWidth);
      }.property('frame'),

      /**
       * isNumeric
       * @property {Boolean}
       */
      isNumeric: function() {
        return this.getPath('model.isNumeric');
      }.property(),

      isNumericDidChange: function() {
        // TODO: Check whether this function is necessary.
        // Is anyone listening for 'isNumeric' notifications from the view?
        // If so, they should be listening to the model instead.
        this.notifyPropertyChange('isNumeric');
      }.observes('*model.isNumeric'),

      /**
       * attributeType
       * @property {DG.Analysis.EAttributeType}
       */
      attributeType: function() {
        return this.getPath('model.attributeDescription.attributeType');
      }.property(),

      attributeTypeDidChange: function() {
        this.notifyPropertyChange('attributeType');
        this.displayDidChange();
      }.observes('*model.attributeDescription.attributeStats.attributeType'),

      selectionDidChange: function() {
        if( this.get('isNumeric')) {
          // not doing anything yet
        }
        else {
          var tSelectionMap = this.getPath('model.selectionMap'),
              tRectangles = this.get('rectangles');
          if( SC.none( tSelectionMap) || SC.none( tRectangles))
              return;
          DG.ObjectMap.forEach( tRectangles, function( iKey, iRect) {
            if( tSelectionMap[ iKey]) {
              iRect.addClass(DG.PlotUtilities.kLegendKeySelected);
            }
            else {
              iRect.removeClass(DG.PlotUtilities.kLegendKeySelected);
            }
          });
        }
      }.observes('model.selectionMap')

    };
  }()));

<|endoftext|>


<commit_before>// Dean Attali 2016

var main = {

  bigImgEl : null,
  numImgs : null,
  scrollBoxCheck : false,

  init : function() {

    // Check if there is a scrollbox to initialize
    if ($("#scroll-box").length > 0 && Cookies.get('daScrollboxSubscribe3') === undefined) {
      if ($("article").length > 0) {
        main.scrollBoxCheck = Math.min(1500, $("article").offset().top + $("article").height() * 0.4);
        $("#scroll-box-close").click(function() {
          $("#scroll-box").fadeOut(500);
          $("body").removeClass("scroll-box-on");
          Cookies.set('daScrollboxSubscribe3', '1', { expires: 1 });
        });
      }
    }

    $(window).scroll(function() {
      // Shorten the navbar after scrolling a little bit down
      if ($(".navbar").offset().top > 50) {
        $(".navbar").addClass("top-nav-short");
      } else {
        $(".navbar").removeClass("top-nav-short");
      }

      // Check if the scrollbox should be made visible
      if (main.scrollBoxCheck) {
        if ($(window).scrollTop() > main.scrollBoxCheck) {
          setTimeout( function(){ $("#scroll-box").fadeIn(500); }, 500);
          main.scrollBoxCheck = false;
          $("body").addClass("scroll-box-on");
        }
      }

    });

    // On mobile, hide the avatar when expanding the navbar menu
    $('#main-navbar').on('show.bs.collapse', function () {
      $(".navbar").addClass("top-nav-expanded");
    });
    $('#main-navbar').on('hidden.bs.collapse', function () {
      $(".navbar").removeClass("top-nav-expanded");
    });

    // On mobile, when clicking on a multi-level navbar menu, show the child links
    $('#main-navbar').on("click", ".navlinks-parent", function(e) {
      var target = e.target;
      $.each($(".navlinks-parent"), function(key, value) {
        if (value == target) {
          $(value).parent().toggleClass("show-children");
        } else {
          $(value).parent().removeClass("show-children");
        }
      });
    });

    // show a message if there is one to show
    var qs = main.getQueryParams();
    if (qs.message) {
      $(".container")[0].innerHTML =
        '

' +
          '
' +
            qs.message +
        "

" +
        $(".container")[0].innerHTML;
    }

    // show the big header image
    main.initImgs();

    // set up Google Analytics event tracking
    if (typeof ga === "function") {
      $("a[data-ga-event]").click(function() {
        ga('send', 'event', $(this).data("ga-category"), $(this).data("ga-action"), $(this).data("ga-label"));
      });
    }
  },

  initImgs : function() {
    // If the page was large images to randomly select from, choose an image
    if ($("#header-big-imgs").length > 0) {
      main.bigImgEl = $("#header-big-imgs");
      main.numImgs = main.bigImgEl.attr("data-num-img");

      // 2fc73a3a967e97599c9763d05e564189
	    // set an initial image
	    var imgInfo = main.getImgInfo();
	    var src = imgInfo.src;
	    var desc = imgInfo.desc;
  	  main.setImg(src, desc);

	    // For better UX, prefetch the next image so that it will already be loaded when we want to show it
  	  var getNextImg = function() {
  	    var imgInfo = main.getImgInfo();
  	    var src = imgInfo.src;
  	    var desc = imgInfo.desc;

  		  var prefetchImg = new Image();
    		prefetchImg.src = src;
  		  // if I want to do something once the image is ready: `prefetchImg.onload = function(){}`

    		setTimeout(function() {
    		  var img = $("

").addClass("big-img-transition").css("background-image", 'url(' + src + ')');
    		  $(".intro-header.big-img").prepend(img);
    		  setTimeout(function(){ img.css("opacity", "1"); }, 50);

  		    // after the animation of fading in the new image is done, prefetch the next one
    		  //img.one("transitioned webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){
  		    setTimeout(function() {
  		      main.setImg(src, desc);
  			    img.remove();
    			  getNextImg();
  		    }, 1000);
    		  //});
    		}, 6000);
    	};

  	  // If there are multiple images, cycle through them
  	  if (main.numImgs > 1) {
    	  getNextImg();
  	  }
    }
  },

  getImgInfo : function() {
  	var randNum = Math.floor((Math.random() * main.numImgs) + 1);
    var src = main.bigImgEl.attr("data-img-src-" + randNum);
	  var desc = main.bigImgEl.attr("data-img-desc-" + randNum);

  	return {
  	  src : src,
  	  desc : desc
  	}
  },

  setImg : function(src, desc) {
  	$(".intro-header.big-img").css("background-image", 'url(' + src + ')');
  	if (typeof desc !== typeof undefined && desc !== false) {
  	  $(".img-desc").text(desc).show();
  	} else {
  	  $(".img-desc").hide();
  	}
  },

 // get the GET parameters in the URL
 getQueryParams : function() {
    var qs = document.location.search.replace(/\?/g, "&").split("+").join(" ");

    var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g;

    while (tokens = re.exec(qs)) {
      params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
    }

    return params;
 }
};

document.addEventListener('DOMContentLoaded', main.init);
<commit_msg>Update main.js<commit_after>// Dean Attali 2016

var main = {

  bigImgEl : null,
  numImgs : null,
  scrollBoxCheck : false,
  purpleAdsCheck : false,

  init : function() {

    // Check if there is a scrollbox to initialize
    if ($("#scroll-box").length > 0 && Cookies.get('daScrollboxSubscribe3') === undefined) {
      if ($("article").length > 0) {
        main.scrollBoxCheck = Math.min(1500, $("article").offset().top + $("article").height() * 0.4);
        $("#scroll-box-close").click(function() {
          $("#scroll-box").fadeOut(500);
          $("body").removeClass("scroll-box-on");
          Cookies.set('daScrollboxSubscribe3', '1', { expires: 1 });
        });
      }
    }

    if ($(window).width() < 750) {
      main.purpleAdsCheck = 1000;
      $("body").addClass("purpleads-hide");
    }

    $(window).scroll(function() {
      // Shorten the navbar after scrolling a little bit down
      if ($(".navbar").offset().top > 50) {
        $(".navbar").addClass("top-nav-short");
      } else {
        $(".navbar").removeClass("top-nav-short");
      }

      // Check if the scrollbox should be made visible
      if (main.scrollBoxCheck) {
        if ($(window).scrollTop() > main.scrollBoxCheck) {
          setTimeout( function(){ $("#scroll-box").fadeIn(500); }, 500);
          main.scrollBoxCheck = false;
          $("body").addClass("scroll-box-on");
        }
      }

    });

    // On mobile, hide the avatar when expanding the navbar menu
    $('#main-navbar').on('show.bs.collapse', function () {
      $(".navbar").addClass("top-nav-expanded");
    });
    $('#main-navbar').on('hidden.bs.collapse', function () {
      $(".navbar").removeClass("top-nav-expanded");
    });

    // On mobile, when clicking on a multi-level navbar menu, show the child links
    $('#main-navbar').on("click", ".navlinks-parent", function(e) {
      var target = e.target;
      $.each($(".navlinks-parent"), function(key, value) {
        if (value == target) {
          $(value).parent().toggleClass("show-children");
        } else {
          $(value).parent().removeClass("show-children");
        }
      });
    });

    // show a message if there is one to show
    var qs = main.getQueryParams();
    if (qs.message) {
      $(".container")[0].innerHTML =
        '

' +
          '
' +
            qs.message +
        "

" +
        $(".container")[0].innerHTML;
    }

    // show the big header image
    main.initImgs();

    // set up Google Analytics event tracking
    if (typeof ga === "function") {
      $("a[data-ga-event]").click(function() {
        ga('send', 'event', $(this).data("ga-category"), $(this).data("ga-action"), $(this).data("ga-label"));
      });
    }
  },

  initImgs : function() {
    // If the page was large images to randomly select from, choose an image
    if ($("#header-big-imgs").length > 0) {
      main.bigImgEl = $("#header-big-imgs");
      main.numImgs = main.bigImgEl.attr("data-num-img");

      // 2fc73a3a967e97599c9763d05e564189
	    // set an initial image
	    var imgInfo = main.getImgInfo();
	    var src = imgInfo.src;
	    var desc = imgInfo.desc;
  	  main.setImg(src, desc);

	    // For better UX, prefetch the next image so that it will already be loaded when we want to show it
  	  var getNextImg = function() {
  	    var imgInfo = main.getImgInfo();
  	    var src = imgInfo.src;
  	    var desc = imgInfo.desc;

  		  var prefetchImg = new Image();
    		prefetchImg.src = src;
  		  // if I want to do something once the image is ready: `prefetchImg.onload = function(){}`

    		setTimeout(function() {
    		  var img = $("

").addClass("big-img-transition").css("background-image", 'url(' + src + ')');
    		  $(".intro-header.big-img").prepend(img);
    		  setTimeout(function(){ img.css("opacity", "1"); }, 50);

  		    // after the animation of fading in the new image is done, prefetch the next one
    		  //img.one("transitioned webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){
  		    setTimeout(function() {
  		      main.setImg(src, desc);
  			    img.remove();
    			  getNextImg();
  		    }, 1000);
    		  //});
    		}, 6000);
    	};

  	  // If there are multiple images, cycle through them
  	  if (main.numImgs > 1) {
    	  getNextImg();
  	  }
    }
  },

  getImgInfo : function() {
  	var randNum = Math.floor((Math.random() * main.numImgs) + 1);
    var src = main.bigImgEl.attr("data-img-src-" + randNum);
	  var desc = main.bigImgEl.attr("data-img-desc-" + randNum);

  	return {
  	  src : src,
  	  desc : desc
  	}
  },

  setImg : function(src, desc) {
  	$(".intro-header.big-img").css("background-image", 'url(' + src + ')');
  	if (typeof desc !== typeof undefined && desc !== false) {
  	  $(".img-desc").text(desc).show();
  	} else {
  	  $(".img-desc").hide();
  	}
  },

 // get the GET parameters in the URL
 getQueryParams : function() {
    var qs = document.location.search.replace(/\?/g, "&").split("+").join(" ");

    var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g;

    while (tokens = re.exec(qs)) {
      params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
    }

    return params;
 }
};

document.addEventListener('DOMContentLoaded', main.init);
<|endoftext|>


<commit_before>/* global Life */
var cellColor = '#b58900';
var graveColor = '#586e75';
var canvasColor = '#073642';

var game = new Life(600, 450, 5);
game.canvas.style.backgroundColor = this.checked ? graveColor : canvasColor;
game.setColor('cellColor', cellColor);
game.setColor('canvasColor', canvasColor);
game.place('glider', 13, 1);
game.place('gosper', 22, 5);
game.place('gosper', 5, 22);
game.place('gosper', 78, 45);
game.place('gosper', 73, 10);
game.place('pulsar', 10, 67);

document.getElementById('life').appendChild(game.canvas);

document.getElementById('showGraves').onchange = function (e) {
  game.canvas.style.backgroundColor = this.checked ? graveColor : canvasColor;
};

document.getElementById('startBtn').onclick = function () {
  if (!game.isRunning()) {
    game.start();
    this.className = 'btn btn-danger';
    this.innerHTML = 'Stop';
  }
  else {
    game.stop();
    this.className = 'btn btn-success';
    this.innerHTML = 'Start';
  }
};
<commit_msg>Minor tweaks to main.js<commit_after>/* global Life */
var cellColor   = '#b58900';
var graveColor  = '#586e75';
var canvasColor = '#073642';

var game = new Life(600, 450, 5);
game.setColor('cellColor', cellColor);
game.setColor('canvasColor', canvasColor);
game.place('glider', 13,  1);
game.place('gosper', 22,  5);
game.place('gosper',  5, 22);
game.place('gosper', 78, 45);
game.place('gosper', 73, 10);
game.place('pulsar', 10, 67);

document.getElementById('life').appendChild(game.canvas);
game.canvas.style.backgroundColor = canvasColor;

document.getElementById('showGraves').onchange = function (e) {
  game.canvas.style.backgroundColor = this.checked ? graveColor : canvasColor;
};

document.getElementById('startBtn').onclick = function () {
  if (!game.isRunning()) {
    game.start();
    this.className = 'btn btn-danger';
    this.innerHTML = 'Stop';
  }
  else {
    game.stop();
    this.className = 'btn btn-success';
    this.innerHTML = 'Start';
  }
};
<|endoftext|>