<commit_before>//viewmodel for the assess page
function pageViewModel(gvm) {
    gvm.userId = -1;
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AssessTitle");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AssessTitle");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.homeManual = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("HomeManual");}, gvm);
    gvm.foundProjects = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FoundProjects");}, gvm);
    gvm.selectCourse = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SelectCourse");}, gvm);

    // Pagination i18n bindings
    gvm.addBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddBtn")}, gvm);

    // Table i18n bindings
    gvm.codeTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CodeTableTitle");}, gvm);
    gvm.nameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("NameTableTitle");}, gvm);
    gvm.descTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("DescTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    gvm.currentCourseId = null;
    gvm.currentLocationId = null;
    gvm.currentTrainingid = null;

    gvm.updateDropdowns = function() {
        $.getJSON('api/lastdropdownchoice/' + gvm.userId, function(data) {
            if(!$.isEmptyObject(data)) {
                $.each(data, function(i, item) {
                    $(".btn-location span:first").text(item.location);
                    $(".btn-training span:first").text(item.training);
                    $(".btn-course span:first").text(item.course);
                    gvm.updateLocations();
                    gvm.updateTrainings(item.locationid);
                    gvm.updateCourses(item.trainingid);
                    loadTablePage(item.courseid, 1);
                });
            } else {
                gvm.updateLocations();
            }
        });
    }

    gvm.saveLastSelectedDropdowns = function() {
        data = {};
        data["location"] = $(".btn-location span:first").text();
        data["locationid"] = gvm.currentLocationId;
        data["training"] = $(".btn-training span:first").text();
        data["trainingid"] = gvm.currentTrainingid;
        data["course"] = $(".btn-course span:first").text();
        data["courseid"] = gvm.currentCourseId;
        data["user"] = gvm.userId;
        console.log(data);
        $.ajax({
            type: "POST",
            url: "/api/savedropdowns",
            data: data,
            success: function() {
                console.log("success");
            }
        })
    }

    gvm.updateLocations = function() {
        $.getJSON('/api/locations', function(data) {
            gvm.availableLocations.removeAll();
            $.each(data, function(i, item) {
                /* Put item in list */
                gvm.availableLocations.push(item);

                /* Add listener to listitem */
                $("#locbtn-" + item.id).click(function(){
                    gvm.currentLocationId = item.id;
                    gvm.currentTrainingid = null;
                    gvm.currentCourseId = null;
                    gvm.updateTrainings(item.id);
                    $(".btn-location span:first").text($(this).text());
                });
            });
        });
    };

    /*
     * Update the training data
     */
    gvm.updateTrainings = function(id) {
        $.getJSON('/api/trainings/' + id, function(data) {
            gvm.availableTrainings.removeAll();
            $.each(data, function(i, item) {
                gvm.availableTrainings.push(item);

                /* Add listener to listitem */
                $("#trainingbtn-" + item.id).click(function(){
                    gvm.currentTrainingid = null;
                    gvm.currentCourseId = null;
                    gvm.updateCourses(item.id);
                    $(".btn-training span:first").text($(this).text());
                });
            });
        });
    }

    /*
     * Update available courses
     */
    gvm.updateCourses = function(id) {
        $.getJSON('/api/courses/' + id, function(data) {
            gvm.availableCourses.removeAll();
            $.each(data, function(i, item) {
                gvm.availableCourses.push(item);

                /* Add listener to listitem */
                $("#coursebtn-" + item.id).click(function(){
                    $(".btn-course span:first").text($(this).text());
                    gvm.currentCourseId = item.id;
                    loadTablePage(item.id, 1);
                });
            });
        });
    }

    // The table data observable array
    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, code, name, desc) {
        // Push data
        var tblOject = {tid: id, tcode: code, tname: name, tdesc: desc};
        gvm.tabledata.push(tblOject);
    }

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    }
}

function loadTablePage(courseid, pagenr)
{
    $.getJSON('/api/projects/' + courseid + '/page/' + pagenr, function(data){

        /* Clear current table page */
        viewModel.clearTable()

        // Load table data
        $.each(data.data, function(i, item) {
            viewModel.addTableData(item.id, item.code, item.name, item.description);
        });

        /* Let previous en next buttons work */
        if(data.prev == "none"){
            $('#pager-prev-btn').addClass('disabled');
        } else {
            $('#pager-prev-btn').removeClass('disabled');
            $('#pager-prev-btn a').click(function(){
                loadTablePage(data.prev);
            });
        }

        if(data.next == "none"){
            $('#pager-next-btn').addClass('disabled');
        } else {
            $('#pager-next-btn').removeClass('disabled');
            $('#pager-next-btn a').click(function(){
                loadTablePage(data.next);
            });
        }

        // Number of pager buttons
        var numItems = $('.pager-nr-btn').length;

        /* Calculate for the pager buttons */
        var lowPage = Math.floor(pagenr/numItems) + 1;

        $('.pager-nr-btn').each(function() {
            /* calculate current page number */
            var thispagenr = lowPage++;

            /* Add the page number */
            $(this).html('' + thispagenr + '');

            /* Add active class to current page */
            if(thispagenr == pagenr) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }

            /* Disable inactive classes and bind handlers to active classes */
            if(thispagenr > data.pagecount) {
                $(this).addClass('disabled');
            } else {
                /* Add click listener for button */
                $(this).click(function() {
                    loadTablePage(courseid, thispagenr);
                });
            }
        });
    });

}

function initPage() {
    $.getJSON('/api/currentuser', function(data) {
        viewModel.userId = data.id;
        viewModel.updateDropdowns();
    });
}<commit_msg>assess page dropdown updates<commit_after>//viewmodel for the assess page
function pageViewModel(gvm) {
    gvm.userId = -1;
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AssessTitle");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AssessTitle");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.homeManual = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("HomeManual");}, gvm);
    gvm.foundProjects = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FoundProjects");}, gvm);
    gvm.selectCourse = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SelectCourse");}, gvm);

    // Pagination i18n bindings
    gvm.addBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddBtn")}, gvm);

    // Table i18n bindings
    gvm.codeTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CodeTableTitle");}, gvm);
    gvm.nameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("NameTableTitle");}, gvm);
    gvm.descTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("DescTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    gvm.currentCourseId = null;
    gvm.currentLocationId = null;
    gvm.currentTrainingid = null;

    gvm.updateDropdowns = function() {
        $.getJSON('api/lastdropdownchoice/' + gvm.userId, function(data) {
            if(!$.isEmptyObject(data)) {
                $.each(data, function(i, item) {
                    $(".btn-location span:first").text(item.location);
                    $(".btn-training span:first").text(item.training);
                    $(".btn-course span:first").text(item.course);
                    gvm.updateLocations();
                    gvm.updateTrainings(item.locationid);
                    gvm.updateCourses(item.trainingid);
                    loadTablePage(item.courseid, 1);
                });
            } else {
                gvm.updateLocations();
            }
        });
    }

    gvm.saveLastSelectedDropdowns = function() {
        data = {};
        data["location"] = $(".btn-location span:first").text();
        data["locationid"] = gvm.currentLocationId;
        data["training"] = $(".btn-training span:first").text();
        data["trainingid"] = gvm.currentTrainingid;
        data["course"] = $(".btn-course span:first").text();
        data["courseid"] = gvm.currentCourseId;
        data["user"] = gvm.userId;
        console.log(data);
        $.ajax({
            type: "POST",
            url: "/api/savedropdowns",
            data: data,
            success: function() {
                console.log("success");
            }
        })
    }

    gvm.updateLocations = function() {
        $.getJSON('/api/locations', function(data) {
            gvm.availableLocations.removeAll();
            $.each(data, function(i, item) {
                /* Put item in list */
                gvm.availableLocations.push(item);

                /* Add listener to listitem */
                $("#locbtn-" + item.id).click(function(){
                    gvm.currentLocationId = item.id;
                    gvm.currentTrainingid = null;
                    gvm.currentCourseId = null;
                    gvm.updateTrainings(item.id);
                    $(".btn-location span:first").text($(this).text());
                    $(".btn-training span:first").text("training");
                    $(".btn-course span:first").text("course");
                });
            });
        });
    };

    /*
     * Update the training data
     */
    gvm.updateTrainings = function(id) {
        $.getJSON('/api/trainings/' + id, function(data) {
            gvm.availableTrainings.removeAll();
            $.each(data, function(i, item) {
                gvm.availableTrainings.push(item);

                /* Add listener to listitem */
                $("#trainingbtn-" + item.id).click(function(){
                    gvm.currentTrainingid = null;
                    gvm.currentCourseId = null;
                    gvm.updateCourses(item.id);
                    $(".btn-training span:first").text($(this).text());
                    $(".btn-course span:first").text("course");
                });
            });
        });
    }

    /*
     * Update available courses
     */
    gvm.updateCourses = function(id) {
        $.getJSON('/api/courses/' + id, function(data) {
            gvm.availableCourses.removeAll();
            $.each(data, function(i, item) {
                gvm.availableCourses.push(item);

                /* Add listener to listitem */
                $("#coursebtn-" + item.id).click(function(){
                    $(".btn-course span:first").text($(this).text());
                    gvm.currentCourseId = item.id;
                    loadTablePage(item.id, 1);
                });
            });
        });
    }

    // The table data observable array
    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, code, name, desc) {
        // Push data
        var tblOject = {tid: id, tcode: code, tname: name, tdesc: desc};
        gvm.tabledata.push(tblOject);
    }

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    }
}

function loadTablePage(courseid, pagenr)
{
    $.getJSON('/api/projects/' + courseid + '/page/' + pagenr, function(data){

        /* Clear current table page */
        viewModel.clearTable()

        // Load table data
        $.each(data.data, function(i, item) {
            viewModel.addTableData(item.id, item.code, item.name, item.description);
        });

        /* Let previous en next buttons work */
        if(data.prev == "none"){
            $('#pager-prev-btn').addClass('disabled');
        } else {
            $('#pager-prev-btn').removeClass('disabled');
            $('#pager-prev-btn a').click(function(){
                loadTablePage(data.prev);
            });
        }

        if(data.next == "none"){
            $('#pager-next-btn').addClass('disabled');
        } else {
            $('#pager-next-btn').removeClass('disabled');
            $('#pager-next-btn a').click(function(){
                loadTablePage(data.next);
            });
        }

        // Number of pager buttons
        var numItems = $('.pager-nr-btn').length;

        /* Calculate for the pager buttons */
        var lowPage = Math.floor(pagenr/numItems) + 1;

        $('.pager-nr-btn').each(function() {
            /* calculate current page number */
            var thispagenr = lowPage++;

            /* Add the page number */
            $(this).html('' + thispagenr + '');

            /* Add active class to current page */
            if(thispagenr == pagenr) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }

            /* Disable inactive classes and bind handlers to active classes */
            if(thispagenr > data.pagecount) {
                $(this).addClass('disabled');
            } else {
                /* Add click listener for button */
                $(this).click(function() {
                    loadTablePage(courseid, thispagenr);
                });
            }
        });
    });

}

function initPage() {
    $.getJSON('/api/currentuser', function(data) {
        viewModel.userId = data.id;
        viewModel.updateDropdowns();
    });
}<|endoftext|>


<commit_before>/**
 * @file BilliardBot GUI module.
 * @author paranoid-androids@googlegroups.com
 */

