<commit_before>
// TODO: This is really defined in the mode module. figure out how to get this double require level
function isTestMode() {
    var search = window.location.search;
    var matches = search.match(/test=([^&]*)&*/);
    if (matches && matches.length == 2) {
        if (matches[1] === "true") {
            return true;
        }
    }
    return false;
}

var questionsFile = "ryaml!config/questions";
if (isTestMode()) {
    var search = window.location.search;
    var matches = search.match(/questions=([^&]*)&*/);
    if (matches && matches.length === 2) {
        questionsFile = "ryaml!tests/functional/configs/" + matches[1];
    }
}

define (["lib/jquery", "lib/lodash", "lib/howler", "src/skinner/core/page", "src/skinner/core/loader", "src/skinner/core/keypath", questionsFile], function ($, _, howler, Page, loader, keyPath, allQuestionData) {
    "use strict";

    var States = {
        PreTest: 0,
        Test: 1,
        InlineTest: 2,
        PostTest: 3,
        ShowTestScore: 4,
        Exit: 5
    };

    function isQuestionGrouped(question) {
        var questionGroup = keyPath(question, "question group");
        return (!_.isUndefined(questionGroup));
    }

    var TestPage = Page.extend({
        init: function (data, task) {
            this._super(data, task);

            this.style = keyPath(this.data, "style", "multipleChoice");
            this.questionSet = keyPath(this.data, "question set");
            this.questionsData = allQuestionData[this.questionSet];
            this.order = keyPath(this.data, "order");
            this.requireCorrectAnswer = keyPath(this.data, "require correct answer", false);

            this.autoStartPageTimer = false;

            this.currentScore = 0;
            this.currentMaxScore = 0;

            this.testPerformsScoring = false;

            // Assign Question Ids
            var flattenedQuestions = _.flatten(_.map(this.questionsData, function (q) {
                if (isQuestionGrouped(q)) {
                    return keyPath(q, "questions", []);
                }
                else {
                    return q;
                }
            }));
            _.each(flattenedQuestions, function (q, index) {
                var displayIndex = index + 1;
                q.id = displayIndex.toString();
            });

            // TODO: Support randomizng inside a question group too
            if (this.order === "random") {
                this.questionsData = _.shuffle(this.questionsData);
            }

            this.state = States.PreTest;
        },
        id: function () {
            return this._super() + "-" + this.style + "-" + this.questionSet;
        },
        postShow: function () {
            console.log("Showing TestPage: " + this.style);

            this.nextState();
        },
        nextState: function () {
            if (this.state === States.PreTest) {
                if (keyPath(this.data, "inline", false)) {
                    this.state = States.InlineTest;
                    this.hasStartedInlineTest = false;
                }
                else {
                    this.state = States.Test;
                    this.currentQuestionIndex = -1;
                }

                this.nextState();
            }
            else if (this.state === States.Test) {
                this.currentQuestionIndex++;

                if (this.questionsData.length > this.currentQuestionIndex) {
                    this.showSingleQuestion(this.questionsData[this.currentQuestionIndex]);
                }
                else {
                    this.state = States.PostTest;
                    this.nextState();
                }
            }
            else if (this.state === States.InlineTest) {
                if (!this.hasStartedInlineTest) {
                    this.showAllQuestions();
                    this.hasStartedInlineTest = true;
                }
                else {
                    this.state = States.PostTest;
                    this.nextState();
                }
            }
            else if (this.state === States.PostTest) {
                this.onPostTest();

                if (keyPath(this.data, "show test results") === "on completion") {
                    this.state = States.ShowTestScore;
                    this.showTestScore();
                }
                else {
                    this.state = States.Exit;
                    this.nextState();
                }
            }
            else if (this.state === States.ShowTestScore) {
                this.state = States.Exit;
                this.nextState();
            }
            else if (this.state === States.Exit) {
                this.moveToNextPage();
            }
        },
        showQuestion: function (q, where, callback) {
            var base = this;

            var questionStyle = keyPath(q, "style", this.style);

            if (isQuestionGrouped(q)) {
                loader.loadModule(questionStyle, "question", function (Question) {
                    q.grouped = true;
                    var question = new Question(q, null, base.data, questionStyle);
                    question.show(where);
                    callback(question);
                });
            }
            else {
                loader.loadModule(questionStyle, "question", function (Question) {
                    var question = new Question(q, q.id, base.data, questionStyle);
                    question.show(where);
                    callback(question);
                });
            }
        },
        showSingleQuestion: function (q) {
            var base = this;
            this.showQuestion(q, "#test", function (question) {
                base.currentQuestion = question;
                base.startPageTimer();
                base.questionStartTime = _.now();
            });
        },
        showAllQuestions: function () {
            var base = this;

            this.currentQuestions = [];

            $("#test").addClass("inline");

            _.each(this.questionsData, function (q, index) {
                var elementId = "test_question_" + q.id;
                $("
", {
                    id: elementId,
                    class: "inline_question"
                }).appendTo("#test");

                base.showQuestion(q, "#" + elementId, function (question) {
                    base.currentQuestions[index] = question;
                });
            });

            // TODO: Can we get this to start after all questions have done their callbacks?
            this.startPageTimer();
            this.questionStartTime = _.now();
        },
        showTestScore: function () {
            // TODO: These should be exposed in experiment.yaml
            var bindings = {
                title: "Practice Test Score",
                content: "
Your score: " + this.currentScore + "

Max score: " + this.currentMaxScore + "
"
            };
            loader.loadLayoutInPackage("testresults", "src/skinner/core/", bindings, "#test");

            // TODO: This is a super hack!!!!!
             _.extend(this.data, { "next": { "button": "Next" } });
            this.updateButtons();
        },
        onPostTest: function () {
            if (this.testPerformsScoring) {
                var pageId = this.id();
                var contextId = "final";
                this.task.subject.report(pageId, contextId, "final score", this.currentScore);
                this.task.subject.report(pageId, contextId, "final max score", this.currentMaxScore);
            }
        },
        next: function () {
            var base = this;
            function playOptionalSound(soundFile) {
                if (!_.isUndefined(soundFile)) {
                    new howler.Howl({
                        urls: ["content/sounds/" + soundFile]
                    }).play();
                }
            }

            var pageId = this.id();
            var questionEndTime = _.now();
            var questionTime = questionEndTime - this.questionStartTime;

            var reportResponseTime = keyPath(this.data, "report.response time", true);

            // TODO: This can use a lot of refactoring!!. lots of repetition
            if (this.state === States.InlineTest) {
                this.cancelPageTimer();
                _.each(this.currentQuestions, function (question) {
                    if (keyPath(question.data, "grouped", false)) {
                        if (keyPath(base.data, "report results", true)) {
                            question.reportResults(base.task.subject, pageId);
                            question.reportGroupedResults(base.task.subject, pageId);
                        }
                    }
                    else {
                        var isCorrect = question.isCorrect();

                        var performsScoring = question.performsScoring();
                        var currentQuestionScore = 0;
                        var currentQuestionMaxScore = 0;
                        if (performsScoring) {
                            this.testPerformsScoring = true;
                            currentQuestionScore = question.tallyScore();
                            currentQuestionMaxScore = question.maxScore();

                            base.currentScore += currentQuestionScore;
                            base.currentMaxScore += currentQuestionMaxScore;
                        }

                        if (keyPath(base.data, "report results", true)) {
                            var contextId = question.id;
                            base.task.subject.report(pageId, contextId, "answer", question.selectedAnswer());
                            if (!_.isEmpty(question.correctAnswers())) {
                                base.task.subject.report(pageId, contextId, "correct answer", question.correctAnswers());
                            }
                            if (performsScoring) {
                                base.task.subject.report(pageId, contextId, "score", currentQuestionScore);
                                base.task.subject.report(pageId, contextId, "max score", currentQuestionMaxScore);
                            }
                            if (reportResponseTime) {
                                base.task.subject.report(pageId, contextId, "time(ms)", questionTime);
                            }
                            question.reportResults(base.task.subject, pageId);
                        }
                    }
                });
            }
            else if (this.state === States.Test) {
                this.cancelPageTimer();
                if (keyPath(this.currentQuestion.data, "grouped", false)) {
                    if (keyPath(this.data, "report results", true)) {
                        this.currentQuestion.reportResults(this.task.subject, pageId);
                        this.currentQuestion.reportGroupedResults(this.task.subject, pageId);
                    }
                }
                else {
                    var incorrectMessageId = "__incorrectAnswerMessage";

                    $("#" + incorrectMessageId).remove();

                    var isCorrect = this.currentQuestion.isCorrect();

                    if (this.requireCorrectAnswer && !isCorrect) {
                        var incorrectMessage = keyPath(this.data, "incorrect answer message", "Incorrect");
                        // Show incorrect answer message.
                        $("
", {
                            id: incorrectMessageId,
                            class: "ui red message",
                            text: incorrectMessage
                        }).appendTo("#test");
                        return;
                    }

                    if (isCorrect) {
                        playOptionalSound(this.data["correct sound"]);
                    }
                    else {
                        playOptionalSound(this.data["incorrect sound"]);
                    }

                    var performsScoring = this.currentQuestion.performsScoring();
                    var currentQuestionScore = 0;
                    var currentQuestionMaxScore = 0;
                    if (performsScoring) {
                        this.testPerformsScoring = true;
                        currentQuestionScore = this.currentQuestion.tallyScore();
                        currentQuestionMaxScore = this.currentQuestion.maxScore();

                        this.currentScore += currentQuestionScore;
                        this.currentMaxScore += currentQuestionMaxScore;
                    }

                    if (keyPath(this.data, "report results", true)) {
                        var contextId = this.currentQuestion.id;
                        this.task.subject.report(pageId, contextId, "answer", this.currentQuestion.selectedAnswer());
                        if (!_.isEmpty(this.currentQuestion.correctAnswers())) {
                            this.task.subject.report(pageId, contextId, "correct answer", this.currentQuestion.correctAnswers());
                        }
                        if (performsScoring) {
                            this.task.subject.report(pageId, contextId, "score", currentQuestionScore);
                            this.task.subject.report(pageId, contextId, "max score", currentQuestionMaxScore);
                        }
                        if (reportResponseTime) {
                            this.task.subject.report(pageId, contextId, "time(ms)", questionTime);
                        }
                        this.currentQuestion.reportResults(this.task.subject, pageId);
                    }
                }
            }

            this.nextState();
        }
    });

    return TestPage;
});
<commit_msg>fix bug when running the same questions multiple times<commit_after>
// TODO: This is really defined in the mode module. figure out how to get this double require level
function isTestMode() {
    var search = window.location.search;
    var matches = search.match(/test=([^&]*)&*/);
    if (matches && matches.length == 2) {
        if (matches[1] === "true") {
            return true;
        }
    }
    return false;
}

var questionsFile = "ryaml!config/questions";
if (isTestMode()) {
    var search = window.location.search;
    var matches = search.match(/questions=([^&]*)&*/);
    if (matches && matches.length === 2) {
        questionsFile = "ryaml!tests/functional/configs/" + matches[1];
    }
}

define (["lib/jquery", "lib/lodash", "lib/howler", "src/skinner/core/page", "src/skinner/core/loader", "src/skinner/core/keypath", questionsFile], function ($, _, howler, Page, loader, keyPath, allQuestionData) {
    "use strict";

    var States = {
        PreTest: 0,
        Test: 1,
        InlineTest: 2,
        PostTest: 3,
        ShowTestScore: 4,
        Exit: 5
    };

    function isQuestionGrouped(question) {
        var questionGroup = keyPath(question, "question group");
        return (!_.isUndefined(questionGroup));
    }

    var TestPage = Page.extend({
        init: function (data, task) {
            this._super(data, task);

            this.style = keyPath(this.data, "style", "multipleChoice");
            this.questionSet = keyPath(this.data, "question set");
            this.questionsData = allQuestionData[this.questionSet];
            this.order = keyPath(this.data, "order");
            this.requireCorrectAnswer = keyPath(this.data, "require correct answer", false);

            this.autoStartPageTimer = false;

            this.currentScore = 0;
            this.currentMaxScore = 0;

            this.testPerformsScoring = false;

            // Assign Question Ids
            var flattenedQuestions = _.flatten(_.map(this.questionsData, function (q) {
                if (isQuestionGrouped(q)) {
                    return keyPath(q, "questions", []);
                }
                else {
                    return q;
                }
            }));
            _.each(flattenedQuestions, function (q, index) {
                var displayIndex = index + 1;
                q.id = displayIndex.toString();
            });

            // TODO: Support randomizng inside a question group too
            if (this.order === "random") {
                this.questionsData = _.shuffle(this.questionsData);
            }

            this.state = States.PreTest;
        },
        id: function () {
            return this._super() + "-" + this.style + "-" + this.questionSet;
        },
        postShow: function () {
            console.log("Showing TestPage: " + this.style);

            this.nextState();
        },
        nextState: function () {
            if (this.state === States.PreTest) {
                if (keyPath(this.data, "inline", false)) {
                    this.state = States.InlineTest;
                    this.hasStartedInlineTest = false;
                }
                else {
                    this.state = States.Test;
                    this.currentQuestionIndex = -1;
                }

                this.nextState();
            }
            else if (this.state === States.Test) {
                this.currentQuestionIndex++;

                if (this.questionsData.length > this.currentQuestionIndex) {
                    this.showSingleQuestion(this.questionsData[this.currentQuestionIndex]);
                }
                else {
                    this.state = States.PostTest;
                    this.nextState();
                }
            }
            else if (this.state === States.InlineTest) {
                if (!this.hasStartedInlineTest) {
                    this.showAllQuestions();
                    this.hasStartedInlineTest = true;
                }
                else {
                    this.state = States.PostTest;
                    this.nextState();
                }
            }
            else if (this.state === States.PostTest) {
                this.onPostTest();

                if (keyPath(this.data, "show test results") === "on completion") {
                    this.state = States.ShowTestScore;
                    this.showTestScore();
                }
                else {
                    this.state = States.Exit;
                    this.nextState();
                }
            }
            else if (this.state === States.ShowTestScore) {
                this.state = States.Exit;
                this.nextState();
            }
            else if (this.state === States.Exit) {
                this.moveToNextPage();
            }
        },
        showQuestion: function (q, where, callback) {

            // Make a full copy of q, so we don't modify the static
            // question data held in questionData
            q = _.cloneDeep(q);

            var base = this;

            var questionStyle = keyPath(q, "style", this.style);

            if (isQuestionGrouped(q)) {
                loader.loadModule(questionStyle, "question", function (Question) {
                    q.grouped = true;
                    var question = new Question(q, null, base.data, questionStyle);
                    question.show(where);
                    callback(question);
                });
            }
            else {
                loader.loadModule(questionStyle, "question", function (Question) {
                    var question = new Question(q, q.id, base.data, questionStyle);
                    question.show(where);
                    callback(question);
                });
            }
        },
        showSingleQuestion: function (q) {
            var base = this;
            this.showQuestion(q, "#test", function (question) {
                base.currentQuestion = question;
                base.startPageTimer();
                base.questionStartTime = _.now();
            });
        },
        showAllQuestions: function () {
            var base = this;

            this.currentQuestions = [];

            $("#test").addClass("inline");

            _.each(this.questionsData, function (q, index) {
                var elementId = "test_question_" + q.id;
                $("
", {
                    id: elementId,
                    class: "inline_question"
                }).appendTo("#test");

                base.showQuestion(q, "#" + elementId, function (question) {
                    base.currentQuestions[index] = question;
                });
            });

            // TODO: Can we get this to start after all questions have done their callbacks?
            this.startPageTimer();
            this.questionStartTime = _.now();
        },
        showTestScore: function () {
            // TODO: These should be exposed in experiment.yaml
            var bindings = {
                title: "Practice Test Score",
                content: "
Your score: " + this.currentScore + "

Max score: " + this.currentMaxScore + "
"
            };
            loader.loadLayoutInPackage("testresults", "src/skinner/core/", bindings, "#test");

            // TODO: This is a super hack!!!!!
             _.extend(this.data, { "next": { "button": "Next" } });
            this.updateButtons();
        },
        onPostTest: function () {
            if (this.testPerformsScoring) {
                var pageId = this.id();
                var contextId = "final";
                this.task.subject.report(pageId, contextId, "final score", this.currentScore);
                this.task.subject.report(pageId, contextId, "final max score", this.currentMaxScore);
            }
        },
        next: function () {
            var base = this;
            function playOptionalSound(soundFile) {
                if (!_.isUndefined(soundFile)) {
                    new howler.Howl({
                        urls: ["content/sounds/" + soundFile]
                    }).play();
                }
            }

            var pageId = this.id();
            var questionEndTime = _.now();
            var questionTime = questionEndTime - this.questionStartTime;

            var reportResponseTime = keyPath(this.data, "report.response time", true);

            // TODO: This can use a lot of refactoring!!. lots of repetition
            if (this.state === States.InlineTest) {
                this.cancelPageTimer();
                _.each(this.currentQuestions, function (question) {
                    if (keyPath(question.data, "grouped", false)) {
                        if (keyPath(base.data, "report results", true)) {
                            question.reportResults(base.task.subject, pageId);
                            question.reportGroupedResults(base.task.subject, pageId);
                        }
                    }
                    else {
                        var isCorrect = question.isCorrect();

                        var performsScoring = question.performsScoring();
                        var currentQuestionScore = 0;
                        var currentQuestionMaxScore = 0;
                        if (performsScoring) {
                            this.testPerformsScoring = true;
                            currentQuestionScore = question.tallyScore();
                            currentQuestionMaxScore = question.maxScore();

                            base.currentScore += currentQuestionScore;
                            base.currentMaxScore += currentQuestionMaxScore;
                        }

                        if (keyPath(base.data, "report results", true)) {
                            var contextId = question.id;
                            base.task.subject.report(pageId, contextId, "answer", question.selectedAnswer());
                            if (!_.isEmpty(question.correctAnswers())) {
                                base.task.subject.report(pageId, contextId, "correct answer", question.correctAnswers());
                            }
                            if (performsScoring) {
                                base.task.subject.report(pageId, contextId, "score", currentQuestionScore);
                                base.task.subject.report(pageId, contextId, "max score", currentQuestionMaxScore);
                            }
                            if (reportResponseTime) {
                                base.task.subject.report(pageId, contextId, "time(ms)", questionTime);
                            }
                            question.reportResults(base.task.subject, pageId);
                        }
                    }
                });
            }
            else if (this.state === States.Test) {
                this.cancelPageTimer();
                if (keyPath(this.currentQuestion.data, "grouped", false)) {
                    if (keyPath(this.data, "report results", true)) {
                        this.currentQuestion.reportResults(this.task.subject, pageId);
                        this.currentQuestion.reportGroupedResults(this.task.subject, pageId);
                    }
                }
                else {
                    var incorrectMessageId = "__incorrectAnswerMessage";

                    $("#" + incorrectMessageId).remove();

                    var isCorrect = this.currentQuestion.isCorrect();

                    if (this.requireCorrectAnswer && !isCorrect) {
                        var incorrectMessage = keyPath(this.data, "incorrect answer message", "Incorrect");
                        // Show incorrect answer message.
                        $("
", {
                            id: incorrectMessageId,
                            class: "ui red message",
                            text: incorrectMessage
                        }).appendTo("#test");
                        return;
                    }

                    if (isCorrect) {
                        playOptionalSound(this.data["correct sound"]);
                    }
                    else {
                        playOptionalSound(this.data["incorrect sound"]);
                    }

                    var performsScoring = this.currentQuestion.performsScoring();
                    var currentQuestionScore = 0;
                    var currentQuestionMaxScore = 0;
                    if (performsScoring) {
                        this.testPerformsScoring = true;
                        currentQuestionScore = this.currentQuestion.tallyScore();
                        currentQuestionMaxScore = this.currentQuestion.maxScore();

                        this.currentScore += currentQuestionScore;
                        this.currentMaxScore += currentQuestionMaxScore;
                    }

                    if (keyPath(this.data, "report results", true)) {
                        var contextId = this.currentQuestion.id;
                        this.task.subject.report(pageId, contextId, "answer", this.currentQuestion.selectedAnswer());
                        if (!_.isEmpty(this.currentQuestion.correctAnswers())) {
                            this.task.subject.report(pageId, contextId, "correct answer", this.currentQuestion.correctAnswers());
                        }
                        if (performsScoring) {
                            this.task.subject.report(pageId, contextId, "score", currentQuestionScore);
                            this.task.subject.report(pageId, contextId, "max score", currentQuestionMaxScore);
                        }
                        if (reportResponseTime) {
                            this.task.subject.report(pageId, contextId, "time(ms)", questionTime);
                        }
                        this.currentQuestion.reportResults(this.task.subject, pageId);
                    }
                }
            }

            this.nextState();
        }
    });

    return TestPage;
});
<|endoftext|>


<commit_before>var Class = require('../utils/Class');
var NOOP = require('../utils/NOOP');
var EventEmitter = require('eventemitter3');
/*!
 * @author Pavle Goloskokovic <pgoloskokovic@gmail.com> (http://prunegames.com)
 */