define(function(require) {
    "use strict";

    var GUIListener = require('guilistener');
    var GameLogic = require('gamelogic');

    /**
     * Constructs a new pool GUI.
     * @constructor
     * @exports GUI
     * @param container {!Element} The container to use.
     */
    function GUI(container) {
        this.canvas = container;
    }

    /**
     * The simulation speed of the engine. 1.0 is normal; higher values make
     * the game faster.
     */
    GUI.TIME_SCALE = 1.0;

    /**
     * The width of the table, in meters.
     * @constant {number}
     */
    GUI.TABLE_WIDTH = 2.7;

    /**
     * The height of the table, in meters.
     * @constant {number}
     */
    GUI.TABLE_HEIGHT = GUI.TABLE_WIDTH / 2;

    /**
     * The width of the table, in pixels.
     * @constant {number}
     */
    GUI.WIDTH = 800;

    /**
     * The pixels per meter.
     * @constant {number}
     */
    GUI.PPM = GUI.WIDTH / GUI.TABLE_WIDTH;

    /**
     * The height of the table, in pixels.
     * @constant {number}
     */
    GUI.HEIGHT = GUI.TABLE_HEIGHT * GUI.PPM;

    /**
     * The radius of each ball, in pixels.
     * @constant {number}
     */
    GUI.BALL_RADIUS = (0.05715 * GUI.PPM) / 2;

    /**
     * Matter.js options for each ball.
     * @constant {object}
     */
    GUI.BALL_OPTIONS = {
        frictionAir: 0.015,
        friction: 0.0001,
        restitution: 0.92,
        render: {
            lineWidth: 0,
            strokeStyle: "transparent",
            fillStyle: "white"
        }
    };

    // TODO: if needed, improve the appearance of the pockets.
    /**
     * The radius of the pocket mouth on the corners, in pixels.
     * @constant {number}
     */
    GUI.POCKET_RADIUS_CORNER = (0.115 * GUI.PPM) / 2 * 1.75;

    /**
     * The radius of the pocket mouth on the side, in pixels.
     * @constant {number}
     */
    GUI.POCKET_RADIUS_SIDE = (0.129 * GUI.PPM) / 2;

    /**
     * Matter.js options for each ball.
     * @constant {object}
     */
    GUI.POCKET_OPTIONS = {
        isStatic: true,
        label: 'pocket',
        slop: 3,
        render: {
            lineWidth: 1,
            strokeStyle: "white",
            fillStyle: "black"
        }
    };

    /**
     * The speed of the fastest ball below which the turn is considered to be
     * over.
     * @constant {number}
     */
    GUI.SPEED_THRESHOLD = 0.05;

    /**
     * The width of the wall, in pixels.
     * @constant {number}
     */
    GUI.WALL_WIDTH = 40;

    /**
     * Matter.js options for the wall.
     */
    GUI.WALL_OPTIONS = {
        isStatic: true,
        slop: 0.02,
        render: {
            lineWidth: 3,
            strokeStyle: "white",
            fillStyle: "brown"
        }
    }

    GUI.POCKETS = [
        {x: 0, y: 0, radius: GUI.POCKET_RADIUS_CORNER},
        {x: GUI.WIDTH, y: 0, radius: GUI.POCKET_RADIUS_CORNER},
        {x: 0, y: GUI.HEIGHT, radius: GUI.POCKET_RADIUS_CORNER},
        {x: GUI.WIDTH, y: GUI.HEIGHT, radius: GUI.POCKET_RADIUS_CORNER},
        {x: GUI.WIDTH / 2, y: 0, radius: GUI.POCKET_RADIUS_SIDE},
        {x: GUI.WIDTH / 2, y: GUI.HEIGHT, radius: GUI.POCKET_RADIUS_SIDE},
    ]

    /**
     * Whether the GUI is currently idle and waiting for someone to take a
     * shot.
     * @type {!boolean}
     * @private
     */
    GUI.prototype.waitingForShot = true;

    /**
     * The current listener.
     * @type {?GUIListener}
     * @private
     */
    GUI.prototype.listener = null;

    /**
     * The number of balls that have fallen into a pocket.
     * @type {!number}
     */
    GUI.prototype.numPocketedBalls = 0;

    var Matter = require('third_party/matter');

    // Matter module aliases
    var Engine = Matter.Engine,
        World = Matter.World,
        Body = Matter.Body,
        Bodies = Matter.Bodies,
        Common = Matter.Common,
        Composites = Matter.Composites,
        Composite = Matter.Composite,
        Events = Matter.Events,
        MouseConstraint = Matter.MouseConstraint,
        Runner = Matter.Runner;

    /**
     * Sets the event listener.
     * @param {GUIListener} listener
     */
    GUI.prototype.setListener = function(listener) {
        this.listener = listener;
    }

    GUI.prototype.init = function() {
        var self = this;

        // Create the Matter.js engine.
        this.canvas.width = GUI.WIDTH;
        this.canvas.height = GUI.HEIGHT;
        this.engine = Engine.create({
            render: {
                canvas: this.canvas,
                options: {
                    width: GUI.WIDTH,
                    height: GUI.HEIGHT,
                    wireframes: false,
                    background: "#31B94D"
                }
            }
        });

        // TODO: Temporary fix: show balls sunk as text.
        this.ballsSunk = document.getElementById("balls-sunk");
        this.currentPlayer = document.getElementById("current-player");

        // Add some some walls to the world.
        // Note that these values were carefully calculated by first hiding all the pockets and
        // seeing that the balls could fit.
        var wallOffset = GUI.WALL_WIDTH / 4;
        var pocketOffset = GUI.POCKET_RADIUS_CORNER * 2;
        World.add(this.engine.world, [
            // Left wall.
            Bodies.rectangle(-wallOffset, GUI.HEIGHT / 2, GUI.WALL_WIDTH, GUI.HEIGHT -
                pocketOffset, GUI.WALL_OPTIONS),
            // Right wall.
            Bodies.rectangle(GUI.WIDTH + wallOffset, GUI.HEIGHT / 2, GUI.WALL_WIDTH,
                GUI.HEIGHT - pocketOffset, GUI.WALL_OPTIONS),
            // Top wall (broken up into two).
            Bodies.rectangle(GUI.WIDTH / 4 + pocketOffset / 12, -wallOffset, (
                GUI.WIDTH - pocketOffset * 7 / 5) / 2, GUI.WALL_WIDTH, GUI.WALL_OPTIONS),
            Bodies.rectangle(GUI.WIDTH * 3 / 4 - pocketOffset / 12, -wallOffset, (
                GUI.WIDTH - pocketOffset * 7 / 5) / 2, GUI.WALL_WIDTH, GUI.WALL_OPTIONS),
            // Bottom wall (broken up into two).
            Bodies.rectangle(GUI.WIDTH / 4 + pocketOffset / 12, GUI.HEIGHT +
                wallOffset, (GUI.WIDTH - pocketOffset * 7 / 5) / 2, GUI.WALL_WIDTH,
                GUI.WALL_OPTIONS
            ),
            Bodies.rectangle(GUI.WIDTH * 3 / 4 - pocketOffset / 12, GUI.HEIGHT +
                wallOffset, (GUI.WIDTH - pocketOffset * 7 / 5) / 2, GUI.WALL_WIDTH,
                GUI.WALL_OPTIONS
            )
        ]);

        // Add pockets.
        GUI.POCKETS.forEach(function (pocket) {
            World.add(self.engine.world, Bodies.circle(pocket.x, pocket.y, pocket.radius, GUI.POCKET_OPTIONS));
        });

        // Create the rack.
        this.setupRack();

        // Create the cue ball.
        this.placeCue();

        Events.on(this.engine, 'afterTick', function(event) {
            if (!self.waitingForShot) {
                // Remove balls that fall in pockets.
                self.removePocketedBalls();

                // Detect when the balls have stopped moving.
                var totalSpeed = self.calculateMaximumBallSpeed();
                if (totalSpeed >= 0 && totalSpeed < GUI.SPEED_THRESHOLD) {
                    self.waitingForShot = true;
                    if (self.listener) {
                        self.listener.onBallsStopped();
                    }
                }
            }

        });

        // Run the engine, turning off gravity.
        this.engine.world.gravity = {
            x: 0,
            y: 0
        };
        this.engine.timing.timeScale = GUI.TIME_SCALE;
        Engine.run(this.engine);
    };

    /**
     * Takes a shot from the given position with the given force vector.
     * @param {!object} The position.
     * @param {!forceVector} The force vector.
     */
    GUI.prototype.takeShot = function(position, forceVector) {
        Body.applyForce(this.cue, position, forceVector);
        this.waitingForShot = false;
    }

    GUI.prototype.takeShot2 = function(ball, position, forceVector) {
        Body.applyForce(ball, position, forceVector);
        this.waitingForShot = false;
    }

    /**
     * @return {!number} The width of the table, in pixels.
     */
    GUI.prototype.getWidth = function() {
        return WIDTH;
    }

    /**
     * @return {!number} The height of the table, in pixels.
     */
    GUI.prototype.getHeight = function() {
        return HEIGHT;
    }

    /**
     * @return {!object} The position of the cue ball.
     */
    GUI.prototype.getCue = function() {
        return this.cue;
    }

    GUI.prototype.placeBall = function(position, ball) {
        this.cue = Bodies.circle(GUI.WIDTH / 4, GUI.HEIGHT / 2, GUI.BALL_RADIUS,
            GUI.BALL_OPTIONS);
        Body.setMass(this.cue, .17);
        this.cue.label = GameLogic.BALL_LABEL_PREFIX + "cue";
        World.add(this.engine.world, this.cue);
    }

    GUI.prototype.placeCue = function() {
        this.cue = Bodies.circle(GUI.WIDTH / 4, GUI.HEIGHT / 2, GUI.BALL_RADIUS,
            GUI.BALL_OPTIONS);
        Body.setMass(this.cue, .17);
        this.cue.label = GameLogic.BALL_LABEL_PREFIX + "cue";
        World.add(this.engine.world, this.cue);
    }

    /**
     * Shows which player is currently taking their turn.
     * @param {number} player The active player.
     */
    GUI.prototype.updateCurrentPlayer = function(player) {
        this.currentPlayer.innerHTML = player;
    }

    GUI.prototype.getBallsOnTable = function() {
        var allBodies = Composite.allBodies(this.engine.world);
        var ballsOnTable = [];
        allBodies.forEach(function(ball) {
            if (ball.label.indexOf(GameLogic.BALL_LABEL_PREFIX) == 0) {
                ballsOnTable.push(ball);
            }
        });

        return ballsOnTable;
    }

    GUI.prototype.getPockets = function() {
        return GUI.POCKETS;
    }

    /**
     * Used to detect when all the balls have stopped moving on screen in order
     * to alert the listener module to take its next turn.
     * @return {number} The speed of the fastest balls.
     */
    GUI.prototype.calculateMaximumBallSpeed = function() {
        var allBodies = Composite.allBodies(this.engine.world);
        var biggestSpeed = 0;
        for (var i = 0; i < allBodies.length; i++) {
            var ball = allBodies[i];
            if (ball.label.indexOf(GameLogic.BALL_LABEL_PREFIX) == 0) {
                biggestSpeed = Math.max(biggestSpeed, ball.speed);
            }
        }

        return biggestSpeed;
    }

    /**
     * Sets up the default rack.
     */
    GUI.prototype.setupRack = function() {
        var x = (3 * GUI.WIDTH / 4);
        var y = GUI.HEIGHT / 2;
        var ballsPerRow = 1;
        var ballList = this.listener.createInitialBallList();
        var currentBall = 0;

        for (var i = 0; i < 5; i++) {
            var currentY = y
            for (var j = 0; j < ballsPerRow; j++) {
                var ball = Bodies.circle(x, currentY, GUI.BALL_RADIUS, GUI.BALL_OPTIONS);
                Body.setMass(ball, .17);
                ball.render.fillStyle = GameLogic.BALL_COLORS[ballList[currentBall] - 1];
                ball.label = GameLogic.BALL_LABEL_PREFIX + ballList[currentBall];

                World.add(this.engine.world, ball);
                currentY += (GUI.BALL_RADIUS * 2);
                currentBall += 1;
            }
            ballsPerRow += 1;

            x += Math.sqrt(Math.pow(GUI.BALL_RADIUS * 2, 2) - Math.pow(GUI.BALL_RADIUS,
                2));
            y -= GUI.BALL_RADIUS;
        }
    }

    /**
     * Remove any balls that have fallen into pockets.
     */
    GUI.prototype.removePocketedBalls = function() {
        var self = this;

        var allBodies = Composite.allBodies(this.engine.world);
        var activeBalls = allBodies.filter(function(b) {
            return b.label.indexOf(GameLogic.BALL_LABEL_PREFIX) == 0;
        });
        var wallOffset = GUI.WALL_WIDTH / 3 * (1 - GUI.WALL_OPTIONS.slop);

        activeBalls.forEach(function(ball) {
            if (ball.position.x < wallOffset || ball.position.x > GUI.WIDTH -
                wallOffset || ball.position.y < wallOffset || ball.position.y >
                GUI.HEIGHT - wallOffset) {
                Composite.removeBody(self.engine.world, ball)

                self.numPocketedBalls++;

                if(self.listener) {
                    self.listener.ballSunk(ball);
                }
            }
        });
    };

    GUI.prototype.endGame = function() {
        console.log("end game");
        Runner.stop(this.engine);
    }

    return GUI;
});<commit_msg>changed timescale which improved collisions<commit_after>/**
 * @file BilliardBot GUI module.
 * @author paranoid-androids@googlegroups.com
 */