var BaseSoundManager = new Class({
    Extends: EventEmitter,
    /**
     * The sound manager is responsible for playing back audio via Web Audio API or HTML Audio tag as fallback.
     * The audio file type and the encoding of those files are extremely important.
     * Not all browsers can play all audio formats.
     * There is a good guide to what's supported [here](https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery/Cross-browser_audio_basics#Audio_Codec_Support).
     *
     * @class Phaser.Sound.BaseSoundManager
     * @constructor
     * @param {Phaser.Game} game - Reference to the current game instance.
     */
    initialize: function BaseSoundManager(game) {
        EventEmitter.call(this);
        /**
         * Local reference to game.
         *
         * @readonly
         * @property {Phaser.Game} game
         */
        this.game = game;
        /**
         * An array containing all added sounds.
         *
         * @private
         * @property {ISound[]} sounds
         * @default []
         */
        this.sounds = [];
        /**
         * Global mute setting.
         *
         * @property {boolean} mute
         * @default false
         */
        this.mute = false;
        /**
         * Global volume setting.
         *
         * @property {number} volume
         * @default 1
         */
        this.volume = 1;
        /**
         * Global playback rate at which all the sounds will be played.
         * Value of 1.0 plays the audio at full speed, 0.5 plays the audio at half speed
         * and 2.0 doubles the audio's playback speed.
         *
         * @property {number} rate
         * @default 1
         */
        this.rate = 1;
        /**
         * Global detuning of all sounds in [cents](https://en.wikipedia.org/wiki/Cent_%28music%29).
         * The range of the value is -1200 to 1200, but we recommend setting it to [50](https://en.wikipedia.org/wiki/50_Cent).
         *
         * @property {number} detune
         * @default 0
         */
        this.detune = 0;
        /**
         * Flag indicating if sounds should be paused when game looses focus,
         * for instance when user switches to another tab/program/app.
         *
         * @property {boolean} pauseOnBlur
         * @default true
         */
        this.pauseOnBlur = true;
        game.events.on('blur', function () {
            if (this.pauseOnBlur) {
                this.onBlur();
            }
        }, this);
        game.events.on('focus', function () {
            if (this.pauseOnBlur) {
                this.onFocus();
            }
        }, this);
        /**
         * Property that actually holds the value of global playback rate.
         *
         * @private
         * @property {number} _rate
         * @default 1
         */
        this._rate = 1;
        /**
         * Property that actually holds the value of global detune.
         *
         * @private
         * @property {number} _detune
         * @default 0
         */
        this._detune = 0;
        /**
         * Mobile devices require sounds to be triggered from an explicit user action,
         * such as a tap, before any sound can be loaded/played on a web page.
         * Set to true if the audio system is currently locked awaiting user interaction.
         *
         * @readonly
         * @property {boolean} locked
         */
        this.locked = this.locked || false;
        /**
         * Flag used internally for handling when the audio system
         * has been unlocked, if there ever was a need for it.
         *
         * @private
         * @property {boolean} unlocked
         * @default false
         */
        this.unlocked = false;
        if (this.locked) {
            this.unlock();
        }
        else {
            this.emit('ready', this);
        }
    },
    /**
     * Adds a new sound into the sound manager.
     *
     * @override
     * @method Phaser.Sound.BaseSoundManager#add
     * @param {string} key - Asset key for the sound.
     * @param {ISoundConfig} [config] - An optional config object containing default sound settings.
     * @returns {ISound} The new sound instance.
     */
    add: NOOP,
    /**
     * Adds a new audio sprite sound into the sound manager.
     *
     * @method Phaser.Sound.BaseSoundManager#addAudioSprite
     * @param {string} key - Asset key for the sound.
     * @param {ISoundConfig} [config] - An optional config object containing default sound settings.
     * @returns {IAudioSpriteSound} The new audio sprite sound instance.
     */
    addAudioSprite: function (key, config) {
        var sound = this.add(key, config);
        /**
         * Local reference to 'spritemap' object form json file generated by audiosprite tool.
         *
         * @property {object} spritemap
         */
        sound.spritemap = this.game.cache.json.get(key).spritemap;
        for (var markerName in sound.spritemap) {
            if (!sound.spritemap.hasOwnProperty(markerName)) {
                continue;
            }
            var marker = sound.spritemap[markerName];
            sound.addMarker({
                name: markerName,
                start: marker.start,
                duration: marker.end - marker.start,
                config: config
            });
        }
        return sound;
    },
    /**
     * Enables playing sound on the fly without the need to keep a reference to it.
     * Sound will auto destroy once its playback ends.
     *
     * @method Phaser.Sound.BaseSoundManager#play
     * @param {string} key - Asset key for the sound.
     * @param {ISoundConfig | ISoundMarker} [extra] - An optional additional object containing settings to be applied to the sound. It could be either config or marker object.
     */
    play: function (key, extra) {
        var sound = this.add(key);
        // TODO document all events
        sound.once('ended', sound.destroy, sound);
        if (extra) {
            if (extra.name) {
                sound.addMarker(extra);
                sound.play(extra.name);
            }
            else {
                sound.play(extra);
            }
        }
        else {
            sound.play();
        }
    },
    /**
     * Enables playing audio sprite sound on the fly without the need to keep a reference to it.
     * Sound will auto destroy once its playback ends.
     *
     * @method Phaser.Sound.BaseSoundManager#playAudioSprite
     * @param {string} key - Asset key for the sound.
     * @param {string} spriteName - The name of the sound sprite to play.
     * @param {ISoundConfig} [config] - An optional config object containing default sound settings.
     */
    playAudioSprite: function (key, spriteName, config) {
        var sound = this.addAudioSprite(key);
        sound.once('ended', sound.destroy, sound);
        sound.play(spriteName, config);
    },
    /**
     * Removes a sound from the sound manager.
     * The removed sound is destroyed before removal.
     *
     * @method Phaser.Sound.BaseSoundManager#remove
     * @param {ISound} sound - The sound object to remove.
     * @returns {boolean} True if the sound was removed successfully, otherwise false.
     */
    remove: function (sound) {
        var index = this.sounds.indexOf(sound);
        if (index !== -1) {
            sound.destroy();
            this.sounds.splice(index, 1);
            return true;
        }
        return false;
    },
    /**
     * Removes all sounds from the sound manager that have an asset key matching the given value.
     * The removed sounds are destroyed before removal.
     *
     * @method Phaser.Sound.BaseSoundManager#removeByKey
     * @param {string} key - The key to match when removing sound objects.
     * @returns {number} The number of matching sound objects that were removed.
     */
    removeByKey: function (key) {
        var removed = 0;
        for (var i = this.sounds.length - 1; i >= 0; i--) {
            var sound = this.sounds[i];
            if (sound.key === key) {
                sound.destroy();
                this.sounds.splice(i, 1);
                removed++;
            }
        }
        return removed;
    },
    /**
     * Pauses all the sounds in the game.
     *
     * @method Phaser.Sound.BaseSoundManager#pauseAll
     */
    pauseAll: function () {
        this.forEachActiveSound(function (sound) {
            sound.pause();
        });
        this.emit('pauseall', this);
    },
    /**
     * Resumes all the sounds in the game.
     *
     * @method Phaser.Sound.BaseSoundManager#resumeAll
     */
    resumeAll: function () {
        this.forEachActiveSound(function (sound) {
            sound.resume();
        });
        this.emit('resumeall', this);
    },
    /**
     * Stops all the sounds in the game.
     *
     * @method Phaser.Sound.BaseSoundManager#stopAll
     */
    stopAll: function () {
        this.forEachActiveSound(function (sound) {
            sound.stop();
        });
        this.emit('stopall', this);
    },
    /**
     * Method used internally for unlocking audio playback on devices that
     * require user interaction before any sound can be played on a web page.
     *
     * Read more about how this issue is handled here in [this article](TODO add link).
     *
     * @override
     * @protected
     * @method Phaser.Sound.BaseSoundManager#unlock
     */
    unlock: NOOP,
    /**
     * Method used internally for pausing sound manager if
     * Phaser.Sound.BaseSoundManager#pauseOnBlur is set to true.
     *
     * @override
     * @protected
     * @method Phaser.Sound.BaseSoundManager#onBlur
     */
    onBlur: NOOP,
    /**
     * Method used internally for resuming sound manager if
     * Phaser.Sound.BaseSoundManager#pauseOnBlur is set to true.
     *
     * @override
     * @protected
     * @method Phaser.Sound.BaseSoundManager#onFocus
     */
    onFocus: NOOP,
    /**
     * Update method called on every game step.
     * Removes destroyed sounds and updates every active sound in the game.
     *
     * @protected
     * @method Phaser.Sound.BaseSoundManager#update
     * @param {number} time - The current timestamp as generated by the Request Animation Frame or SetTimeout.
     * @param {number} delta - The delta time elapsed since the last frame.
     */
    update: function (time, delta) {
        if (this.unlocked) {
            this.unlocked = false;
            this.locked = false;
            this.emit('unlocked', this);
        }
        for (var i = this.sounds.length - 1; i >= 0; i--) {
            if (this.sounds[i].pendingRemove) {
                this.sounds.splice(i, 1);
            }
        }
        this.sounds.forEach(function (sound) {
            sound.update(time, delta);
        });
    },
    /**
     * Destroys all the sounds in the game and all associated events.
     *
     * @method Phaser.Sound.BaseSoundManager#destroy
     */
    destroy: function () {
        this.game = null;
        this.removeAllListeners();
        this.forEachActiveSound(function (sound) {
            sound.destroy();
        });
        this.sounds.length = 0;
        this.sounds = null;
    },
    /**
     * Method used internally for iterating only over active sounds and skipping sounds that are marked for removal.
     *
     * @private
     * @method Phaser.Sound.BaseSoundManager#forEachActiveSound
     * @param {(sound: ISound, index: number, array: ISound[]) => void} callbackfn - Callback function.
     * @param [thisArg=this] - Callback context.
     */
    forEachActiveSound: function (callbackfn, thisArg) {
        var _this = this;
        this.sounds.forEach(function (sound, index) {
            if (!sound.pendingRemove) {
                callbackfn.call(thisArg || _this, sound, index, _this.sounds);
            }
        });
    }
});
/**
 * Global playback rate.
 *
 * @name Phaser.Sound.BaseSoundManager#rate
 * @property {number} rate
 */
Object.defineProperty(BaseSoundManager.prototype, 'rate', {
    get: function () {
        return this._rate;
    },
    set: function (value) {
        this._rate = value;
        this.forEachActiveSound(function (sound) {
            sound.setRate();
        });
        this.emit('rate', this, value);
    }
});
/**
 * Global detune.
 *
 * @name Phaser.Sound.BaseSoundManager#detune
 * @property {number} detune
 */
Object.defineProperty(BaseSoundManager.prototype, 'detune', {
    get: function () {
        return this._detune;
    },
    set: function (value) {
        this._detune = value;
        this.forEachActiveSound(function (sound) {
            sound.setRate();
        });
        this.emit('detune', this, value);
    }
});
module.exports = BaseSoundManager;
<commit_msg>Emitting ready event when sound manager gets unlocked<commit_after>var Class = require('../utils/Class');
var NOOP = require('../utils/NOOP');
var EventEmitter = require('eventemitter3');
/*!
 * @author Pavle Goloskokovic <pgoloskokovic@gmail.com> (http://prunegames.com)
 */
var BaseSoundManager = new Class({
    Extends: EventEmitter,
    /**
     * The sound manager is responsible for playing back audio via Web Audio API or HTML Audio tag as fallback.
     * The audio file type and the encoding of those files are extremely important.
     * Not all browsers can play all audio formats.
     * There is a good guide to what's supported [here](https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery/Cross-browser_audio_basics#Audio_Codec_Support).
     *
     * @class Phaser.Sound.BaseSoundManager
     * @constructor
     * @param {Phaser.Game} game - Reference to the current game instance.
     */
    initialize: function BaseSoundManager(game) {
        EventEmitter.call(this);
        /**
         * Local reference to game.
         *
         * @readonly
         * @property {Phaser.Game} game
         */
        this.game = game;
        /**
         * An array containing all added sounds.
         *
         * @private
         * @property {ISound[]} sounds
         * @default []
         */
        this.sounds = [];
        /**
         * Global mute setting.
         *
         * @property {boolean} mute
         * @default false
         */
        this.mute = false;
        /**
         * Global volume setting.
         *
         * @property {number} volume
         * @default 1
         */
        this.volume = 1;
        /**
         * Global playback rate at which all the sounds will be played.
         * Value of 1.0 plays the audio at full speed, 0.5 plays the audio at half speed
         * and 2.0 doubles the audio's playback speed.
         *
         * @property {number} rate
         * @default 1
         */
        this.rate = 1;
        /**
         * Global detuning of all sounds in [cents](https://en.wikipedia.org/wiki/Cent_%28music%29).
         * The range of the value is -1200 to 1200, but we recommend setting it to [50](https://en.wikipedia.org/wiki/50_Cent).
         *
         * @property {number} detune
         * @default 0
         */
        this.detune = 0;
        /**
         * Flag indicating if sounds should be paused when game looses focus,
         * for instance when user switches to another tab/program/app.
         *
         * @property {boolean} pauseOnBlur
         * @default true
         */
        this.pauseOnBlur = true;
        game.events.on('blur', function () {
            if (this.pauseOnBlur) {
                this.onBlur();
            }
        }, this);
        game.events.on('focus', function () {
            if (this.pauseOnBlur) {
                this.onFocus();
            }
        }, this);
        /**
         * Property that actually holds the value of global playback rate.
         *
         * @private
         * @property {number} _rate
         * @default 1
         */
        this._rate = 1;
        /**
         * Property that actually holds the value of global detune.
         *
         * @private
         * @property {number} _detune
         * @default 0
         */
        this._detune = 0;
        /**
         * Mobile devices require sounds to be triggered from an explicit user action,
         * such as a tap, before any sound can be loaded/played on a web page.
         * Set to true if the audio system is currently locked awaiting user interaction.
         *
         * @readonly
         * @property {boolean} locked
         */
        this.locked = this.locked || false;
        /**
         * Flag used internally for handling when the audio system
         * has been unlocked, if there ever was a need for it.
         *
         * @private
         * @property {boolean} unlocked
         * @default false
         */
        this.unlocked = false;
        if (this.locked) {
            this.unlock();
        }
        else {
            this.emit('ready', this);
        }
    },
    /**
     * Adds a new sound into the sound manager.
     *
     * @override
     * @method Phaser.Sound.BaseSoundManager#add
     * @param {string} key - Asset key for the sound.
     * @param {ISoundConfig} [config] - An optional config object containing default sound settings.
     * @returns {ISound} The new sound instance.
     */
    add: NOOP,
    /**
     * Adds a new audio sprite sound into the sound manager.
     *
     * @method Phaser.Sound.BaseSoundManager#addAudioSprite
     * @param {string} key - Asset key for the sound.
     * @param {ISoundConfig} [config] - An optional config object containing default sound settings.
     * @returns {IAudioSpriteSound} The new audio sprite sound instance.
     */
    addAudioSprite: function (key, config) {
        var sound = this.add(key, config);
        /**
         * Local reference to 'spritemap' object form json file generated by audiosprite tool.
         *
         * @property {object} spritemap
         */
        sound.spritemap = this.game.cache.json.get(key).spritemap;
        for (var markerName in sound.spritemap) {
            if (!sound.spritemap.hasOwnProperty(markerName)) {
                continue;
            }
            var marker = sound.spritemap[markerName];
            sound.addMarker({
                name: markerName,
                start: marker.start,
                duration: marker.end - marker.start,
                config: config
            });
        }
        return sound;
    },
    /**
     * Enables playing sound on the fly without the need to keep a reference to it.
     * Sound will auto destroy once its playback ends.
     *
     * @method Phaser.Sound.BaseSoundManager#play
     * @param {string} key - Asset key for the sound.
     * @param {ISoundConfig | ISoundMarker} [extra] - An optional additional object containing settings to be applied to the sound. It could be either config or marker object.
     */
    play: function (key, extra) {
        var sound = this.add(key);
        // TODO document all events
        sound.once('ended', sound.destroy, sound);
        if (extra) {
            if (extra.name) {
                sound.addMarker(extra);
                sound.play(extra.name);
            }
            else {
                sound.play(extra);
            }
        }
        else {
            sound.play();
        }
    },
    /**
     * Enables playing audio sprite sound on the fly without the need to keep a reference to it.
     * Sound will auto destroy once its playback ends.
     *
     * @method Phaser.Sound.BaseSoundManager#playAudioSprite
     * @param {string} key - Asset key for the sound.
     * @param {string} spriteName - The name of the sound sprite to play.
     * @param {ISoundConfig} [config] - An optional config object containing default sound settings.
     */
    playAudioSprite: function (key, spriteName, config) {
        var sound = this.addAudioSprite(key);
        sound.once('ended', sound.destroy, sound);
        sound.play(spriteName, config);
    },
    /**
     * Removes a sound from the sound manager.
     * The removed sound is destroyed before removal.
     *
     * @method Phaser.Sound.BaseSoundManager#remove
     * @param {ISound} sound - The sound object to remove.
     * @returns {boolean} True if the sound was removed successfully, otherwise false.
     */
    remove: function (sound) {
        var index = this.sounds.indexOf(sound);
        if (index !== -1) {
            sound.destroy();
            this.sounds.splice(index, 1);
            return true;
        }
        return false;
    },
    /**
     * Removes all sounds from the sound manager that have an asset key matching the given value.
     * The removed sounds are destroyed before removal.
     *
     * @method Phaser.Sound.BaseSoundManager#removeByKey
     * @param {string} key - The key to match when removing sound objects.
     * @returns {number} The number of matching sound objects that were removed.
     */
    removeByKey: function (key) {
        var removed = 0;
        for (var i = this.sounds.length - 1; i >= 0; i--) {
            var sound = this.sounds[i];
            if (sound.key === key) {
                sound.destroy();
                this.sounds.splice(i, 1);
                removed++;
            }
        }
        return removed;
    },
    /**
     * Pauses all the sounds in the game.
     *
     * @method Phaser.Sound.BaseSoundManager#pauseAll
     */
    pauseAll: function () {
        this.forEachActiveSound(function (sound) {
            sound.pause();
        });
        this.emit('pauseall', this);
    },
    /**
     * Resumes all the sounds in the game.
     *
     * @method Phaser.Sound.BaseSoundManager#resumeAll
     */
    resumeAll: function () {
        this.forEachActiveSound(function (sound) {
            sound.resume();
        });
        this.emit('resumeall', this);
    },
    /**
     * Stops all the sounds in the game.
     *
     * @method Phaser.Sound.BaseSoundManager#stopAll
     */
    stopAll: function () {
        this.forEachActiveSound(function (sound) {
            sound.stop();
        });
        this.emit('stopall', this);
    },
    /**
     * Method used internally for unlocking audio playback on devices that
     * require user interaction before any sound can be played on a web page.
     *
     * Read more about how this issue is handled here in [this article](TODO add link).
     *
     * @override
     * @protected
     * @method Phaser.Sound.BaseSoundManager#unlock
     */
    unlock: NOOP,
    /**
     * Method used internally for pausing sound manager if
     * Phaser.Sound.BaseSoundManager#pauseOnBlur is set to true.
     *
     * @override
     * @protected
     * @method Phaser.Sound.BaseSoundManager#onBlur
     */
    onBlur: NOOP,
    /**
     * Method used internally for resuming sound manager if
     * Phaser.Sound.BaseSoundManager#pauseOnBlur is set to true.
     *
     * @override
     * @protected
     * @method Phaser.Sound.BaseSoundManager#onFocus
     */
    onFocus: NOOP,
    /**
     * Update method called on every game step.
     * Removes destroyed sounds and updates every active sound in the game.
     *
     * @protected
     * @method Phaser.Sound.BaseSoundManager#update
     * @param {number} time - The current timestamp as generated by the Request Animation Frame or SetTimeout.
     * @param {number} delta - The delta time elapsed since the last frame.
     */
    update: function (time, delta) {
        if (this.unlocked) {
            this.unlocked = false;
            this.locked = false;
            this.emit('unlocked', this);
            this.emit('ready', this);
        }
        for (var i = this.sounds.length - 1; i >= 0; i--) {
            if (this.sounds[i].pendingRemove) {
                this.sounds.splice(i, 1);
            }
        }
        this.sounds.forEach(function (sound) {
            sound.update(time, delta);
        });
    },
    /**
     * Destroys all the sounds in the game and all associated events.
     *
     * @method Phaser.Sound.BaseSoundManager#destroy
     */
    destroy: function () {
        this.game = null;
        this.removeAllListeners();
        this.forEachActiveSound(function (sound) {
            sound.destroy();
        });
        this.sounds.length = 0;
        this.sounds = null;
    },
    /**
     * Method used internally for iterating only over active sounds and skipping sounds that are marked for removal.
     *
     * @private
     * @method Phaser.Sound.BaseSoundManager#forEachActiveSound
     * @param {(sound: ISound, index: number, array: ISound[]) => void} callbackfn - Callback function.
     * @param [thisArg=this] - Callback context.
     */
    forEachActiveSound: function (callbackfn, thisArg) {
        var _this = this;
        this.sounds.forEach(function (sound, index) {
            if (!sound.pendingRemove) {
                callbackfn.call(thisArg || _this, sound, index, _this.sounds);
            }
        });
    }
});
/**
 * Global playback rate.
 *
 * @name Phaser.Sound.BaseSoundManager#rate
 * @property {number} rate
 */
Object.defineProperty(BaseSoundManager.prototype, 'rate', {
    get: function () {
        return this._rate;
    },
    set: function (value) {
        this._rate = value;
        this.forEachActiveSound(function (sound) {
            sound.setRate();
        });
        this.emit('rate', this, value);
    }
});
/**
 * Global detune.
 *
 * @name Phaser.Sound.BaseSoundManager#detune
 * @property {number} detune
 */
Object.defineProperty(BaseSoundManager.prototype, 'detune', {
    get: function () {
        return this._detune;
    },
    set: function (value) {
        this._detune = value;
        this.forEachActiveSound(function (sound) {
            sound.setRate();
        });
        this.emit('detune', this, value);
    }
});
module.exports = BaseSoundManager;
<|endoftext|>