define(function(require) {
    "use strict";

    var GUIListener = require('guilistener');
    var GameLogic = require('gamelogic');

    /**
     * Constructs a new pool GUI.
     * @constructor
     * @exports GUI
     * @param container {!Element} The container to use.
     */
    function GUI(container) {
        this.canvas = container;
    }

    /**
     * The simulation speed of the engine. 1.0 is normal; higher values make
     * the game faster.
     */
    GUI.TIME_SCALE = 0.7;

    /**
     * The width of the table, in meters.
     * @constant {number}
     */
    GUI.TABLE_WIDTH = 2.7;

    /**
     * The height of the table, in meters.
     * @constant {number}
     */
    GUI.TABLE_HEIGHT = GUI.TABLE_WIDTH / 2;

    /**
     * The width of the table, in pixels.
     * @constant {number}
     */
    GUI.WIDTH = 800;

    /**
     * The pixels per meter.
     * @constant {number}
     */
    GUI.PPM = GUI.WIDTH / GUI.TABLE_WIDTH;

    /**
     * The height of the table, in pixels.
     * @constant {number}
     */
    GUI.HEIGHT = GUI.TABLE_HEIGHT * GUI.PPM;

    /**
     * The radius of each ball, in pixels.
     * @constant {number}
     */
    GUI.BALL_RADIUS = (0.05715 * GUI.PPM) / 2;

    /**
     * Matter.js options for each ball.
     * @constant {object}
     */
    GUI.BALL_OPTIONS = {
        frictionAir: 0.015,
        friction: 0.0001,
        restitution: 0.92,
        render: {
            lineWidth: 0,
            strokeStyle: "transparent",
            fillStyle: "white"
        }
    };

    // TODO: if needed, improve the appearance of the pockets.
    /**
     * The radius of the pocket mouth on the corners, in pixels.
     * @constant {number}
     */
    GUI.POCKET_RADIUS_CORNER = (0.115 * GUI.PPM) / 2 * 1.75;

    /**
     * The radius of the pocket mouth on the side, in pixels.
     * @constant {number}
     */
    GUI.POCKET_RADIUS_SIDE = (0.129 * GUI.PPM) / 2;

    /**
     * Matter.js options for each ball.
     * @constant {object}
     */
    GUI.POCKET_OPTIONS = {
        isStatic: true,
        label: 'pocket',
        slop: 3,
        render: {
            lineWidth: 1,
            strokeStyle: "white",
            fillStyle: "black"
        }
    };

    /**
     * The speed of the fastest ball below which the turn is considered to be
     * over.
     * @constant {number}
     */
    GUI.SPEED_THRESHOLD = 0.05;

    /**
     * The width of the wall, in pixels.
     * @constant {number}
     */
    GUI.WALL_WIDTH = 40;

    /**
     * Matter.js options for the wall.
     */
    GUI.WALL_OPTIONS = {
        isStatic: true,
        slop: 0.02,
        render: {
            lineWidth: 3,
            strokeStyle: "white",
            fillStyle: "brown"
        }
    }

    GUI.POCKETS = [
        {x: 0, y: 0, radius: GUI.POCKET_RADIUS_CORNER},
        {x: GUI.WIDTH, y: 0, radius: GUI.POCKET_RADIUS_CORNER},
        {x: 0, y: GUI.HEIGHT, radius: GUI.POCKET_RADIUS_CORNER},
        {x: GUI.WIDTH, y: GUI.HEIGHT, radius: GUI.POCKET_RADIUS_CORNER},
        {x: GUI.WIDTH / 2, y: 0, radius: GUI.POCKET_RADIUS_SIDE},
        {x: GUI.WIDTH / 2, y: GUI.HEIGHT, radius: GUI.POCKET_RADIUS_SIDE},
    ]

    /**
     * Whether the GUI is currently idle and waiting for someone to take a
     * shot.
     * @type {!boolean}
     * @private
     */
    GUI.prototype.waitingForShot = true;

    /**
     * The current listener.
     * @type {?GUIListener}
     * @private
     */
    GUI.prototype.listener = null;

    /**
     * The number of balls that have fallen into a pocket.
     * @type {!number}
     */
    GUI.prototype.numPocketedBalls = 0;

    var Matter = require('third_party/matter');

    // Matter module aliases
    var Engine = Matter.Engine,
        World = Matter.World,
        Body = Matter.Body,
        Bodies = Matter.Bodies,
        Common = Matter.Common,
        Composites = Matter.Composites,
        Composite = Matter.Composite,
        Events = Matter.Events,
        MouseConstraint = Matter.MouseConstraint,
        Runner = Matter.Runner;

    /**
     * Sets the event listener.
     * @param {GUIListener} listener
     */
    GUI.prototype.setListener = function(listener) {
        this.listener = listener;
    }

    GUI.prototype.init = function() {
        var self = this;

        // Create the Matter.js engine.
        this.canvas.width = GUI.WIDTH;
        this.canvas.height = GUI.HEIGHT;
        this.engine = Engine.create({
            render: {
                canvas: this.canvas,
                options: {
                    width: GUI.WIDTH,
                    height: GUI.HEIGHT,
                    wireframes: false,
                    background: "#31B94D"
                }
            }
        });

        // TODO: Temporary fix: show balls sunk as text.
        this.ballsSunk = document.getElementById("balls-sunk");
        this.currentPlayer = document.getElementById("current-player");

        // Add some some walls to the world.
        // Note that these values were carefully calculated by first hiding all the pockets and
        // seeing that the balls could fit.
        var wallOffset = GUI.WALL_WIDTH / 4;
        var pocketOffset = GUI.POCKET_RADIUS_CORNER * 2;
        World.add(this.engine.world, [
            // Left wall.
            Bodies.rectangle(-wallOffset, GUI.HEIGHT / 2, GUI.WALL_WIDTH, GUI.HEIGHT -
                pocketOffset, GUI.WALL_OPTIONS),
            // Right wall.
            Bodies.rectangle(GUI.WIDTH + wallOffset, GUI.HEIGHT / 2, GUI.WALL_WIDTH,
                GUI.HEIGHT - pocketOffset, GUI.WALL_OPTIONS),
            // Top wall (broken up into two).
            Bodies.rectangle(GUI.WIDTH / 4 + pocketOffset / 12, -wallOffset, (
                GUI.WIDTH - pocketOffset * 7 / 5) / 2, GUI.WALL_WIDTH, GUI.WALL_OPTIONS),
            Bodies.rectangle(GUI.WIDTH * 3 / 4 - pocketOffset / 12, -wallOffset, (
                GUI.WIDTH - pocketOffset * 7 / 5) / 2, GUI.WALL_WIDTH, GUI.WALL_OPTIONS),
            // Bottom wall (broken up into two).
            Bodies.rectangle(GUI.WIDTH / 4 + pocketOffset / 12, GUI.HEIGHT +
                wallOffset, (GUI.WIDTH - pocketOffset * 7 / 5) / 2, GUI.WALL_WIDTH,
                GUI.WALL_OPTIONS
            ),
            Bodies.rectangle(GUI.WIDTH * 3 / 4 - pocketOffset / 12, GUI.HEIGHT +
                wallOffset, (GUI.WIDTH - pocketOffset * 7 / 5) / 2, GUI.WALL_WIDTH,
                GUI.WALL_OPTIONS
            )
        ]);

        // Add pockets.
        GUI.POCKETS.forEach(function (pocket) {
            World.add(self.engine.world, Bodies.circle(pocket.x, pocket.y, pocket.radius, GUI.POCKET_OPTIONS));
        });

        // Create the rack.
        this.setupRack();

        // Create the cue ball.
        this.placeCue();

        Events.on(this.engine, 'afterTick', function(event) {
            if (!self.waitingForShot) {
                // Remove balls that fall in pockets.
                self.removePocketedBalls();

                // Detect when the balls have stopped moving.
                var totalSpeed = self.calculateMaximumBallSpeed();
                if (totalSpeed >= 0 && totalSpeed < GUI.SPEED_THRESHOLD) {
                    self.waitingForShot = true;
                    if (self.listener) {
                        self.listener.onBallsStopped();
                    }
                }
            }

        });

        // Run the engine, turning off gravity.
        this.engine.world.gravity = {
            x: 0,
            y: 0
        };
        this.engine.timing.timeScale = GUI.TIME_SCALE;
        Engine.run(this.engine);
    };

    /**
     * Takes a shot from the given position with the given force vector.
     * @param {!object} The position.
     * @param {!forceVector} The force vector.
     */
    GUI.prototype.takeShot = function(position, forceVector) {
        Body.applyForce(this.cue, position, forceVector);
        this.waitingForShot = false;
    }

    GUI.prototype.takeShot2 = function(ball, position, forceVector) {
        Body.applyForce(ball, position, forceVector);
        this.waitingForShot = false;
    }

    /**
     * @return {!number} The width of the table, in pixels.
     */
    GUI.prototype.getWidth = function() {
        return WIDTH;
    }

    /**
     * @return {!number} The height of the table, in pixels.
     */
    GUI.prototype.getHeight = function() {
        return HEIGHT;
    }

    /**
     * @return {!object} The position of the cue ball.
     */
    GUI.prototype.getCue = function() {
        return this.cue;
    }

    GUI.prototype.placeBall = function(position, ball) {
        this.cue = Bodies.circle(GUI.WIDTH / 4, GUI.HEIGHT / 2, GUI.BALL_RADIUS,
            GUI.BALL_OPTIONS);
        Body.setMass(this.cue, .17);
        this.cue.label = GameLogic.BALL_LABEL_PREFIX + "cue";
        World.add(this.engine.world, this.cue);
    }

    GUI.prototype.placeCue = function() {
        this.cue = Bodies.circle(GUI.WIDTH / 4, GUI.HEIGHT / 2, GUI.BALL_RADIUS,
            GUI.BALL_OPTIONS);
        Body.setMass(this.cue, .17);
        this.cue.label = GameLogic.BALL_LABEL_PREFIX + "cue";
        World.add(this.engine.world, this.cue);
    }

    /**
     * Shows which player is currently taking their turn.
     * @param {number} player The active player.
     */
    GUI.prototype.updateCurrentPlayer = function(player) {
        this.currentPlayer.innerHTML = player;
    }

    GUI.prototype.getBallsOnTable = function() {
        var allBodies = Composite.allBodies(this.engine.world);
        var ballsOnTable = [];
        allBodies.forEach(function(ball) {
            if (ball.label.indexOf(GameLogic.BALL_LABEL_PREFIX) == 0) {
                ballsOnTable.push(ball);
            }
        });

        return ballsOnTable;
    }

    GUI.prototype.getPockets = function() {
        return GUI.POCKETS;
    }

    /**
     * Used to detect when all the balls have stopped moving on screen in order
     * to alert the listener module to take its next turn.
     * @return {number} The speed of the fastest balls.
     */
    GUI.prototype.calculateMaximumBallSpeed = function() {
        var allBodies = Composite.allBodies(this.engine.world);
        var biggestSpeed = 0;
        for (var i = 0; i < allBodies.length; i++) {
            var ball = allBodies[i];
            if (ball.label.indexOf(GameLogic.BALL_LABEL_PREFIX) == 0) {
                biggestSpeed = Math.max(biggestSpeed, ball.speed);
            }
        }

        return biggestSpeed;
    }

    /**
     * Sets up the default rack.
     */
    GUI.prototype.setupRack = function() {
        var x = (3 * GUI.WIDTH / 4);
        var y = GUI.HEIGHT / 2;
        var ballsPerRow = 1;
        var ballList = this.listener.createInitialBallList();
        var currentBall = 0;

        for (var i = 0; i < 5; i++) {
            var currentY = y
            for (var j = 0; j < ballsPerRow; j++) {
                var ball = Bodies.circle(x, currentY, GUI.BALL_RADIUS, GUI.BALL_OPTIONS);
                Body.setMass(ball, .17);
                ball.render.fillStyle = GameLogic.BALL_COLORS[ballList[currentBall] - 1];
                ball.label = GameLogic.BALL_LABEL_PREFIX + ballList[currentBall];

                World.add(this.engine.world, ball);
                currentY += (GUI.BALL_RADIUS * 2);
                currentBall += 1;
            }
            ballsPerRow += 1;

            x += Math.sqrt(Math.pow(GUI.BALL_RADIUS * 2, 2) - Math.pow(GUI.BALL_RADIUS,
                2));
            y -= GUI.BALL_RADIUS;
        }
    }

    /**
     * Remove any balls that have fallen into pockets.
     */
    GUI.prototype.removePocketedBalls = function() {
        var self = this;

        var allBodies = Composite.allBodies(this.engine.world);
        var activeBalls = allBodies.filter(function(b) {
            return b.label.indexOf(GameLogic.BALL_LABEL_PREFIX) == 0;
        });
        var wallOffset = GUI.WALL_WIDTH / 3 * (1 - GUI.WALL_OPTIONS.slop);

        activeBalls.forEach(function(ball) {
            if (ball.position.x < wallOffset || ball.position.x > GUI.WIDTH -
                wallOffset || ball.position.y < wallOffset || ball.position.y >
                GUI.HEIGHT - wallOffset) {
                Composite.removeBody(self.engine.world, ball)

                self.numPocketedBalls++;

                if(self.listener) {
                    self.listener.ballSunk(ball);
                }
            }
        });
    };

    GUI.prototype.endGame = function() {
        console.log("end game");
        Runner.stop(this.engine);
    }

    return GUI;
});<|endoftext|>