<commit_before>module.exports = {
    "crowdfunding":
    {
        "title_cht": "群眾募資",
        "title_eng": "crowdfunding",
        "prefix_cht": "數位商務模式：",
        "prefix_eng": "commerce",
        "proposer_abbr_cht":"金管會證期局",
        "proposer_abbr_eng":"sfb",
        "stages" : [
            {
                "name" : "討論",
                "gitbook_url": "https://g0v.github.io/crowdfunding-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "February 1, 2015 00:00:00",
                "end_date" : "March 13, 2015 23:59:59",
                "category_num": 6
            },
            {
                "name" : "建議",
                "gitbook_url": "https://g0v.github.io/crowdfunding-spec-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 17, 2015 00:00:00",
                "end_date" : "April 17, 2015 23:59:59",
                "category_num": 55
            },
            {
                "name" : "草案 #1",
                "gitbook_url": "https://g0v.github.io/crowdfunding-ref1-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 20, 2015 00:00:00",
                "end_date" : "April 19, 2015 23:59:59",
                "category_num": 59
            }
        ]
    }
}

<commit_msg>update ProposalList 各主題 meta data<commit_after>module.exports = {
    "crowdfunding":
    {
        "title_cht": "群眾募資",
        "title_eng": "crowdfunding",
        "prefix_cht": "數位商務模式：",
        "prefix_eng": "commerce",
        "proposer_abbr_cht":"金管會證期局",
        "proposer_abbr_eng":"sfb",
        "stages" : [
            {
                "name" : "草案 #1",
                "gitbook_url": "https://g0v.github.io/crowdfunding-ref1-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 20, 2015 00:00:00",
                "end_date" : "April 19, 2015 23:59:59",
                "category_num": 59
            },
            {
                "name" : "建議",
                "gitbook_url": "https://g0v.github.io/crowdfunding-spec-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 17, 2015 00:00:00",
                "end_date" : "April 17, 2015 23:59:59",
                "category_num": 55
            },
            {
                "name" : "討論",
                "gitbook_url": "https://g0v.github.io/crowdfunding-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "February 1, 2015 00:00:00",
                "end_date" : "March 13, 2015 23:59:59",
                "category_num": 6
            }
        ]
    },
    "closelyheld":
    {
        "title_cht": "閉鎖型公司",
        "title_eng": "closelyheld",
        "prefix_cht": "數位商務模式：",
        "prefix_eng": "commerce",
        "proposer_abbr_cht":"經濟部商業司",
        "proposer_abbr_eng":"DOCMOEA",
        "stages" : [
            {
                "name" : "定案",
                "gitbook_url": "https://g0v.github.io/closelyheld-ref1-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "May 1, 2015 00:00:00",
                "end_date" : "May 31, 2015 23:59:59",
                "category_num": 72
            },
            {
                "name" : "草案 #1",
                "proposer_abbr_eng":"vtaiwan",
                "proposer_abbr_cht":"邵慶平",
                "gitbook_url": "https://g0v.github.io/closelyheld-ref1-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "May 1, 2015 00:00:00",
                "end_date" : "May 31, 2015 23:59:59",
                "category_num": 36
            },
            {
                "name" : "建議",
                "gitbook_url": "https://g0v.github.io/closelyheld-spec-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 17, 2015 00:00:00",
                "end_date" : "May 31, 2015 23:59:59",
                "category_num": 53
            },
            {
                "name" : "討論",
                "gitbook_url": "https://g0v.github.io/closelyheld-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "February 1, 2015 00:00:00",
                "end_date" : "March 13, 2015 23:59:59",
                "category_num": 5
            }
        ]
    },
    "etax":
    {
        "title_cht": "網路交易課稅",
        "title_eng": "etax",
        "prefix_cht": "數位商務模式：",
        "prefix_eng": "commerce",
        "proposer_abbr_eng":"MOFTA",
        "proposer_abbr_cht":"財政部賦稅署",
        "stages" : [
            {
                "name" : "建議",
                "gitbook_url": "https://g0v.github.io/etax-spec-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 17, 2015 00:00:00",
                "end_date" : "May 31, 2015 23:59:59",
                "category_num": 53
            },
            {
                "name" : "討論",
                "gitbook_url": "https://g0v.github.io/etax-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "February 1, 2015 00:00:00",
                "end_date" : "March 13, 2015 23:59:59",
                "category_num": 14
            }
        ]
    },
    "distant-education":
    {
        "title_cht": "遠距教育",
        "title_eng": "distant-education",
        "prefix_cht": "數位生活：",
        "prefix_eng": "lifestyle",
        "proposer_abbr_eng":"MOE",
        "proposer_abbr_cht":"教育部",
        "stages" : [
            {
                "name" : "建議",
                "gitbook_url": "https://g0v.github.io/distant-education-spec-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "May 1, 2015 00:00:00",
                "end_date" : "May 31, 2015 23:59:59",
                "category_num": 70
            },
            {
                "name" : "討論",
                "gitbook_url": "https://g0v.github.io/distant-education-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 1, 2015 00:00:00",
                "end_date" : "April 24, 2015 23:59:59",
                "category_num": 17
            }
        ]
    },
    "telework":
    {
        "title_cht": "電傳勞動",
        "title_eng": "telework",
        "prefix_cht": "數位生活：",
        "prefix_eng": "lifestyle",
        "proposer_abbr_eng":"mol",
        "proposer_abbr_cht":"勞動部",
        "stages" : [
            {
                "name" : "討論",
                "gitbook_url": "https://g0v.github.io/telework-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 1, 2015 00:00:00",
                "end_date" : "May 31, 2015 23:59:59",
                "category_num": 18
            }
        ]
    },
    "telemedicine":
    {
        "title_cht": "遠距健康照護",
        "title_eng": "telemedicine",
        "prefix_cht": "數位生活：",
        "prefix_eng": "lifestyle",
        "proposer_abbr_eng":"MOHW",
        "proposer_abbr_cht":"衛福部",
        "stages" : [
            {
                "name" : "討論",
                "gitbook_url": "https://g0v.github.io/telemedicine-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 1, 2015 00:00:00",
                "end_date" : "May 31, 2015 23:59:59",
                "category_num": 19
            }
        ]
    },
    "data-levy":
    {
        "title_cht": "開放資料例外收費原則",
        "title_eng": "data-levy",
        "prefix_cht": "數位公民環境：",
        "prefix_eng": "civic",
        "proposer_abbr_eng":"opendata_mis_ndc",
        "proposer_abbr_cht":"國發會",
        "stages" : [
            {
                "name" : "建議",
                "gitbook_url": "https://g0v.github.io/data-levy-spec-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "May 1, 2015 00:00:00",
                "end_date" : "May 31, 2015 23:59:59",
                "category_num": 68
            },
            {
                "name" : "討論",
                "gitbook_url": "https://g0v.github.io/data-levy-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 1, 2015 00:00:00",
                "end_date" : "April 24, 2015 23:59:59",
                "category_num": 20
            }
        ]
    },
    "consumer-protection":
    {
        "title_cht": "零售業網路定型化契約",
        "title_eng": "consumer-protection",
        "prefix_cht": "數位公民環境：",
        "prefix_eng": "civic",
        "proposer_abbr_eng":"CPCEY",
        "proposer_abbr_cht":"消費者保護處",
        "stages" : [
            {
                "name" : "討論",
                "gitbook_url": "https://g0v.github.io/consumer-protection-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 1, 2015 00:00:00",
                "end_date" : "May 31, 2015 23:59:59",
                "category_num": 21
            }
        ]
    },
    "personal-data-protection":
    {
        "title_cht": "個人資料利用與去識別化",
        "title_eng": "personal-data-protection",
        "prefix_cht": "數位公民環境：",
        "prefix_eng": "civic",
        "proposer_abbr_eng":"CPCEY",
        "proposer_abbr_cht":"消費者保護處",
        "stages" : [
            {
                "name" : "討論",
                "gitbook_url": "https://g0v.github.io/personal-data-protection-gitbook",
                "discourse_url": "https://talk.vtaiwan.tw",
                "start_date" : "March 1, 2015 00:00:00",
                "end_date" : "May 31, 2015 23:59:59",
                "category_num": 22
            }
        ]
    }
}

<|endoftext|>


<commit_before>window.onmouseup = function run(event1) {
  var echoForm = false

  if (window.getSelection() != "") {
    var keys = [];

    var selectedString = window.getSelection().toString();

    onkeydown = onkeyup = function(event2) {
      keys[event2.keyCode] = event2.type == 'keydown';

      if ( (keys[17] === true) && (keys[69] === true) ) {
        event2.preventDefault();
        (keys[17] = false);
        (keys[69] = false);

        if ( echoForm === false ) {
         // not protected variable!
          spawnedEcho = spawnEchoForm(event1.pageX, event1.pageY, this, selectedString);
          window.getSelection().removeAllRanges();
          echoForm = true;

          var userTextandSubmitForm = document.getElementById("userTextAndSubmit");
          userTextandSubmitForm.addEventListener("submit", function(event3){
            event3.preventDefault();

            var userText = document.getElementById("userText").value;

            closeEchoFormAfterSubmit(selectedString);
            echoForm = false;

            chrome.runtime.sendMessage({
              message: selectedString + " " + userText
            }, function(response) {
              // response from eventpage.js
            });
          });

          document.onmousedown = function(event4) {
            console.log("Inside MouseDown: " + selectedString);
            hideSpawnedEcho(selectedString);
          };
        };
      };
    };
  };
};

function closeEchoFormAfterSubmit(selectedString) {
  var echoFrame = document.getElementsByClassName("echo-frame")[0];
  body.removeChild(echoFrame);
  spawnedEcho = null;
};

function hideSpawnedEcho(selectedString) {
  var echoFrame = document.getElementsByClassName("echo-frame")[0];

  if (spawnedEcho) {
    if (!checkClickEventWithinForm(event, echoFrame)) {
      body.removeChild(echoFrame);
      spawnedEcho = null;
    }
  }
};

function checkClickEventWithinForm(event, parent) {
  var current = event.target;

  while (current) {
    if (current === parent) return true;
    current = current.parentNode;
  }
  return false;
};

function spawnEchoForm(x, y, that, selectedString) {
  that.echoForm = document.createElement("div");
  that.echoForm.setAttribute("class", "echo-frame");

  that.echoSubmit = document.createElement("div");
  that.echoSubmit.setAttribute("class", "echo-submit");
  that.echoForm.appendChild(that.echoSubmit);

  that.echoInputForm = document.createElement("form");
  that.echoInputForm.setAttribute("id", "userTextAndSubmit");
  that.echoSubmit.appendChild(that.echoInputForm);

  that.echoButton = document.createElement("button");
  that.echoButton.setAttribute("type", "submit");
  that.echoInputForm.appendChild(that.echoButton);

  that.echoText = document.createElement("input");
  that.echoText.setAttribute("type", "text");
  that.echoText.setAttribute("id", "userText");
  that.echoText.setAttribute("name", "userText");
  that.echoText.setAttribute("placeholder", "add to your Echo");
  that.echoInputForm.appendChild(that.echoText);

  that.echoHighLight = document.createElement("textarea");
  that.echoHighLight.setAttribute("id", "userHighLight");
  that.echoHighLight.setAttribute("name", "userHighLight");
  that.echoHighLight.setAttribute("rows", "4");
  that.echoHighLight.setAttribute("cols", "20");
  that.echoHighLight.value = selectedString;
  that.echoInputForm.appendChild(that.echoHighLight);

  that.echoTextCharCount = document.createElement("span");
  that.echoTextCharCount.setAttribute("id", "char-count");
  that.echoInputForm.appendChild(that.echoTextCharCount);

  var shortenedUrlLength = 25; //subject to change based on length of shortered URL
  var echoHighlight = window.getSelection().toString();
  var lengthOfUserText = that.echoText.value.length;
  var charCount = shortenedUrlLength + echoHighlight.length + lengthOfUserText;
  that.echoTextCharCount.innerHTML = charCount;
  console.log(that.echoTextCharCount.innerHTML);

  that.echoText.addEventListener("keyup", function(event) {
    lengthOfUserText = that.echoText.value.length;
    charCount = shortenedUrlLength + echoHighlight.length + lengthOfUserText;
    that.echoTextCharCount.innerHTML = charCount;

    if (charCount > 119 && charCount < 140){
      document.getElementById("userText").style.borderColor="#3B5998";
      document.getElementById("char-count").style.color="#333333";
    }
    else if (charCount > 139){
      document.getElementById("userText").style.borderColor="#000000";
      document.getElementById("char-count").style.color="#333333";

    }
    else {
      document.getElementById("userText").style.borderColor="#B6FCD5";
      document.getElementById("char-count").style.color="#333333";
    }
  });

  that.fileRef = document.createElement("link");
  that.fileRef.setAttribute("rel", "stylesheet");
  that.fileRef.setAttribute("type", "text/css");
  that.fileRef.setAttribute("href", chrome.extension.getURL("echoform.css"));
  document.getElementsByTagName("head")[0].appendChild(that.fileRef);

  that.echoForm.style.visibility = "visible";

  if ( x > (document.body.clientWidth - 300) ) {
    x = document.body.clientWidth - 310;
    that.echoForm.style.left = x + "px";
  } else {
    that.echoForm.style.left = x + "px";
  };

  y = y + 15;
  that.echoForm.style.top = y + "px";

  body = document.getElementsByTagName("body")[0];
  body.appendChild(that.echoForm);
  return true;
};

<commit_msg>char count on the way UP is operating properly from both forms<commit_after>window.onmouseup = function run(event1) {
  var echoForm = false

  if (window.getSelection() != "") {
    var keys = [];

    var selectedString = window.getSelection().toString();

    onkeydown = onkeyup = function(event2) {
      keys[event2.keyCode] = event2.type == 'keydown';

      if ( (keys[17] === true) && (keys[69] === true) ) {
        event2.preventDefault();
        (keys[17] = false);
        (keys[69] = false);

        if ( echoForm === false ) {
         // not protected variable!
          spawnedEcho = spawnEchoForm(event1.pageX, event1.pageY, this, selectedString);
          window.getSelection().removeAllRanges();
          echoForm = true;

          var userTextandSubmitForm = document.getElementById("userTextAndSubmit");
          userTextandSubmitForm.addEventListener("submit", function(event3){
            event3.preventDefault();

            var userText = document.getElementById("userText").value;

            closeEchoFormAfterSubmit(selectedString);
            echoForm = false;

            chrome.runtime.sendMessage({
              message: selectedString + " " + userText
            }, function(response) {
              // response from eventpage.js
            });
          });

          document.onmousedown = function(event4) {
            hideSpawnedEcho(selectedString);
          };
        };
      };
    };
  };
};

function closeEchoFormAfterSubmit(selectedString) {
  var echoFrame = document.getElementsByClassName("echo-frame")[0];
  body.removeChild(echoFrame);
  spawnedEcho = null;
};

function hideSpawnedEcho(selectedString) {
  var echoFrame = document.getElementsByClassName("echo-frame")[0];

  if (spawnedEcho) {
    if (!checkClickEventWithinForm(event, echoFrame)) {
      body.removeChild(echoFrame);
      spawnedEcho = null;
    }
  }
};

function checkClickEventWithinForm(event, parent) {
  var current = event.target;

  while (current) {
    if (current === parent) return true;
    current = current.parentNode;
  }
  return false;
};

function spawnEchoForm(x, y, that, selectedString) {
  that.echoForm = document.createElement("div");
  that.echoForm.setAttribute("class", "echo-frame");

  that.echoSubmit = document.createElement("div");
  that.echoSubmit.setAttribute("class", "echo-submit");
  that.echoForm.appendChild(that.echoSubmit);

  that.echoInputForm = document.createElement("form");
  that.echoInputForm.setAttribute("id", "userTextAndSubmit");
  that.echoSubmit.appendChild(that.echoInputForm);

  that.echoButton = document.createElement("button");
  that.echoButton.setAttribute("type", "submit");
  that.echoInputForm.appendChild(that.echoButton);

  that.echoText = document.createElement("input");
  that.echoText.setAttribute("type", "text");
  that.echoText.setAttribute("id", "userText");
  that.echoText.setAttribute("name", "userText");
  that.echoText.setAttribute("placeholder", "add to your Echo");
  that.echoInputForm.appendChild(that.echoText);

  that.echoHighLight = document.createElement("textarea");
  that.echoHighLight.setAttribute("id", "userHighLight");
  that.echoHighLight.setAttribute("name", "userHighLight");
  that.echoHighLight.setAttribute("rows", "4");
  that.echoHighLight.setAttribute("cols", "20");
  that.echoHighLight.value = selectedString;
  that.echoInputForm.appendChild(that.echoHighLight);

  that.echoTextCharCount = document.createElement("span");
  that.echoTextCharCount.setAttribute("id", "char-count");
  that.echoInputForm.appendChild(that.echoTextCharCount);

  var shortenedUrlLength = 25; //subject to change based on length of shortered URL
  var editableEchoHighLight = selectedString.length;
  var lengthOfUserText = that.echoText.value.length;
  var charCount = shortenedUrlLength + editableEchoHighLight + lengthOfUserText;
  that.echoTextCharCount.innerHTML = charCount;

  that.echoHighLight.addEventListener("keyup", function(event) {
    editableEchoHighLight = that.echoHighLight.value.length;
    charCount = shortenedUrlLength + editableEchoHighLight + lengthOfUserText;
    that.echoTextCharCount.innerHTML = charCount;
  });

  that.echoText.addEventListener("keyup", function(event) {
    lengthOfUserText = that.echoText.value.length;
    charCount = shortenedUrlLength + editableEchoHighLight + lengthOfUserText;
    that.echoTextCharCount.innerHTML = charCount;

    if (charCount > 119 && charCount < 140){
      document.getElementById("userText").style.borderColor="#3B5998";
      document.getElementById("char-count").style.color="#333333";
    }
    else if (charCount > 139){
      document.getElementById("userText").style.borderColor="#000000";
      document.getElementById("char-count").style.color="#333333";

    }
    else {
      document.getElementById("userText").style.borderColor="#B6FCD5";
      document.getElementById("char-count").style.color="#333333";
    }
  });

  that.fileRef = document.createElement("link");
  that.fileRef.setAttribute("rel", "stylesheet");
  that.fileRef.setAttribute("type", "text/css");
  that.fileRef.setAttribute("href", chrome.extension.getURL("echoform.css"));
  document.getElementsByTagName("head")[0].appendChild(that.fileRef);

  that.echoForm.style.visibility = "visible";

  if ( x > (document.body.clientWidth - 300) ) {
    x = document.body.clientWidth - 310;
    that.echoForm.style.left = x + "px";
  } else {
    that.echoForm.style.left = x + "px";
  };

  y = y + 15;
  that.echoForm.style.top = y + "px";

  body = document.getElementsByTagName("body")[0];
  body.appendChild(that.echoForm);
  return true;
};

<|endoftext|>


<commit_before>document.onmouseup = function run(event1) {

  if (window.getSelection() != "") {
    var keys = [];
    var selectedString = window.getSelection().toString();

    onkeydown = onkeyup = function(event2) {
      keys[event2.keyCode] = event2.type == 'keydown';

      if ( (keys[17] === true) && (keys[69] === true) ) {
        var selectedString = window.getSelection().toString();

        spawnedEcho = spawnEchoForm(event1.pageX, event1.pageY, this);
        // document.getElementById("userText").focus();

        var userTextandSubmitForm = document.getElementById("userTextAndSubmit");
        userTextandSubmitForm.addEventListener("submit", function(event3){
          event3.preventDefault();

          var userText = document.getElementById("userText").value;

          closeEchoFormAfterSubmit();

          chrome.runtime.sendMessage({
            message: selectedString + " " + userText
          }, function(response) {
            console.log(response.message);
          });
        });

        document.onmousedown = function remove(event4) {
          hideSpawnedEcho(event4);
        };
      };
    };
  };
};

function closeEchoFormAfterSubmit() {
  var echoFrame = document.getElementsByClassName("echo-frame")[0];
  body.removeChild(echoFrame);
  spawnedEcho = null;
};

function spawnEchoForm(x, y, that) {

    that.echoForm = document.createElement("div");
    that.echoForm.setAttribute("class", "echo-frame");

    that.echoSubmit = document.createElement("div");
    that.echoSubmit.setAttribute("class", "echo-submit");
    that.echoForm.appendChild(that.echoSubmit);

    that.echoInputForm = document.createElement("form");
    that.echoInputForm.setAttribute("id", "userTextAndSubmit");
    that.echoSubmit.appendChild(that.echoInputForm);

    that.echoButton = document.createElement("button");
    that.echoButton.setAttribute("type", "submit");
    that.echoInputForm.appendChild(that.echoButton);

    that.echoText = document.createElement("input");
    that.echoText.setAttribute("type", "text");
    that.echoText.setAttribute("id", "userText");
    that.echoText.setAttribute("name", "userText");
    that.echoText.setAttribute("placeholder", "add to your Echo");

    that.echoInputForm.appendChild(that.echoText);

    that.fileRef = document.createElement("link");
    that.fileRef.setAttribute("rel", "stylesheet");
    that.fileRef.setAttribute("type", "text/css");
    that.fileRef.setAttribute("href", chrome.extension.getURL("echoform.css"));
    document.getElementsByTagName("head")[0].appendChild(that.fileRef);

    that.echoForm.style.visibility = "visible";

    if ( x > (document.body.clientWidth - 300) ) {
      x = document.body.clientWidth - 310;
      that.echoForm.style.left = x + "px";
    } else {
      that.echoForm.style.left = x + "px";
    };

    // if ( y > (document.body.clientHeight - 50) ) {
      // y = document.body.clientWidth - 100;
      // that.echoForm.style.top = y + "px";
    // } else {
      y = y + 15;
      that.echoForm.style.top = y + "px";
    // };

    body = document.getElementsByTagName("body")[0];
    body.appendChild(that.echoForm);
    return true;
};