<commit_before>(function(app) {
  'use strict';

  var helper = app.helper || require('../helper.js');
  var dom = app.dom || require('../dom.js');
  var Component = app.Component || require('./component.js');
  var Main = app.Main || require('./main.js');
  var Sidebar = app.Sidebar || require('./sidebar.js');

  var Body = Component.inherits(function(props) {
    this.dragCount = this.prop(0);
    this.sidebar = new Sidebar({ element: this.childElement('.sidebar') });
    this.main = new Main({ element: this.childElement('.main') });
  });

  Body.prototype.isDragging = function() {
    return (this.dragCount() > 0);
  };

  Body.prototype.incrementDragCount = function() {
    this.dragCount(this.dragCount() + 1);
  };

  Body.prototype.decrementDragCount = function() {
    this.dragCount(this.dragCount() - 1);
  };

  Body.prototype.disabled = function(value) {
    this.sidebar.disabled(value);
    this.main.disabled(value);
  };

  Body.prototype.toggleSidebar = function() {
    this.sidebar.disabled(!this.sidebar.disabled());
  };

  Body.prototype.currentDemoName = function() {
    return (dom.urlQuery(dom.location()).demo || '');
  };

  Body.prototype.demoUrl = function(name) {
    return 'demos/' + name + '.json';
  };

  Body.prototype.load = function() {
    return this.sidebar.loadEntries().then(function() {
      return this.loadDemo(this.currentDemoName());
    }.bind(this));
  };

  Body.prototype.loadModule = function(name, x, y) {
    var point = this.main.contentLocalPoint({ x: x, y: y });
    if (point.x < 0 || point.y < 0) {
      return;
    }

    var entry = this.sidebar.entry(name);
    this.main.loadModule(helper.extend({
      title: entry.label,
      name: name,
    }, point), entry.visiblePortNames);
  };

  Body.prototype.loadDemo = function(name) {
    return (name ? this.main.loadUrl(this.demoUrl(name)) : Promise.resolve());
  };

  Body.prototype.oninit = function() {
    dom.ready(Body.prototype.onready.bind(this));
    this.sidebar.on('dragstart', this.ondragstart.bind(this));
    this.sidebar.on('dragend', this.ondragend.bind(this));
    this.sidebar.on('drop', this.ondrop.bind(this));
    this.main.on('sidebartoggle', this.onsidebartoggle.bind(this));
    this.main.on('dragstart', this.ondragstart.bind(this));
    this.main.on('dragend', this.ondragend.bind(this));
    this.main.on('loadstart', this.onloadstart.bind(this));
    this.main.on('loadend', this.onloadend.bind(this));
  };

  Body.prototype.onredraw = function() {
    this.redrawBy('isDragging', function(isDragging) {
      dom.toggleClass(this.element(), 'dragging', isDragging);
    });
  };

  Body.prototype.onready = function() {
    this.disabled(true);
    this.load().catch(function(e) {
      alert(e);
    }).then(function() {
      this.disabled(false);
    }.bind(this));
  };

  Body.prototype.ondragstart = function() {
    this.incrementDragCount();
  };

  Body.prototype.ondragend = function() {
    this.decrementDragCount();
  };

  Body.prototype.ondrop = function(name, x, y) {
    this.loadModule(name, x, y);
  };

  Body.prototype.onsidebartoggle = function() {
    this.toggleSidebar();
  };

  Body.prototype.onloadstart = function() {
    this.disabled(true);
  };

  Body.prototype.onloadend = function() {
    this.disabled(false);
  };

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = Body;
  } else {
    app.Body = Body;
  }
})(this.app || (this.app = {}));
<commit_msg>Modify code for loading demo<commit_after>(function(app) {
  'use strict';

  var helper = app.helper || require('../helper.js');
  var dom = app.dom || require('../dom.js');
  var Component = app.Component || require('./component.js');
  var Main = app.Main || require('./main.js');
  var Sidebar = app.Sidebar || require('./sidebar.js');

  var Body = Component.inherits(function(props) {
    this.dragCount = this.prop(0);
    this.sidebar = new Sidebar({ element: this.childElement('.sidebar') });
    this.main = new Main({ element: this.childElement('.main') });
  });

  Body.prototype.isDragging = function() {
    return (this.dragCount() > 0);
  };

  Body.prototype.incrementDragCount = function() {
    this.dragCount(this.dragCount() + 1);
  };

  Body.prototype.decrementDragCount = function() {
    this.dragCount(this.dragCount() - 1);
  };

  Body.prototype.disabled = function(value) {
    this.sidebar.disabled(value);
    this.main.disabled(value);
  };

  Body.prototype.toggleSidebar = function() {
    this.sidebar.disabled(!this.sidebar.disabled());
  };

  Body.prototype.demoUrl = function(name) {
    return 'demos/' + name + '.json';
  };

  Body.prototype.load = function() {
    return this.sidebar.loadEntries().then(function() {
      return this.loadDemo();
    }.bind(this));
  };

  Body.prototype.loadModule = function(name, x, y) {
    var point = this.main.contentLocalPoint({ x: x, y: y });
    if (point.x < 0 || point.y < 0) {
      return;
    }

    var entry = this.sidebar.entry(name);
    this.main.loadModule(helper.extend({
      title: entry.label,
      name: name,
    }, point), entry.visiblePortNames);
  };

  Body.prototype.loadDemo = function() {
    var name = dom.urlQuery(dom.location()).demo;
    return (name ? this.main.loadUrl(this.demoUrl(name)) : Promise.resolve());
  };

  Body.prototype.oninit = function() {
    dom.ready(Body.prototype.onready.bind(this));
    this.sidebar.on('dragstart', this.ondragstart.bind(this));
    this.sidebar.on('dragend', this.ondragend.bind(this));
    this.sidebar.on('drop', this.ondrop.bind(this));
    this.main.on('sidebartoggle', this.onsidebartoggle.bind(this));
    this.main.on('dragstart', this.ondragstart.bind(this));
    this.main.on('dragend', this.ondragend.bind(this));
    this.main.on('loadstart', this.onloadstart.bind(this));
    this.main.on('loadend', this.onloadend.bind(this));
  };

  Body.prototype.onredraw = function() {
    this.redrawBy('isDragging', function(isDragging) {
      dom.toggleClass(this.element(), 'dragging', isDragging);
    });
  };

  Body.prototype.onready = function() {
    this.disabled(true);
    this.load().catch(function(e) {
      alert(e);
    }).then(function() {
      this.disabled(false);
    }.bind(this));
  };

  Body.prototype.ondragstart = function() {
    this.incrementDragCount();
  };

  Body.prototype.ondragend = function() {
    this.decrementDragCount();
  };

  Body.prototype.ondrop = function(name, x, y) {
    this.loadModule(name, x, y);
  };

  Body.prototype.onsidebartoggle = function() {
    this.toggleSidebar();
  };

  Body.prototype.onloadstart = function() {
    this.disabled(true);
  };

  Body.prototype.onloadend = function() {
    this.disabled(false);
  };

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = Body;
  } else {
    app.Body = Body;
  }
})(this.app || (this.app = {}));
<|endoftext|>