function hideSpawnedEcho(event) {
  var echoFrame = document.getElementsByClassName("echo-frame")[0];

  if (spawnedEcho) {
    if (!checkClickEventWithinForm(event, echoFrame)) {
      body.removeChild(echoFrame);
      spawnedEcho = null;
    }
  }
};

function checkClickEventWithinForm(event, parent) {
  var current = event.target;

  while (current) {
    if (current === parent) return true;
    current = current.parentNode;
  }
  return false;
};
<commit_msg>some minor changes for cleanup and rebase for everyone<commit_after>document.onmouseup = function run(event1) {

  if (window.getSelection() != "") {
    var keys = [];
    var selectedString = window.getSelection().toString();

    onkeydown = onkeyup = function(event2) {
      keys[event2.keyCode] = event2.type == 'keydown';

      if ( (keys[17] === true) && (keys[69] === true) ) {
        event2.preventDefault();

        spawnedEcho = spawnEchoForm(event1.pageX, event1.pageY, this);

        var userTextandSubmitForm = document.getElementById("userTextAndSubmit");
        userTextandSubmitForm.addEventListener("submit", function(event3){
          event3.preventDefault();

          var userText = document.getElementById("userText").value;

          closeEchoFormAfterSubmit();

          chrome.runtime.sendMessage({
            message: selectedString + " " + userText
          }, function(response) {
            console.log(response.message);
          });
        });

        document.onmousedown = function remove(event4) {
          hideSpawnedEcho(event4);
        };
      };
    };
  };
};

function closeEchoFormAfterSubmit() {
  var echoFrame = document.getElementsByClassName("echo-frame")[0];
  body.removeChild(echoFrame);
  spawnedEcho = null;
};

function spawnEchoForm(x, y, that) {

    that.echoForm = document.createElement("div");
    that.echoForm.setAttribute("class", "echo-frame");

    that.echoSubmit = document.createElement("div");
    that.echoSubmit.setAttribute("class", "echo-submit");
    that.echoForm.appendChild(that.echoSubmit);

    that.echoInputForm = document.createElement("form");
    that.echoInputForm.setAttribute("id", "userTextAndSubmit");
    that.echoSubmit.appendChild(that.echoInputForm);

    that.echoButton = document.createElement("button");
    that.echoButton.setAttribute("type", "submit");
    that.echoInputForm.appendChild(that.echoButton);

    that.echoText = document.createElement("input");
    that.echoText.setAttribute("type", "text");
    that.echoText.setAttribute("id", "userText");
    that.echoText.setAttribute("name", "userText");
    that.echoText.setAttribute("placeholder", "add to your Echo");

    that.echoInputForm.appendChild(that.echoText);

    that.fileRef = document.createElement("link");
    that.fileRef.setAttribute("rel", "stylesheet");
    that.fileRef.setAttribute("type", "text/css");
    that.fileRef.setAttribute("href", chrome.extension.getURL("echoform.css"));
    document.getElementsByTagName("head")[0].appendChild(that.fileRef);

    that.echoForm.style.visibility = "visible";

    if ( x > (document.body.clientWidth - 300) ) {
      x = document.body.clientWidth - 310;
      that.echoForm.style.left = x + "px";
    } else {
      that.echoForm.style.left = x + "px";
    };

    y = y + 15;
    that.echoForm.style.top = y + "px";

    body = document.getElementsByTagName("body")[0];
    body.appendChild(that.echoForm);
    return true;
};

function hideSpawnedEcho(event) {
  var echoFrame = document.getElementsByClassName("echo-frame")[0];

  if (spawnedEcho) {
    if (!checkClickEventWithinForm(event, echoFrame)) {
      body.removeChild(echoFrame);
      spawnedEcho = null;
    }
  }
};

function checkClickEventWithinForm(event, parent) {
  var current = event.target;

  while (current) {
    if (current === parent) return true;
    current = current.parentNode;
  }
  return false;
};
<|endoftext|>


<commit_before>'use strict';

var Wall = require('../prefabs/wall');
var Player = require('../prefabs/player');
var Pill = require('../prefabs/pill');

function Play() {}

Play.prototype = {
  addToMap: function(x, y) {
    if (!this.map) {
      this.map = [];
    }
    if (!this.map[x]) {
      this.map[x] = [];
    }

    this.map[x][y] = true;
  },
  removeFromMap: function(x,y) {
    if (!this.map || !this.map[x]) {
      return;
    }
    this.map[x][y] = false;
  },
  checkMap: function(x,y) {
    if (!this.map || !this.map[x]) {
      return false;
    }
    return this.map[x][y];
  },
  preload: function() {
  },
  create: function() {
    this.createWalls();
    this.createPills();
    this.createPlayers();

    this.world.scale = {x:100, y:100};
    this.world.bounds = {x: -50, y:-50, width: this.game.width, height: this.game.height};
    this.world.camera.setBoundsToWorld();

    this.addPlayerControls();

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

    this.playerAScoreText = this.game.add.bitmapText(-0.1, -0.4, 'spaced-scorefont','0',1);
    this.playerBScoreText = this.game.add.bitmapText(this.world.width/this.world.scale.x - 2.1, -0.4, 'spaced-scorefont','0',1);

    this.victoryText = this.game.add.bitmapText(this.world.width/2/this.world.scale.x, 2, 'scorefont', '', 1);

    this.gameWon = false;
  },
  update: function() {
    this.game.physics.arcade.overlap(this.players, this.pills, this.playerPillCollision, null, this);

    if (!this.gameWon && this.pills.total === 0) {
      this.gameWon = true;
      if (this.playerA.score > this.playerB.score) {
        this.setVictoryText("PLAYER A WINS");
      }
      else if (this.playerA.score < this.playerB.score) {
        this.setVictoryText("PLAYER B WINS");
      }
      else {
        this.setVictoryText("DRAW");
      }

      var self = this;
      setTimeout(function() {
        self.game.state.start('play');
      }, 5000);
    }
  },
  createWalls: function() {
    this.walls = this.game.add.group();

    this.walls.add(new Wall(this.game, 0,0));
    this.walls.add(new Wall(this.game, 1,0));
    this.walls.add(new Wall(this.game, 2,0));
    this.walls.add(new Wall(this.game, 3,0));
    this.walls.add(new Wall(this.game, 4,0));
    this.walls.add(new Wall(this.game, 5,0));
    this.walls.add(new Wall(this.game, 6,0));
    this.walls.add(new Wall(this.game, 7,0));

    this.walls.add(new Wall(this.game, 0,1));
    this.walls.add(new Wall(this.game, 7,1));

    this.walls.add(new Wall(this.game, 0,2));
    this.walls.add(new Wall(this.game, 2,2));
    this.walls.add(new Wall(this.game, 5,2));
    this.walls.add(new Wall(this.game, 7,2));

    this.walls.add(new Wall(this.game, 0,3));
    this.walls.add(new Wall(this.game, 2,3));
    this.walls.add(new Wall(this.game, 5,3));
    this.walls.add(new Wall(this.game, 7,3));

    this.walls.add(new Wall(this.game, 0,4));
    this.walls.add(new Wall(this.game, 7,4));

    this.walls.add(new Wall(this.game, 0,5));
    this.walls.add(new Wall(this.game, 1,5));
    this.walls.add(new Wall(this.game, 2,5));
    this.walls.add(new Wall(this.game, 3,5));
    this.walls.add(new Wall(this.game, 4,5));
    this.walls.add(new Wall(this.game, 5,5));
    this.walls.add(new Wall(this.game, 6,5));
    this.walls.add(new Wall(this.game, 7,5));

    this.walls.forEach(function(wall) {
      this.addToMap(wall.x, wall.y);
    }, this);
  },
  createPills: function() {
    this.pills = this.game.add.group();

    this.pills.add(new Pill(this.game, 1,1));
    this.pills.add(new Pill(this.game, 2,1));
    this.pills.add(new Pill(this.game, 3,1));
    this.pills.add(new Pill(this.game, 4,1));
    this.pills.add(new Pill(this.game, 5,1));
    this.pills.add(new Pill(this.game, 6,1));

    this.pills.add(new Pill(this.game, 3,2));
    this.pills.add(new Pill(this.game, 4,2));

    this.pills.add(new Pill(this.game, 3,3));
    this.pills.add(new Pill(this.game, 4,3));

    this.pills.add(new Pill(this.game, 1,4));
    this.pills.add(new Pill(this.game, 2,4));
    this.pills.add(new Pill(this.game, 3,4));
    this.pills.add(new Pill(this.game, 4,4));
    this.pills.add(new Pill(this.game, 5,4));
    this.pills.add(new Pill(this.game, 6,4));
  },
  createPlayers: function() {
    this.players = this.game.add.group();

    this.playerA = new Player(this.game, 1, 2, 'player-a', 0);
    this.playerB = new Player(this.game, 6, 2, 'player-b', 0);
    this.players.add(this.playerA);
    this.players.add(this.playerB);

    this.updatePlayerTurn(0);
  },
  addPlayerControls: function() {
    this.playerAControls = {
      up: Phaser.Keyboard.W,
      left: Phaser.Keyboard.A,
      down: Phaser.Keyboard.S,
      right: Phaser.Keyboard.D
    }
    this.playerBControls = {
      up: Phaser.Keyboard.UP,
      left: Phaser.Keyboard.LEFT,
      down: Phaser.Keyboard.DOWN,
      right: Phaser.Keyboard.RIGHT
    };

    function addKeyCaptures(controls, keyboard) {
      for (var index in controls) {
        if (controls.hasOwnProperty(index)) {
          keyboard.addKeyCapture(controls[index]);
        }
      }
    }
    addKeyCaptures(this.playerAControls, this.game.input.keyboard);
    addKeyCaptures(this.playerBControls, this.game.input.keyboard);

    this.game.input.keyboard.addKey(this.playerAControls.up).onDown.add(this.movePlayer.bind(this, this.playerA, 0, -1), this);
    this.game.input.keyboard.addKey(this.playerAControls.down).onDown.add(this.movePlayer.bind(this, this.playerA, 0, 1), this);
    this.game.input.keyboard.addKey(this.playerAControls.left).onDown.add(this.movePlayer.bind(this, this.playerA, -1, 0), this);
    this.game.input.keyboard.addKey(this.playerAControls.right).onDown.add(this.movePlayer.bind(this, this.playerA, 1, 0), this);

    this.game.input.keyboard.addKey(this.playerBControls.up).onDown.add(this.movePlayer.bind(this, this.playerB, 0, -1), this);
    this.game.input.keyboard.addKey(this.playerBControls.down).onDown.add(this.movePlayer.bind(this, this.playerB, 0, 1), this);
    this.game.input.keyboard.addKey(this.playerBControls.left).onDown.add(this.movePlayer.bind(this, this.playerB, -1, 0), this);
    this.game.input.keyboard.addKey(this.playerBControls.right).onDown.add(this.movePlayer.bind(this, this.playerB, 1, 0), this);
  },
  movePlayer: function(player, deltaX, deltaY) {
    var newX = player.x + deltaX;
    var newY = player.y + deltaY;

    if (!this.checkMap(newX, newY) && player.isMyTurn) {
      player.move(newX, newY);
      this.togglePlayerTurn();
    }
  },
  playerPillCollision: function(player, pill) {
    player.score++;
    pill.destroy();

    this.playerAScoreText.setText(this.playerA.score+'');
    this.playerBScoreText.setText(this.playerB.score+'');
  },
  togglePlayerTurn: function() {
    this.updatePlayerTurn((this.playerTurn+1)%this.players.length);
  },
  updatePlayerTurn: function(newPlayerTurn) {
    this.playerTurn = newPlayerTurn;
    for (var i=0; i<this.players.children.length; ++i) {
      this.players.children[i].isMyTurn = (i === this.playerTurn);
    }
    console.log("Player " + this.playerTurn + "'s turn");
  },
  setVictoryText: function(newText) {
    this.victoryText.setText(newText);
    this.victoryText.position.x = this.world.width/2/this.world.scale.x - this.victoryText.textWidth/2 - 0.5;
  },
  shutdown: function() {
    this.game.input.keyboard.removeKey(this.playerAControls.up);
    this.game.input.keyboard.removeKey(this.playerAControls.down);
    this.game.input.keyboard.removeKey(this.playerAControls.left);
    this.game.input.keyboard.removeKey(this.playerAControls.right);

    this.game.input.keyboard.removeKey(this.playerBControls.up);
    this.game.input.keyboard.removeKey(this.playerBControls.down);
    this.game.input.keyboard.removeKey(this.playerBControls.left);
    this.game.input.keyboard.removeKey(this.playerBControls.right);
  }
};

module.exports = Play;
<commit_msg>Fixed centering of victory text<commit_after>'use strict';

var Wall = require('../prefabs/wall');
var Player = require('../prefabs/player');
var Pill = require('../prefabs/pill');

function Play() {}

Play.prototype = {
  addToMap: function(x, y) {
    if (!this.map) {
      this.map = [];
    }
    if (!this.map[x]) {
      this.map[x] = [];
    }

    this.map[x][y] = true;
  },
  removeFromMap: function(x,y) {
    if (!this.map || !this.map[x]) {
      return;
    }
    this.map[x][y] = false;
  },
  checkMap: function(x,y) {
    if (!this.map || !this.map[x]) {
      return false;
    }
    return this.map[x][y];
  },
  preload: function() {
  },
  create: function() {
    this.createWalls();
    this.createPills();
    this.createPlayers();

    this.world.scale = {x:100, y:100};
    this.world.bounds = {x: -50, y:-50, width: this.game.width, height: this.game.height};
    this.world.camera.setBoundsToWorld();

    this.addPlayerControls();

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

    this.playerAScoreText = this.game.add.bitmapText(-0.1, -0.4, 'spaced-scorefont','0',1);
    this.playerBScoreText = this.game.add.bitmapText(this.world.width/this.world.scale.x - 2.1, -0.4, 'spaced-scorefont','0',1);

    this.gameWon = false;
  },
  update: function() {
    this.game.physics.arcade.overlap(this.players, this.pills, this.playerPillCollision, null, this);

    if (!this.gameWon && this.pills.total === 0) {
      this.gameWon = true;
      if (this.playerA.score > this.playerB.score) {
        this.setVictoryText("PLAYER A WINS");
      }
      else if (this.playerA.score < this.playerB.score) {
        this.setVictoryText("PLAYER B WINS");
      }
      else {
        this.setVictoryText("DRAW");
      }

      var self = this;
      setTimeout(function() {
        self.game.state.start('play');
      }, 5000);
    }
  },
  createWalls: function() {
    this.walls = this.game.add.group();

    this.walls.add(new Wall(this.game, 0,0));
    this.walls.add(new Wall(this.game, 1,0));
    this.walls.add(new Wall(this.game, 2,0));
    this.walls.add(new Wall(this.game, 3,0));
    this.walls.add(new Wall(this.game, 4,0));
    this.walls.add(new Wall(this.game, 5,0));
    this.walls.add(new Wall(this.game, 6,0));
    this.walls.add(new Wall(this.game, 7,0));

    this.walls.add(new Wall(this.game, 0,1));
    this.walls.add(new Wall(this.game, 7,1));

    this.walls.add(new Wall(this.game, 0,2));
    this.walls.add(new Wall(this.game, 2,2));
    this.walls.add(new Wall(this.game, 5,2));
    this.walls.add(new Wall(this.game, 7,2));

    this.walls.add(new Wall(this.game, 0,3));
    this.walls.add(new Wall(this.game, 2,3));
    this.walls.add(new Wall(this.game, 5,3));
    this.walls.add(new Wall(this.game, 7,3));

    this.walls.add(new Wall(this.game, 0,4));
    this.walls.add(new Wall(this.game, 7,4));

    this.walls.add(new Wall(this.game, 0,5));
    this.walls.add(new Wall(this.game, 1,5));
    this.walls.add(new Wall(this.game, 2,5));
    this.walls.add(new Wall(this.game, 3,5));
    this.walls.add(new Wall(this.game, 4,5));
    this.walls.add(new Wall(this.game, 5,5));
    this.walls.add(new Wall(this.game, 6,5));
    this.walls.add(new Wall(this.game, 7,5));

    this.walls.forEach(function(wall) {
      this.addToMap(wall.x, wall.y);
    }, this);
  },
  createPills: function() {
    this.pills = this.game.add.group();

    this.pills.add(new Pill(this.game, 1,1));
    this.pills.add(new Pill(this.game, 2,1));
    this.pills.add(new Pill(this.game, 3,1));
    this.pills.add(new Pill(this.game, 4,1));
    this.pills.add(new Pill(this.game, 5,1));
    this.pills.add(new Pill(this.game, 6,1));

    this.pills.add(new Pill(this.game, 3,2));
    this.pills.add(new Pill(this.game, 4,2));

    this.pills.add(new Pill(this.game, 3,3));
    this.pills.add(new Pill(this.game, 4,3));

    this.pills.add(new Pill(this.game, 1,4));
    this.pills.add(new Pill(this.game, 2,4));
    this.pills.add(new Pill(this.game, 3,4));
    this.pills.add(new Pill(this.game, 4,4));
    this.pills.add(new Pill(this.game, 5,4));
    this.pills.add(new Pill(this.game, 6,4));
  },
  createPlayers: function() {
    this.players = this.game.add.group();

    this.playerA = new Player(this.game, 1, 2, 'player-a', 0);
    this.playerB = new Player(this.game, 6, 2, 'player-b', 0);
    this.players.add(this.playerA);
    this.players.add(this.playerB);

    this.updatePlayerTurn(0);
  },
  addPlayerControls: function() {
    this.playerAControls = {
      up: Phaser.Keyboard.W,
      left: Phaser.Keyboard.A,
      down: Phaser.Keyboard.S,
      right: Phaser.Keyboard.D
    }
    this.playerBControls = {
      up: Phaser.Keyboard.UP,
      left: Phaser.Keyboard.LEFT,
      down: Phaser.Keyboard.DOWN,
      right: Phaser.Keyboard.RIGHT
    };

    function addKeyCaptures(controls, keyboard) {
      for (var index in controls) {
        if (controls.hasOwnProperty(index)) {
          keyboard.addKeyCapture(controls[index]);
        }
      }
    }
    addKeyCaptures(this.playerAControls, this.game.input.keyboard);
    addKeyCaptures(this.playerBControls, this.game.input.keyboard);

    this.game.input.keyboard.addKey(this.playerAControls.up).onDown.add(this.movePlayer.bind(this, this.playerA, 0, -1), this);
    this.game.input.keyboard.addKey(this.playerAControls.down).onDown.add(this.movePlayer.bind(this, this.playerA, 0, 1), this);
    this.game.input.keyboard.addKey(this.playerAControls.left).onDown.add(this.movePlayer.bind(this, this.playerA, -1, 0), this);
    this.game.input.keyboard.addKey(this.playerAControls.right).onDown.add(this.movePlayer.bind(this, this.playerA, 1, 0), this);

    this.game.input.keyboard.addKey(this.playerBControls.up).onDown.add(this.movePlayer.bind(this, this.playerB, 0, -1), this);
    this.game.input.keyboard.addKey(this.playerBControls.down).onDown.add(this.movePlayer.bind(this, this.playerB, 0, 1), this);
    this.game.input.keyboard.addKey(this.playerBControls.left).onDown.add(this.movePlayer.bind(this, this.playerB, -1, 0), this);
    this.game.input.keyboard.addKey(this.playerBControls.right).onDown.add(this.movePlayer.bind(this, this.playerB, 1, 0), this);
  },
  movePlayer: function(player, deltaX, deltaY) {
    var newX = player.x + deltaX;
    var newY = player.y + deltaY;

    if (!this.checkMap(newX, newY) && player.isMyTurn) {
      player.move(newX, newY);
      this.togglePlayerTurn();
    }
  },
  playerPillCollision: function(player, pill) {
    player.score++;
    pill.destroy();

    this.playerAScoreText.setText(this.playerA.score+'');
    this.playerBScoreText.setText(this.playerB.score+'');
  },
  togglePlayerTurn: function() {
    this.updatePlayerTurn((this.playerTurn+1)%this.players.length);
  },
  updatePlayerTurn: function(newPlayerTurn) {
    this.playerTurn = newPlayerTurn;
    for (var i=0; i<this.players.children.length; ++i) {
      this.players.children[i].isMyTurn = (i === this.playerTurn);
    }
    console.log("Player " + this.playerTurn + "'s turn");
  },
  setVictoryText: function(newText) {
    this.victoryText = this.game.add.bitmapText(this.world.width/2/this.world.scale.x, 2, 'scorefont', newText, 1);
    this.victoryText.position.x = this.world.width/2/this.world.scale.x - this.victoryText.textWidth/2 - 0.5;
  },
  shutdown: function() {
    this.game.input.keyboard.removeKey(this.playerAControls.up);
    this.game.input.keyboard.removeKey(this.playerAControls.down);
    this.game.input.keyboard.removeKey(this.playerAControls.left);
    this.game.input.keyboard.removeKey(this.playerAControls.right);

    this.game.input.keyboard.removeKey(this.playerBControls.up);
    this.game.input.keyboard.removeKey(this.playerBControls.down);
    this.game.input.keyboard.removeKey(this.playerBControls.left);
    this.game.input.keyboard.removeKey(this.playerBControls.right);
  }
};

module.exports = Play;
<|endoftext|>