<commit_before>$(document).ready(function() {
  var load = $('#load');
  var save = $('#save');
  var name = $('#name');

  // var ConceptNetwork = require('concept-network').ConceptNetwork; // FIXME
  var ConceptNetwork = require('/home/francois/dev/browser-concept-network/lib/concept-network').ConceptNetwork;
  cn = new ConceptNetwork();

  if (!localStorage) {
    load.remove();
    save.remove();
  }
  else {
    save.hide();
    if (typeof localStorage.ector === 'undefined') {
      load.hide();
    }
  }

  var alertTpl = $('#alerts').html();
  $('#alerts div').remove();
  /**
   *
   * @param {string} type 'success', 'warning', 'error', or 'info'
   * @param {string} message
   **/
  var showAlert = function(type, message) {
    var inform = {
      type: type,
      message: message
    };
    $('#alerts').append(Mustache.render(alertTpl, inform));
  };

  var infoTpl = $('#infos').html();
  $('#infos').html('');
  /**
   * Display information on the Concept Network (cn)
   **/
  var showInfos = function() {
    var status = {
      nodes_number: cn.nodeLastId,
      links_number: Object.size(cn.link)
    };
    // status.nodes = [
    //   {id: 1, label: "sSalut, comment ça va?", occ: 1}
    // ];
    status.nodes = [];
    // for(var i in cn.node) {
    //   status.nodes.push(cn.node[i]);
    // }
    $('#infos').append(Mustache.render(infoTpl, status));

    // Create data table for DataTable
    aaData = [];
    var aoColumns = [
      {"sTitle": "id", "sClass": "right", "sType": "numeric"},
      {"sTitle": "label", "sWidth": "80%"},
      {"sTitle": "occ", "sClass": "right", "sType": "numeric", "sWidth": "5%"},
      {"sTitle": "type", "sClass": "center","sWidth": "5%"}
    ];
    for(var i in cn.node) {
      var node = cn.node[i];
      var a = [node.id, node.label, node.occ, node.label[0]];
      aaData.push(a);
    }
    // Display DataTable
    $('#infos').append('

');
    $('#cntable').DataTable({"aaData": aaData, "aoColumns": aoColumns, "sPaginationType": "full_numbers"});
  };

  load.on('click', function () {
    var cnSave = localStorage.ector;
    var newCN = Object.create(ConceptNetwork.prototype);
    Object.merge(newCN, JSON.parse(cnSave));
    cn = newCN;
    load.hide();
    showAlert('success', 'Concept Network loaded.');
    showInfos();
    return false;
  });

  save.on('click', function () {
    localStorage.setItem('ector', JSON.stringify(cn));
    load.hide();
    save.hide();

    showAlert('success', 'Concept Network saved.');
    return false;
  });

});<commit_msg>Add a "pos"ition in the sentence column.<commit_after>$(document).ready(function() {
  var load = $('#load');
  var save = $('#save');
  var name = $('#name');

  // var ConceptNetwork = require('concept-network').ConceptNetwork; // FIXME
  var ConceptNetwork = require('/home/francois/dev/browser-concept-network/lib/concept-network').ConceptNetwork;
  cn = new ConceptNetwork();

  if (!localStorage) {
    load.remove();
    save.remove();
  }
  else {
    save.hide();
    if (typeof localStorage.ector === 'undefined') {
      load.hide();
    }
  }

  var alertTpl = $('#alerts').html();
  $('#alerts div').remove();
  /**
   *
   * @param {string} type 'success', 'warning', 'error', or 'info'
   * @param {string} message
   **/
  var showAlert = function(type, message) {
    var inform = {
      type: type,
      message: message
    };
    $('#alerts').append(Mustache.render(alertTpl, inform));
  };

  var infoTpl = $('#infos').html();
  $('#infos').html('');
  /**
   * Display information on the Concept Network (cn)
   **/
  var showInfos = function() {
    var status = {
      nodes_number: cn.nodeLastId,
      links_number: Object.size(cn.link)
    };
    // status.nodes = [
    //   {id: 1, label: "sSalut, comment ça va?", occ: 1}
    // ];
    status.nodes = [];
    // for(var i in cn.node) {
    //   status.nodes.push(cn.node[i]);
    // }
    $('#infos').append(Mustache.render(infoTpl, status));

    // Create data table for DataTable
    aaData = [];
    var aoColumns = [
      {"sTitle": "id", "sClass": "right", "sType": "numeric", "sWidth": "5%"},
      {"sTitle": "label", "sWidth": "80%"},
      {"sTitle": "occ", "sClass": "right", "sType": "numeric", "sWidth": "5%"},
      {"sTitle": "type", "sClass": "center","sWidth": "5%"},
      {"sTitle": "pos", "sClass": "center", "sWith": "5%"}
    ];
    for(var i in cn.node) {
      var node = cn.node[i];
      var pos = "b" + (node.beg ? node.beg : 0) +
                "m" + (node.mid ? node.mid : 0) +
                "e" + (node.end ? node.end : 0);
      if (pos === "b0m0e0") {
        pos = '';
      }
      var a = [node.id, node.label, node.occ, node.label[0], pos];
      aaData.push(a);
    }
    // Display DataTable
    $('#infos').append('

');
    $('#cntable').DataTable({"aaData": aaData, "aoColumns": aoColumns, "sPaginationType": "full_numbers"});
  };

  load.on('click', function () {
    var cnSave = localStorage.ector;
    var newCN = Object.create(ConceptNetwork.prototype);
    Object.merge(newCN, JSON.parse(cnSave));
    cn = newCN;
    load.hide();
    showAlert('success', 'Concept Network loaded.');
    showInfos();
    return false;
  });

  save.on('click', function () {
    localStorage.setItem('ector', JSON.stringify(cn));
    load.hide();
    save.hide();

    showAlert('success', 'Concept Network saved.');
    return false;
  });

});<|endoftext|>


<commit_before>/**
 * This file defines the WumpusGame class.
 */
"use strict";

define(["./WumpusGame.Def", "./Tile", "./Grid",  "./Player", "./WorkerScriptContext", "../user/DefaultWorldGenerator"], function(wumpusGame, Tile, Grid, Player, WorkerScriptContext) {
	 /**
	  * Constructs a new game.
	  * @constructor
	  */
	wumpusGame.WumpusGame = function(coreConfig) {
		// store settings
		this.initialPlayerState = coreConfig.playerState;

		// create core objects
		this.grid = new wumpusGame.Grid(this, coreConfig.gridConfig);
		this.player = new wumpusGame.Player(this);
		this.scriptContext = new WorkerScriptContext(this);

		// create event objects
		this.events = {
			tileChanged : new squishy.Event(this),
			restart : new squishy.Event(this),
            scriptError: new squishy.Event(this)
		};

		if (!this.worldGenerator) {
			// if no custom world generator is available, use the default one
			this.setWorldGenerator(new wumpusGame.DefaultWorldGenerator());
		}

		this.restart();
	};

	 /**
	  * Clears all tiles.
	  */
	wumpusGame.WumpusGame.prototype.clearGame = function() {
		this.grid.foreachTile(function(tile) {
			tile.clearTile();
		});
	};

	 /**
	  * Sets the current world generator.
	  */
	wumpusGame.WumpusGame.prototype.setWorldGenerator = function(worldGenerator) {
		this.worldGenerator = worldGenerator;
	};

	 /**
	  * Clears (if necessary), initializes and starts the game.
	  *
	  * @param {Object} coreConfig Configuration of the game core.
	  * @param {Object} [coreConfig.gridConfig] Grid configuration.
	  * @param {Object} [coreConfig.playerState] Initial player state.
	  */
	wumpusGame.WumpusGame.prototype.restart = function() {
		// gen world
		this.worldGenerator.genWorld(this);

		// initialize player
		this.player.initializePlayer(this.initialPlayerState);

		// restart script worker
		this.scriptContext.restartWorker();

		// notify all listeners
		this.events.restart.notify();

		return true;
	};

	return wumpusGame;
});<commit_msg>[mini] added onPlayerMove<commit_after>/**
 * This file defines the WumpusGame class.
 */
"use strict";

define(["./WumpusGame.Def", "./Tile", "./Grid",  "./Player", "./WorkerScriptContext", "../user/DefaultWorldGenerator"], function(wumpusGame, Tile, Grid, Player, WorkerScriptContext) {
	 /**
	  * Constructs a new game.
	  * @constructor
	  */
	wumpusGame.WumpusGame = function(coreConfig) {
		// store settings
		this.initialPlayerState = coreConfig.playerState;

		// create core objects
		this.grid = new wumpusGame.Grid(this, coreConfig.gridConfig);
		this.player = new wumpusGame.Player(this);
		this.scriptContext = new WorkerScriptContext(this);

		// create event objects
		this.events = {
			tileChanged : new squishy.Event(this),
			restart : new squishy.Event(this),
            		scriptError: new squishy.Event(this)
		};

		if (!this.worldGenerator) {
			// if no custom world generator is available, use the default one
			this.setWorldGenerator(new wumpusGame.DefaultWorldGenerator());
		}

		this.restart();
	};

	 /**
	  * Clears all tiles.
	  */
	wumpusGame.WumpusGame.prototype.clearGame = function() {
		this.grid.foreachTile(function(tile) {
			tile.clearTile();
		});
	};

	 /**
	  * Sets the current world generator.
	  */
	wumpusGame.WumpusGame.prototype.setWorldGenerator = function(worldGenerator) {
		this.worldGenerator = worldGenerator;
	};

	 /**
	  * Clears (if necessary), initializes and starts the game.
	  *
	  * @param {Object} coreConfig Configuration of the game core.
	  * @param {Object} [coreConfig.gridConfig] Grid configuration.
	  * @param {Object} [coreConfig.playerState] Initial player state.
	  */
	wumpusGame.WumpusGame.prototype.restart = function() {
		// gen world
		this.worldGenerator.genWorld(this);

		// initialize player
		this.player.initializePlayer(this.initialPlayerState);

		// restart script worker
		this.scriptContext.restartWorker();

		// notify all listeners
		this.events.restart.notify();

		return true;
	};

	/**
	 * Enforce game rules.
	 */
    	wumpusGame.WumpusGame.prototype.onPlayerMove = function() ｛
    		var player = this.player;
    		var tile = player.getTile();
    		if (tile.hasObject(wumpusGame.ObjectTypes.Pit)) {
    			this.setStatus(wumpusGame.GameStatus.Fail);
    		}
    		// TODO: Cannot paste in ACE on Android; also, cannot sufficiently zoom vertically
    	｝

	return wumpusGame;
});
<|endoftext|>


<commit_before>// Copyright 2019-2021, University of Colorado Boulder

/**
 * Handles serializing and deserializing versions for simulations.
 *
 **************************************************************
 * IMPORTANT NOTE: This file is copied from PERENNIAL to CHIPPER frequently. If this is in CHIPPER, then it is AUTO
 * GENERATED; do not edit, as it will be overwritten. Make sure that any change here is supported by usages of
 * CHIPPER's SimVersion (i.e. in JOIST/updateCheck.js), see https://github.com/phetsims/perennial/issues/111 for more
 **************************************************************
 *
 * See https://github.com/phetsims/chipper/issues/560 for discussion on version ID definition.
 *
 * The canonical description of our general versions:
 *
 * Each version string has the form: {{MAJOR}}.{{MINOR}}.{{MAINTENANCE}}[-{{TEST_TYPE}}.{{TEST_NUMBER}}] where:
 *
 * MAJOR: Sequential integer, starts at 1, and is generally incremented when there are significant changes to a simulation.
 * MINOR: Sequential integer, starts at 0, and is generally incremented when there are smaller changes to a simulation.
 *   Resets to 0 whenever the major number is incremented.
 * MAINTENANCE: Sequential integer, starts at 0, and is incremented whenever we build with the same major/minor (but with different SHAs).
 *   Resets to 0 whenever the minor number is incremented.
 * TEST_TYPE (when present): Indicates that this is a non-production build when present. Typically will take the values:
 *   'dev' - A normal dev deployment, which goes to phet-dev.colorado.edu/html/
 *   'rc' -  A release-candidate deployment (off of a release branch). Also goes to phet-dev.colorado.edu/html/ only.
 *   anything else - A one-off deployment name, which is the same name as the branch it was deployed from.
 * TEST_NUMBER (when present): Indicates the version of the test/one-off type (gets incremented for every deployment).
 *   starts at 0 in package.json, but since it is incremented on every deploy, the first version published will be 1.
 *
 * It used to be (pre-chipper-2.0) that sometimes a shortened form of the (non-'phet') brand would be added to the end
 * (e.g. '1.3.0-dev.1-phetio' or '1.3.0-dev.1-adaptedfromphet'), or as a direct prefix for the TEST_TYPE (e.g.
 * 1.1.0-phetiodev.1 or 1.1.0-phetio). We have since moved to a deployment model where there are
 * subdirectories for each brand, so this is no longer part of the version. Since this was not used for any production sim
 * builds that we need statistics from, it is excluded in SimVersion.js or its description.
 *
 * Examples:
 *
 * 1.5.0                - Production simulation version (no test type). Major = 1, minor = 5, maintenance = 0
 * 1.5.0-rc.1           - Example of a release-candidate build version that would be published before '1.5.0' for testing.
 * 1.5.0-dev.1          - Example of a dev build that would be from master.
 * 1.5.0-sonification.1 - Example of a one-off build (which would be from the branch 'sonification')
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

/* eslint-env browser, node */

// To support loading in Node.js and the browser
const assert = typeof module !== 'undefined' ? require( 'assert' ) : window && window.assert;

( function( global, assert ) {

  class SimVersion {
    /**
     * @constructor
     *
     * @param {number} major - The major part of the version (the 3 in 3.1.2)
     * @param {number} minor - The minor part of the version (the 1 in 3.1.2)
     * @param {number} maintenance - The maintenance part of the version (the 2 in 3.1.2)
     * @param {Object} [options]
     */
    constructor( major, minor, maintenance, options ) {
      const {
        // {string|null} - If provided, indicates the time at which the sim file was built
        buildTimestamp = null,

        // {string|null} - The test name, e.g. the 'rc' in rc.1. Also can be the one-off version name, if provided.
        testType = null,

        // {number|null} - The test number, e.g. the 1 in rc.1
        testNumber = null
      } = options || {};

      assert && assert( typeof major === 'number' && major >= 0 && major % 1 === 0, 'major version should be a non-negative integer' );
      assert && assert( typeof minor === 'number' && minor >= 0 && minor % 1 === 0, 'minor version should be a non-negative integer' );
      assert && assert( typeof maintenance === 'number' && maintenance >= 0 && maintenance % 1 === 0, 'maintenance version should be a non-negative integer' );
      assert && assert( typeof testType !== 'string' || typeof testNumber === 'number', 'if testType is provided, testNumber should be a number' );

      // @public {number}
      this.major = major;

      // @public {number}
      this.minor = minor;

      // @public {number}
      this.maintenance = maintenance;

      // @public {string|null}
      this.testType = testType;

      // @public {number|null}
      this.testNumber = testNumber;

      // @public {string|null} - If provided, like '2015-06-12 16:05:03 UTC' (phet.chipper.buildTimestamp)
      this.buildTimestamp = buildTimestamp;
    }

    /**
     * Convert into a plain JS object meant for JSON serialization.
     * @public
     *
     * @returns {Object}
     */
    serialize() {
      return {
        major: this.major,
        minor: this.minor,
        maintenance: this.maintenance,
        testType: this.testType,
        testNumber: this.testNumber,
        buildTimestamp: this.buildTimestamp
      };
    }

    /**
     * @returns {boolean}
     * @public
     */
    get isSimNotPublished() {
      return this.major < 1 || // e.g. 0.0.0-dev.1
             ( this.major === 1 && // e.g. 1.0.0-dev.1
               this.minor === 0 &&
               this.maintenance === 0 &&
               this.testType );
    }

    /**
     * @returns {boolean}
     * @public
     */
    get isSimPublished() {
      return !this.isSimNotPublished;
    }

    /**
     * Takes a serialized form of the SimVersion and returns an actual instance.
     * @public
     *
     * @param {Object}
     * @returns {SimVersion}
     */
    static deserialize( { major, minor, maintenance, testType, testNumber, buildTimestamp } ) {
      return new SimVersion( major, minor, maintenance, {
        testType: testType,
        testNumber: testNumber,
        buildTimestamp: buildTimestamp
      } );
    }

    /**
     * Compares versions, returning -1 if this version is before the passed in version, 0 if equal, or 1 if this version
     * is after.
     * @public
     *
     * This function only compares major/minor/maintenance, leaving other details to the client.
     *
     * @param {SimVersion} version
     */
    compareNumber( version ) {
      if ( this.major < version.major ) { return -1; }
      if ( this.major > version.major ) { return 1; }
      if ( this.minor < version.minor ) { return -1; }
      if ( this.minor > version.minor ) { return 1; }
      if ( this.maintenance < version.maintenance ) { return -1; }
      if ( this.maintenance > version.maintenance ) { return 1; }
      return 0; // equal
    }

    /**
     * Returns the string form of the version.
     * @public
     *
     * @returns {string}
     */
    toString() {
      let str = `${this.major}.${this.minor}.${this.maintenance}`;
      if ( typeof this.testType === 'string' ) {
        str += `-${this.testType}.${this.testNumber}`;
      }
      return str;
    }

    /**
     * Parses a sim version from a string form.
     * @public
     *
     * @param {string} versionString - e.g. '1.0.0', '1.0.1-dev.3', etc.
     * @param {string} [buildTimestamp] - Optional build timestamp, like '2015-06-12 16:05:03 UTC' (phet.chipper.buildTimestamp)
     * @returns {SimVersion}
     */
    static parse( versionString, buildTimestamp ) {
      const matches = versionString.match( /^(\d+)\.(\d+)\.(\d+)(-(([^.-]+)\.(\d+)))?(-([^.-]+))?$/ );

      if ( !matches ) {
        throw new Error( `could not parse version: ${versionString}` );
      }

      const major = parseInt( matches[ 1 ], 10 );
      const minor = parseInt( matches[ 2 ], 10 );
      const maintenance = parseInt( matches[ 3 ], 10 );
      const testType = matches[ 6 ];
      const testNumber = matches[ 7 ] === undefined ? matches[ 7 ] : parseInt( matches[ 7 ], 10 );

      return new SimVersion( major, minor, maintenance, {
        testType: testType,
        testNumber: testNumber,
        buildTimestamp: buildTimestamp
      } );
    }

    /**
     * Parses a branch in the form {{MAJOR}}.{{MINOR}} and returns a corresponding version. Uses 0 for the maintenance version (unknown).
     * @public
     *
     * @param {string} branch - e.g. '1.0'
     * @returns {SimVersion}
     */
    static fromBranch( branch ) {
      const bits = branch.split( '.' );
      assert && assert( bits.length === 2, `Bad branch, should be {{MAJOR}}.{{MINOR}}, had: ${branch}` );

      const major = parseInt( branch.split( '.' )[ 0 ], 10 );
      const minor = parseInt( branch.split( '.' )[ 1 ], 10 );

      return new SimVersion( major, minor, 0 );
    }

    /**
     * Ensures that a branch name is ok to be a release branch.
     * @public
     *
     * @param {string} branch - e.g. '1.0'
     */
    static ensureReleaseBranch( branch ) {
      const version = SimVersion.fromBranch( branch );
      assert && assert( version.major > 0, 'Major version for a branch should be greater than zero' );
      assert && assert( version.minor >= 0, 'Minor version for a branch should be greater than (or equal) to zero' );
    }
  }

  // Node.js-compatible definition
  if ( typeof module !== 'undefined' ) {
    module.exports = SimVersion;
  }
  else {

    // Browser support, assign with
    window.phet = window.phet || {};
    window.phet.preloads = window.phet.preloads || {};
    window.phet.preloads.chipper = window.phet.preloads.chipper || {};
    window.phet.preloads.chipper.SimVersion = SimVersion;
  }
} )( ( 1, eval )( 'this' ), assert ); // eslint-disable-line no-eval
// Indirect eval usage done since babel likes to wrap things in strict mode.
// See http://perfectionkills.com/unnecessarily-comprehensive-look-into-a-rather-insignificant-issue-of-global-objects-creation/#ecmascript_5_strict_mode
<commit_msg>Copy perennial/dual to chipper/dual from daily grunt work<commit_after>// Copyright 2019-2021, University of Colorado Boulder

/**
 * Handles serializing and deserializing versions for simulations.
 *
 **************************************************************
 * IMPORTANT NOTE: This file is copied from PERENNIAL to CHIPPER frequently.
 * If this is in CHIPPER, then it is AUTO GENERATED; do not edit, as it will be overwritten.
 * If this is in PERENNIAL, make sure your changes are compatible with CHIPPER.
 * See https://github.com/phetsims/perennial/issues/111 and https://github.com/phetsims/chipper/issues/1018
 **************************************************************
 *
 * See https://github.com/phetsims/chipper/issues/560 for discussion on version ID definition.
 *
 * The canonical description of our general versions:
 *
 * Each version string has the form: {{MAJOR}}.{{MINOR}}.{{MAINTENANCE}}[-{{TEST_TYPE}}.{{TEST_NUMBER}}] where:
 *
 * MAJOR: Sequential integer, starts at 1, and is generally incremented when there are significant changes to a simulation.
 * MINOR: Sequential integer, starts at 0, and is generally incremented when there are smaller changes to a simulation.
 *   Resets to 0 whenever the major number is incremented.
 * MAINTENANCE: Sequential integer, starts at 0, and is incremented whenever we build with the same major/minor (but with different SHAs).
 *   Resets to 0 whenever the minor number is incremented.
 * TEST_TYPE (when present): Indicates that this is a non-production build when present. Typically will take the values:
 *   'dev' - A normal dev deployment, which goes to phet-dev.colorado.edu/html/
 *   'rc' -  A release-candidate deployment (off of a release branch). Also goes to phet-dev.colorado.edu/html/ only.
 *   anything else - A one-off deployment name, which is the same name as the branch it was deployed from.
 * TEST_NUMBER (when present): Indicates the version of the test/one-off type (gets incremented for every deployment).
 *   starts at 0 in package.json, but since it is incremented on every deploy, the first version published will be 1.
 *
 * It used to be (pre-chipper-2.0) that sometimes a shortened form of the (non-'phet') brand would be added to the end
 * (e.g. '1.3.0-dev.1-phetio' or '1.3.0-dev.1-adaptedfromphet'), or as a direct prefix for the TEST_TYPE (e.g.
 * 1.1.0-phetiodev.1 or 1.1.0-phetio). We have since moved to a deployment model where there are
 * subdirectories for each brand, so this is no longer part of the version. Since this was not used for any production sim
 * builds that we need statistics from, it is excluded in SimVersion.js or its description.
 *
 * Examples:
 *
 * 1.5.0                - Production simulation version (no test type). Major = 1, minor = 5, maintenance = 0
 * 1.5.0-rc.1           - Example of a release-candidate build version that would be published before '1.5.0' for testing.
 * 1.5.0-dev.1          - Example of a dev build that would be from master.
 * 1.5.0-sonification.1 - Example of a one-off build (which would be from the branch 'sonification')
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

/* eslint-env browser, node */

// To support loading in Node.js and the browser
const assert = typeof module !== 'undefined' ? require( 'assert' ) : window && window.assert;

( function( global, assert ) {

  class SimVersion {
    /**
     * @constructor
     *
     * @param {number} major - The major part of the version (the 3 in 3.1.2)
     * @param {number} minor - The minor part of the version (the 1 in 3.1.2)
     * @param {number} maintenance - The maintenance part of the version (the 2 in 3.1.2)
     * @param {Object} [options]
     */
    constructor( major, minor, maintenance, options ) {
      const {
        // {string|null} - If provided, indicates the time at which the sim file was built
        buildTimestamp = null,

        // {string|null} - The test name, e.g. the 'rc' in rc.1. Also can be the one-off version name, if provided.
        testType = null,

        // {number|null} - The test number, e.g. the 1 in rc.1
        testNumber = null
      } = options || {};

      assert && assert( typeof major === 'number' && major >= 0 && major % 1 === 0, 'major version should be a non-negative integer' );
      assert && assert( typeof minor === 'number' && minor >= 0 && minor % 1 === 0, 'minor version should be a non-negative integer' );
      assert && assert( typeof maintenance === 'number' && maintenance >= 0 && maintenance % 1 === 0, 'maintenance version should be a non-negative integer' );
      assert && assert( typeof testType !== 'string' || typeof testNumber === 'number', 'if testType is provided, testNumber should be a number' );

      // @public {number}
      this.major = major;

      // @public {number}
      this.minor = minor;

      // @public {number}
      this.maintenance = maintenance;

      // @public {string|null}
      this.testType = testType;

      // @public {number|null}
      this.testNumber = testNumber;

      // @public {string|null} - If provided, like '2015-06-12 16:05:03 UTC' (phet.chipper.buildTimestamp)
      this.buildTimestamp = buildTimestamp;
    }

    /**
     * Convert into a plain JS object meant for JSON serialization.
     * @public
     *
     * @returns {Object}
     */
    serialize() {
      return {
        major: this.major,
        minor: this.minor,
        maintenance: this.maintenance,
        testType: this.testType,
        testNumber: this.testNumber,
        buildTimestamp: this.buildTimestamp
      };
    }

    /**
     * @returns {boolean}
     * @public
     */
    get isSimNotPublished() {
      return this.major < 1 || // e.g. 0.0.0-dev.1
             ( this.major === 1 && // e.g. 1.0.0-dev.1
               this.minor === 0 &&
               this.maintenance === 0 &&
               this.testType );
    }

    /**
     * @returns {boolean}
     * @public
     */
    get isSimPublished() {
      return !this.isSimNotPublished;
    }

    /**
     * Takes a serialized form of the SimVersion and returns an actual instance.
     * @public
     *
     * @param {Object}
     * @returns {SimVersion}
     */
    static deserialize( { major, minor, maintenance, testType, testNumber, buildTimestamp } ) {
      return new SimVersion( major, minor, maintenance, {
        testType: testType,
        testNumber: testNumber,
        buildTimestamp: buildTimestamp
      } );
    }

    /**
     * Compares versions, returning -1 if this version is before the passed in version, 0 if equal, or 1 if this version
     * is after.
     * @public
     *
     * This function only compares major/minor/maintenance, leaving other details to the client.
     *
     * @param {SimVersion} version
     */
    compareNumber( version ) {
      if ( this.major < version.major ) { return -1; }
      if ( this.major > version.major ) { return 1; }
      if ( this.minor < version.minor ) { return -1; }
      if ( this.minor > version.minor ) { return 1; }
      if ( this.maintenance < version.maintenance ) { return -1; }
      if ( this.maintenance > version.maintenance ) { return 1; }
      return 0; // equal
    }

    /**
     * Returns the string form of the version.
     * @public
     *
     * @returns {string}
     */
    toString() {
      let str = `${this.major}.${this.minor}.${this.maintenance}`;
      if ( typeof this.testType === 'string' ) {
        str += `-${this.testType}.${this.testNumber}`;
      }
      return str;
    }

    /**
     * Parses a sim version from a string form.
     * @public
     *
     * @param {string} versionString - e.g. '1.0.0', '1.0.1-dev.3', etc.
     * @param {string} [buildTimestamp] - Optional build timestamp, like '2015-06-12 16:05:03 UTC' (phet.chipper.buildTimestamp)
     * @returns {SimVersion}
     */
    static parse( versionString, buildTimestamp ) {
      const matches = versionString.match( /^(\d+)\.(\d+)\.(\d+)(-(([^.-]+)\.(\d+)))?(-([^.-]+))?$/ );

      if ( !matches ) {
        throw new Error( `could not parse version: ${versionString}` );
      }

      const major = parseInt( matches[ 1 ], 10 );
      const minor = parseInt( matches[ 2 ], 10 );
      const maintenance = parseInt( matches[ 3 ], 10 );
      const testType = matches[ 6 ];
      const testNumber = matches[ 7 ] === undefined ? matches[ 7 ] : parseInt( matches[ 7 ], 10 );

      return new SimVersion( major, minor, maintenance, {
        testType: testType,
        testNumber: testNumber,
        buildTimestamp: buildTimestamp
      } );
    }

    /**
     * Parses a branch in the form {{MAJOR}}.{{MINOR}} and returns a corresponding version. Uses 0 for the maintenance version (unknown).
     * @public
     *
     * @param {string} branch - e.g. '1.0'
     * @returns {SimVersion}
     */
    static fromBranch( branch ) {
      const bits = branch.split( '.' );
      assert && assert( bits.length === 2, `Bad branch, should be {{MAJOR}}.{{MINOR}}, had: ${branch}` );

      const major = parseInt( branch.split( '.' )[ 0 ], 10 );
      const minor = parseInt( branch.split( '.' )[ 1 ], 10 );

      return new SimVersion( major, minor, 0 );
    }

    /**
     * Ensures that a branch name is ok to be a release branch.
     * @public
     *
     * @param {string} branch - e.g. '1.0'
     */
    static ensureReleaseBranch( branch ) {
      const version = SimVersion.fromBranch( branch );
      assert && assert( version.major > 0, 'Major version for a branch should be greater than zero' );
      assert && assert( version.minor >= 0, 'Minor version for a branch should be greater than (or equal) to zero' );
    }
  }

  // Node.js-compatible definition
  if ( typeof module !== 'undefined' ) {
    module.exports = SimVersion;
  }
  else {

    // Browser support, assign with
    window.phet = window.phet || {};
    window.phet.preloads = window.phet.preloads || {};
    window.phet.preloads.chipper = window.phet.preloads.chipper || {};
    window.phet.preloads.chipper.SimVersion = SimVersion;
  }
} )( ( 1, eval )( 'this' ), assert ); // eslint-disable-line no-eval
// Indirect eval usage done since babel likes to wrap things in strict mode.
// See http://perfectionkills.com/unnecessarily-comprehensive-look-into-a-rather-insignificant-issue-of-global-objects-creation/#ecmascript_5_strict_mode
<|endoftext|>


<commit_before>/* Boids flocking simulation (TODO) */

function Boid (x, y) {
  this.x = x || flock.canvas.getAttribute("width") / 2;
  this.y = y || flock.canvas.getAttribute("height") / 2;
}

document.addEventListener("DOMContentLoaded", function () {
  window.flock = {

    // BASIC ATTRIBUTES =======================================================

    boids: [],
    canvas: document.getElementById("boids"),
    ctx: document.getElementById("boids").getContext("2d"),

    fps: 15,

    // RENDERING FUNCTIONS ====================================================
    // These functions connect the simulation to the browser

    // Called to update the canvas coordinate system if the canvas size changes
    sizeChanged: function() {
      var width = flock.canvas.offsetWidth,
          height = flock.canvas.offsetHeight;
      flock.canvas.setAttribute("width", width);
      flock.canvas.setAttribute("height", height);
    },

    // Render the simulation on the canvas
    redraw: function() {

    },

    // SIMULATION LOGIC =======================================================

    // Advance the simulation by one step
    step: function() {

    },

    // USER INTERACTION =======================================================

    interacted: function(e) {
      // Position of the mouse in the viewport
      var absx = e.clientX, absy=e.clientY;
    },

    // CONTROL FUNCTIONS ======================================================

    randomize: function () {

    },

    // Begin the loop

    start: function() {
      flock.step();
      flock.redraw();
      setTimeout(function() {
        requestAnimationFrame(flock.start);
      }, 1000 / flock.fps);
    },

    // Initialize and begin

    init: function() {
      this.sizeChanged(); // Calculate sizes
      this.randomize();
      this.start();
    }
  };

  window.addEventListener("resize", flock.sizeChanged);
  document.addEventListener("mousemove", flock.interacted);
  flock.init();

});
<commit_msg>Rewrite placeholder boids.js function in ES6<commit_after>/* Boids flocking simulation (TODO) */

class Boid {
  constructor(x, y) {
    this.x = x || window.flock.canvas.getAttribute('width') / 2;
    this.y = y || window.flock.canvas.getAttribute('height') / 2;
  }
}

document.addEventListener('DOMContentLoaded', () => {
  window.flock = {

    // BASIC ATTRIBUTES =======================================================

    boids: [],
    canvas: document.getElementById('boids'),
    ctx: document.getElementById('boids').getContext('2d'),

    fps: 15,

    // RENDERING FUNCTIONS ====================================================
    // These functions connect the simulation to the browser

    // Called to update the canvas coordinate system if the canvas size changes
    sizeChanged() {
      const width = window.flock.canvas.offsetWidth;
      const height = window.flock.canvas.offsetHeight;
      window.flock.canvas.setAttribute('width', width);
      window.flock.canvas.setAttribute('height', height);
    },

    // Render the simulation on the canvas
    redraw() {

    },

    // SIMULATION LOGIC =======================================================

    // Advance the simulation by one step
    step() {

    },

    // USER INTERACTION =======================================================

    interacted(e) {
      // Position of the mouse in the viewport
      const absx = e.clientX;
      const absy = e.clientY;
    },

    // CONTROL FUNCTIONS ======================================================

    randomize() {

    },

    // Begin the loop

    start() {
      window.flock.step();
      window.flock.redraw();
      setTimeout(() => {
        requestAnimationFrame(window.flock.start);
      }, 1000 / window.flock.fps);
    },

    // Initialize and begin

    init() {
      this.sizeChanged(); // Calculate sizes
      this.randomize();
      this.start();
    },
  };

  window.addEventListener('resize', window.flock.sizeChanged);
  document.addEventListener('mousemove', window.flock.interacted);
  window.flock.init();
});
<|endoftext|>


<commit_before>// The WEBSOCKET server and port the bot should connect to.
// Most of the time this isn't the same as the URL, check the `Request URL` of
// the websocket.
// If you really don't know how to do this... Run `node getserver.js URL`.
// Fill in the URL of the client where `URL` is.
// For example: `node getserver.js http://example-server.psim.us/`
exports.server = 'cbc.pokecommunity.com';
exports.port = 8000;

// This is the server id.
// To know this one, you should check where the AJAX call 'goes' to when you
// log in.
// For example, on the Smogon server, it will say somewhere in the URL
// ~~showdown, meaning that the server id is 'showdown'.
// If you really don't know how to check this... run the said script above.
exports.serverid = 'pokecommunity';

// The nick and password to log in with
// If no password is required, leave pass empty
exports.nick = 'PokeCommBot';
exports.pass = 'filler';

// The rooms that should be joined.
// Joining Smogon's Showdown's Lobby is not allowed.
exports.rooms = ['lobby'];

// Any private rooms that should be joined.
// Private rooms will be moderated differently (since /warn doesn't work in them).
// The bot will also avoid leaking the private rooms through .seen
exports.privaterooms = ['staff'];

// The character text should start with to be seen as a command.
// Note that using / and ! might be 'dangerous' since these are used in
// Showdown itself.
// Using only alphanumeric characters and spaces is not allowed.
exports.commandcharacter = '.';

// The default rank is the minimum rank that can use a command in a room when
// no rank is specified in settings.json
exports.defaultrank = '%';

// Whether this file should be watched for changes or not.
// If you change this option, the server has to be restarted in order for it to
// take effect.
exports.watchconfig = true;

// Secondary websocket protocols should be defined here, however, Showdown
// doesn't support that yet, so it's best to leave this empty.
exports.secprotocols = [];

// What should be logged?
// 0 = error, ok, info, debug, recv, send
// 1 = error, ok, info, debug, cmdr, send
// 2 = error, ok, info, debug (recommended for development)
// 3 = error, ok, info (recommended for production)
// 4 = error, ok
// 5 = error
exports.debuglevel = 3;

// Users who can use all commands regardless of their rank. Be very cautious
// with this, especially on servers other than main.
exports.excepts = [];

// Whitelisted users are those who the bot will not enforce moderation for.
exports.whitelist = ['PokeCommBot'];

// Add a link to the help for the bot here. When there is a link here, .help and .guide
// will link to it.
exports.botguide = 'http://www.pokecommunity.com/showthread.php?t=289012#bot';

// This allows the bot to act as an automated moderator. If enabled, the bot will
// mute users who send 6 lines or more in 6 or fewer seconds for 7 minutes. NOTE: THIS IS
// BY NO MEANS A PERFECT MODERATOR OR SCRIPT. It is a bot and so cannot think for itself or
// exercise moderator discretion. In addition, it currently uses a very simple method of
// determining who to mute and so may miss people who should be muted, or mute those who
// shouldn't. Use with caution.
exports.allowmute = true;

// The punishment values system allows you to customise how you want the bot to deal with
// rulebreakers. Spamming has a points value of 2, all caps has a points value of 1, etc.
exports.punishvals = {
	1: 'warn',
	2: 'mute',
	3: 'hourmute',
	4: 'roomban',
	5: 'ban'
};

<commit_msg>Delete config.js<commit_after><|endoftext|>


<commit_before>var userCharacter = JSON.parse(localStorage.character);

function Character (name, str, agil, int, hp, enemy, ghostType){
  this.name = name;
  this.str = str;
  this.agil = agil;
  this.int = int;
  this.hp = hp;
  this.ghostType = ghostType;
  this.totalLvl = 0;
  this.enemy = enemy;
}

var enemyTurn = false;
var questionCounter = 0;
var enemyCharacter = [];
var encounterArray = [];
var dogEncounter = ['This is the Dog encoutner. Fight him', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', true];
var hipsterEncounter = ['You encounter a hipster ghost. He annoyingly bumps into you. Your life will be taken from you (again), unless you answer this one correct', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', true];
var firstDropEncounter = ['The hipster drops some items for you. You can only carry one. Choose wisely', 'Old Timey Straight Razor', 'Die Verwandlung by Franz Kafka', 'Ear Gauges', false];
var enviroOneEncounter = ['This is the event for the skeleton', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', false];
var skeletonEncounter = ['This is the skeleton encounter. Choose your path', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', true];
var secondDropEncounter = ['The skeleton drops some items, your carrying capicity is slightly larger than last time, but you can only carry one more. Make your pick', 'Hammer', 'Granny Smith Apple', 'Skull', false];
var enviroTwoEncounter = ['This is the second environment event. Choose wisely', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', false];
var ghostlyEncounter = ['Oh god, a cute yet legally differentialble character named ghostly approaches. What will you do to vanquish this foe?', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', true];
var thirdDropEncounter = ['The ghostly ghost drops a couple more items. Make sure you choose wisely, you have a bad feeling somethign big is coming.', 'Gas Cloud', 'Skateboard', 'Fuji Apple', false];
var finalBossEncounter = ['Welp, this is it. It doesnt look like your going to make it out of this one. That guy looks real big. You remind yourself that youve died once before, which calms you down momentarily, anticipating the impending ass kicking. Your move', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', true];
encounterArray.push(dogEncounter, hipsterEncounter, firstDropEncounter, enviroOneEncounter, skeletonEncounter, secondDropEncounter, enviroTwoEncounter, ghostlyEncounter, thirdDropEncounter, finalBossEncounter);
var Doggo = new Character('Doggo', 2, 2, 2, 20, true, 'assets/doggo.png');
var hipsterGhost = new Character('Hipster Ghost', 3, 3, 3, 50, true, 'assets/hipster.png');
var firstItemDrop = new Character('Item Drop One', 506, 507, 508, 1, false);
var enviroOne = new Character('Skeleton Trap', 500, 501, 502, 1, false);
var Skeleton = new Character('Skeleton', 10, 7, 5, 20, true, 'assets/skullex.png');
var secondItemDrop = new Character('Item Drop Two', 509, 5010, 5011, 1, false);
var enviroTwo = new Character('Second Environment', 503, 504, 505, 1, false);
var ghostly = new Character('Ghostly', 7, 14, 12, 22, true, 'assets/ghostly.png');
var thirdItemDrop = new Character('Item Drop Three', 5012, 5013, 5014, 1, false);
var finalBoss = new Character('Chaos Lord', 20, 13, 17, 30, true, 'assets/gho.png');
enemyCharacter.push(Doggo, hipsterGhost, firstItemDrop, enviroOne, Skeleton, secondItemDrop, enviroTwo, ghostly, thirdItemDrop, finalBoss);

function appendUserGhost(){
  var userAsset = document.createElement('img');
  userAsset.setAttribute('id', 'hero');
  userAsset.setAttribute('src', userCharacter.ghostType);
  var assetHolder = document.getElementsByClassName('hero')[0];
  assetHolder.appendChild(userAsset);
}
appendUserGhost();
<commit_msg>added method to character for background sounds<commit_after>var userCharacter = JSON.parse(localStorage.character);

function Character (name, str, agil, int, hp, enemy, ghostType, audioFilePath){
  this.name = name;
  this.str = str;
  this.agil = agil;
  this.int = int;
  this.hp = hp;
  this.ghostType = ghostType;
  this.totalLvl = 0;
  this.enemy = enemy;
  this.audioFilePath = audioFilePath;
  this.enemyBackgroundMusicChange = function() {
    var grabBackgroundMusicAudio = document.getElementById('audio');
    var enemyAudioFile = this.audioFilePath;
    grabBackgroundMusicAudio.setAttribute('src', this.audioFilePath);
  };
  this.enemyBackgroundMusicChange();
}

var enemyTurn = false;
var questionCounter = 0;
var enemyCharacter = [];
var encounterArray = [];
var dogEncounter = ['This is the Dog encoutner. Fight him', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', true];
var hipsterEncounter = ['You encounter a hipster ghost. He annoyingly bumps into you. Your life will be taken from you (again), unless you answer this one correct', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', true];
var firstDropEncounter = ['The hipster drops some items for you. You can only carry one. Choose wisely', 'Old Timey Straight Razor', 'Die Verwandlung by Franz Kafka', 'Ear Gauges', false];
var enviroOneEncounter = ['This is the event for the skeleton', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', false];
var skeletonEncounter = ['This is the skeleton encounter. Choose your path', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', true];
var secondDropEncounter = ['The skeleton drops some items, your carrying capicity is slightly larger than last time, but you can only carry one more. Make your pick', 'Hammer', 'Granny Smith Apple', 'Skull', false];
var enviroTwoEncounter = ['This is the second environment event. Choose wisely', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', false];
var ghostlyEncounter = ['Oh god, a cute yet legally differentialble character named ghostly approaches. What will you do to vanquish this foe?', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', true];
var thirdDropEncounter = ['The ghostly ghost drops a couple more items. Make sure you choose wisely, you have a bad feeling somethign big is coming.', 'Gas Cloud', 'Skateboard', 'Fuji Apple', false];
var finalBossEncounter = ['Welp, this is it. It doesnt look like your going to make it out of this one. That guy looks real big. You remind yourself that youve died once before, which calms you down momentarily, anticipating the impending ass kicking. Your move', 'This is the strength Option', 'this is the Intelligence Option', 'This is the agility option', true];
encounterArray.push(dogEncounter, hipsterEncounter, firstDropEncounter, enviroOneEncounter, skeletonEncounter, secondDropEncounter, enviroTwoEncounter, ghostlyEncounter, thirdDropEncounter, finalBossEncounter);
var Doggo = new Character('Doggo', 2, 2, 2, 20, true, 'assets/doggo.png', 'music/battleOne.mp3');
var hipsterGhost = new Character('Hipster Ghost', 3, 3, 3, 50, true, 'assets/hipster.png', 'music/battleOne.mp3');
var firstItemDrop = new Character('Item Drop One', 506, 507, 508, 1, false);
var enviroOne = new Character('Skeleton Trap', 500, 501, 502, 1, false);
var Skeleton = new Character('Skeleton', 10, 7, 5, 20, true, 'assets/skullex.png', 'music/battleTwo.mp3');
var secondItemDrop = new Character('Item Drop Two', 509, 5010, 5011, 1, false);
var enviroTwo = new Character('Second Environment', 503, 504, 505, 1, false);
var ghostly = new Character('Ghostly', 7, 14, 12, 22, true, 'assets/ghostly.png', 'music/battleTwo.mp3');
var thirdItemDrop = new Character('Item Drop Three', 5012, 5013, 5014, 1, false);
var finalBoss = new Character('Chaos Lord', 20, 13, 17, 30, true, 'assets/gho.png', 'music/boss.wav');
enemyCharacter.push(Doggo, hipsterGhost, firstItemDrop, enviroOne, Skeleton, secondItemDrop, enviroTwo, ghostly, thirdItemDrop, finalBoss);

function appendUserGhost(){
  var userAsset = document.createElement('img');
  userAsset.setAttribute('id', 'hero');
  userAsset.setAttribute('src', userCharacter.ghostType);
  var assetHolder = document.getElementsByClassName('hero')[0];
  assetHolder.appendChild(userAsset);
}
appendUserGhost();
<|endoftext|>