<commit_before>$(function () {
    $("#shutdown").prop("checked", false);
    var curDamage = parseInt($("#damage").data("damage"));
    // Enable the submit program button
    $("#sendcards img").click(sendCards);
    var submitted = true;
    var isShutdown = false;

    var timer;
    var timeRemaining;

    // Set up howler sounds
    var damageSound = new Howl({
        src: ['/sounds/damage.ogg', '/sounds/damage.mp3']
    });
    var laserSound = new Howl({
        src: ['/sounds/laser.ogg', '/sounds/laser.mp3']
    });
    var winnerSound = new Howl({
        src: ['/sounds/winner.ogg', '/sounds/winner.mp3']
    });
    var flagTouch = new Howl({
        src: ['/sounds/flagtouch.ogg', '/sounds/flagtouch.mp3']
    });
    var timerStarted = new Howl({
        src: ['/sounds/timer.ogg', '/sounds/timer.mp3']
    });

    // Shutdown toggle effects
    $("#shutdown").button().click(function () {
        if ($('#shutdown').prop("checked"))
        {
            $("#labelText").html("Shutdown On");
        }
        else
        {
            $("#labelText").html("Shutdown Off");
        }
    });
    $("#shutdownLabel").hover(function () {
        $(this).removeClass("ui-state-hover");
    });

    // Set up arrays for card faces and details
    var faces = new Array();
    faces["right"] = "R";
    faces["left"] = "L";
    faces["uturn"] = "U";
    faces["backup"] = "B";

    var detail = new Array();
    detail["right"] = "Right";
    detail["left"] = "Left";
    detail["backup"] = "Backup";
    detail["uturn"] = "U-Turn";
    detail["forward"] = "Move";

    var boxes = 9;

    // Start connection to player hub
    var cardControl = $.connection.playerHub;

    // Processes and displays cards dealt to the player
    cardControl.client.deal = (function (cards, lockedCards) {
        $('.executing').removeClass('executing');
        submitted = true;
        isShutdown = false;
        $(".slot ul").empty();
        if ($("#submitted").length != 0) {
            $("#submitted").remove();
        }
        $("#labelText").html("Shutdown Off");
        $("#shutdown").prop("checked", false);
        var _cards = $.parseJSON(cards);
        if (_cards.length == 0) {
            $("#shutdownLabel").css("background", "red");
            $("#cardsContainer").html("
Robot shutdown
");
            isShutdown = true;
            return;
        }
        else
        {
            $("#cardsContainer").empty();
            $("#shutdownLabel").css("background", "none");
        }
        var i = 1;
        $.each(_cards, function () {
            var face;
            var details;
            if (this.direction == "forward") {
                face = this.magnitude;
                details = detail[this.direction] + " " + this.magnitude;
            }
            else {
                face = faces[this.direction];
                details = detail[this.direction];
            }
            // Append card to card container
            $("#cardsContainer").append("
\

\

" + this.priority + "
\

" + face + "
\

" + details + "
\
                    \

\

");
            $("#card" + i).data("cardinfo", this);
            i++;
        });
        // Makes the card slots droppable
        $(".slot").droppable("enable").css("border", "1px solid #DDD");
        // Reset locked card slots
        $(".locked").remove();

        var slot = 5;
        // Process locked cards
        $.each($.parseJSON(lockedCards), function () {
            var face;
            var details;
            if (this.direction == "forward") {
                face = this.magnitude;
                details = detail[this.direction] + " " + this.magnitude;
            }
            else {
                face = faces[this.direction];
                details = detail[this.direction];
            }
            // Add card to locked slot
            $("#slot" + slot + " ul").append("
\

\

" + this.priority + "
\

" + face + "
\

" + details + "
\
                    \

\

");
            $("#slot" + slot).droppable("disable").css("border", "3px solid red");
            $("#slot" + slot + " h4").append(" LOCKED!");
            $("#card" + i).data("cardinfo", this);
            slot--;
            i++;
        });
        // Minimum width of window is 7 slots worth
        boxes = ($(".dealtCard").length < 7) ? 7 : $(".dealtCard").length;

        // Set the width of the cards to fill the screen in one row
        var imageWidth = (($(window).width() - 80) / boxes);
        if (imageWidth < 350) {
            var percent = (imageWidth / 350);
            var imageHeight = percent * 520;
            $(".order").css("font-size", percent * 4 + "em");
            $(".face").css("font-size", percent * 11.8 + "em");
            $(".details").css("font-size", percent * 2.5 + "em");
            $("#cardsContainer img, .slot img").width(imageWidth);
            $("#cardsContainer img,.slot img").height(imageHeight);
            $("#cardsContainer li, .slot li").css({
                "height": "",
                "width": ""
            });
            $(".slot, #sendcards").width(imageWidth + 2);
            $(".slot, #sendcards").height(imageHeight + 28);
            $("#cardsContainer").css("min-height", imageHeight + 5);
        }

        // Let the card elements be draggable
        $("li", "#cardsContainer").draggable({
            revert: "invalid", // When not dropped, the item will revert back to its initial position
            containment: "document",
            cursor: "move"
        });
        // Enable the submit program button
        submitted = false;
        $("#submitButton").attr("src", "/images/cards/submit.png");
        // Get bot's current status
        cardControl.server.getHealth($('#playerNum').data("player")).done(function (damage) {
            updateHealth(damage);
        })
    });

    // Shows the current move being executed
    cardControl.client.showMove = (function (card, robot, register) {
        if (curDamage < 10) {
            $('.executing').removeClass('executing');
            $("#slot" + register + ' .ui-widget-header').addClass('executing');
            $("#cardsContainer").empty();
            var _card = $.parseJSON(card);
            var face;
            var details;
            if (_card.direction == "forward") {
                face = _card.magnitude;
                details = detail[_card.direction] + " " + _card.magnitude;
            }
            else {
                face = faces[_card.direction];
                details = detail[_card.direction];
            }
            // Add current card being executed to the card container
            $("#cardsContainer").append("
\

\

" + _card.priority + "
\

" + face + "
\

" + details + "
\
                    \

\

\

Robot moving: " + robot + "<\li>"
            );

            // Set the width of the cards to fill the screen in one row
            var imageWidth = (($(window).width() - 80) / 7);
            if (imageWidth < 350) {
                var percent = (imageWidth / 350);
                var imageHeight = percent * 520;
                $(".order").css("font-size", percent * 4 + "em");
                $(".face").css("font-size", percent * 11.8 + "em");
                $(".details").css("font-size", percent * 2.5 + "em");
                $("#cardsContainer img, .slot img").width(imageWidth);
                $("#cardsContainer img,.slot img").height(imageHeight);
                $("#cardsContainer li, .slot li").css({
                    "height": "",
                    "width": ""
                });
                $("#player").css("font-size", percent * 5.8 + "em");
                $(".slot, #sendcards").width(imageWidth + 2);
                $(".slot, #sendcards").height(imageHeight + 28);
                $("#cardsContainer").css("min-height", imageHeight + 5);
            }
        }
    });

    // Bind update damage function
    cardControl.client.UpdateHealth = (function (damage) {
        var curHealth = $.parseJSON(damage);
        var player = parseInt($('#playerNum').data("player"));
        var myDamage = curHealth[player - 1];
        updateHealth(myDamage);
    });

    // When called, requests a deal from the server
    cardControl.client.requestdeal = (function () {
        $("#shutdown").prop("checked", false).button("refresh");
        cardControl.server.dealMe($('#playerNum').data("player"));
    });

    // Once the page loads, get the player's first hand
    $.connection.hub.start().done(function () {
        cardControl.server.dealMe($('#playerNum').data("player"));
    });

    // Game has been reset, return to setup page
    cardControl.client.Reset = (function (resetAll) {
        if (resetAll == 0) {
            window.location = "/Player/playerSetup/" + $('#playerNum').data("player") + "?reset=1";
        }
        else
        {
            window.location = "/";
        }
    });

    // Displays a message from the server
    cardControl.client.displayMessage = (function (message, sound) {
        if (curDamage < 10) {
            $("#cardsContainer").html("
" + message + "
");
            switch (sound) {
                case "laser":
                    laserSound.play();
                    break;
                case "winner":
                    winnerSound.play();
                    break;
                case "flagTouch":
                    flagTouch.play();
                    break;
            }
        }
    });

    // Resize the cards as the window resizes, this is inelegant but works for now, should switch to entirely CSS solution
    $(window).resize(function () {
        var imageWidth = (($(window).width() - 80) / boxes);
        if (imageWidth < 350) {
            var percent = (imageWidth / 350);
            var imageHeight = percent * 520;
            $(".order").css("font-size", percent * 4 + "em");
            $(".face").css("font-size", percent * 11.8 + "em");
            $(".details").css("font-size", percent * 2.5 + "em");
            $("#cardsContainer img, .slot img").width(imageWidth);
            $("#cardsContainer img, .slot img").height(imageHeight);
            $("#cardsContainer li, .slot li").css({
                "height": "",
                "width": ""
            });
            $(".slot, #sendcards").width(imageWidth + 2);
            $(".slot, #sendcards").height(imageHeight + 28);
            $("#cardsContainer").css("min-height", imageHeight + 5);
        }
        else
        {
            $(".order").css("font-size", "2.15em");
            $("#cardsContainer img, .slot img").width(350);
            $("#cardsContainer img, .slot img").height(520);
            $("#cardsContainer li, .slot li").css({
                "height": "",
                "width": ""
            });
            $(".slot, #sendcards").width(352);
            $(".slot, #sendcards").height(548);
            $("#cardsContainer").css("min-height", 525);
        }
    });

    // Let the slots be droppable, accepting the card elements
    $(".slot").droppable({
        accept: "#cardsContainer > li, .slot li",
        hoverClass: "ui-state-hover",
        drop: function (event, ui) {
            if ($(ui.draggable).parent().hasClass("slotList")) {
                $(ui.draggable).closest("div").droppable("enable");
            }
            $(ui.draggable).css({
                "top": 0,
                "right": 0,
                "left": 0,
                "bottom": 0
            });
            $(ui.draggable).detach().appendTo($("ul", this));
            $(this).droppable("disable");
        }
    });

    // Let the card area be droppable as well, accepting elements from the slots
    $("#cardsContainer").droppable({
        accept: ".slot li",
        activeClass: "custom-state-active",
        drop: function (event, ui) {
            $(ui.draggable).closest("div").droppable("enable");
            $(ui.draggable).css({
                "top": 0,
                "right": 0,
                "left": 0,
                "bottom": 0
            });
            $(ui.draggable).appendTo($(this));
        }
    });

    // Receives the robot's current health from the server
    function updateHealth(damage)
    {
        if (damage > curDamage)
        {
            damageSound.play();
        }
        $(".damageBox").css('background', 'none');
        if (damage >= 10) {
            $("#damage").html("Robot is dead! ");
            $("#cardsContainer").html("
Your robot has died!
");
        }
        else {
            $("#damage").html("Robot damage: ");
        }
        for (var i = 0; i <= damage; i++)
        {
            $("#damageBox_" + i).css('background', 'red');
        }
        curDamage = damage;
        // Gets the flags the robot has touched
        $.get("/Setup/Status", function (data) {
            var player = data.players[parseInt($('#playerNum').data("player")) - 1];
            updateFlags(player);
            updateLives(player);
        });
    }

    // Draws the flags and touched flags
    function updateFlags(player) {
        if (player.totalFlags > 0) {
            $("#flagBoxes").empty();
            for (var i = 0; i < player.totalFlags; i++) {
                $("#flagBoxes").append(' ');
                if (player.flags > i) {
                    $("#flag" + i).addClass("touchedFlag");
                }
            }
        } else {
            $(".flagInfo").remove();
        }
    }

    // Updates the life boxes
    function updateLives(player) {
        $(".lifeBox").css("background", "none");
        for (var i = 1; i <= player.lives; i++) {
            $("#lifeBox_" + i).css("background", "blue");
        }
        if (player.lives <=0)
        {
            $("#cardsContainer").html("
You lose :-(
");
        }
    }

    // Sends the selected cards to the server
    function sendCards() {
        if (!submitted) {
            submitted = true;
            if ($(".slot").has("li").length != $(".slot").length) {
                alert("Please fill all movement slots");
                submitted = false;
            }
            else {
                window.clearInterval(timer);
                $("#timer").empty();
                $("#submitButton").attr("src", "/images/cards/submitted.png");
                var shutdown = false;
                var move = new Array();
                $(".slot").each(function () {
                    move.push($("li", this).data("cardinfo"));
                });
                $(".ui-draggable").draggable("option", "disabled", true).css("cursor", "default");
                if ($('#shutdown').prop("checked")) {
                    shutdown = true;
                }
                cardControl.server.sendCards($('#playerNum').data("player"), move, shutdown);
                $("#slots").prepend("
Program Submitted
");
            }
        }
    }

    // Starts the countdown timer
    cardControl.client.startTimer = (function () {
        if (!submitted && !isShutdown) {
            timeRemaining = 30;
            $("#timer").html("
Time remaining: " + timeRemaining + "
");
            timerStarted.play();
            timer = setInterval(timerHandler, 1000);
        }
    });

    // Handles the countdown timer
    function timerHandler()
    {
        // Count down
        timeRemaining--;
        $("#timer").html("
Time remaining: " + timeRemaining + "
");
        if (timeRemaining == 0)
        {
            clearInterval(timer);
            // Deal random cards into the register slots
            $(".slot").each(function () {
                if (!$(this).has("li").length)
                {
                    var number = Math.floor((Math.random() * $('#cardsContainer li').length) + 1);
                    $('#cardsContainer li:nth-child(' + number + ')').detach().appendTo($(this).find('.slotList'));
                }
            });
            $(".ui-draggable").draggable("option", "disabled", true).css("cursor", "default");
            setTimeout(sendCards, 1500);
        }
    }
});<commit_msg>Fixed bug in card dealing.<commit_after>$(function () {
    $("#shutdown").prop("checked", false);
    var curDamage = parseInt($("#damage").data("damage"));
    // Enable the submit program button
    $("#sendcards img").click(sendCards);
    var submitted = true;
    var isShutdown = false;

    var timer;
    var timeRemaining;

    // Set up howler sounds
    var damageSound = new Howl({
        src: ['/sounds/damage.ogg', '/sounds/damage.mp3']
    });
    var laserSound = new Howl({
        src: ['/sounds/laser.ogg', '/sounds/laser.mp3']
    });
    var winnerSound = new Howl({
        src: ['/sounds/winner.ogg', '/sounds/winner.mp3']
    });
    var flagTouch = new Howl({
        src: ['/sounds/flagtouch.ogg', '/sounds/flagtouch.mp3']
    });
    var timerStarted = new Howl({
        src: ['/sounds/timer.ogg', '/sounds/timer.mp3']
    });

    // Shutdown toggle effects
    $("#shutdown").button().click(function () {
        if ($('#shutdown').prop("checked"))
        {
            $("#labelText").html("Shutdown On");
        }
        else
        {
            $("#labelText").html("Shutdown Off");
        }
    });
    $("#shutdownLabel").hover(function () {
        $(this).removeClass("ui-state-hover");
    });

    // Set up arrays for card faces and details
    var faces = new Array();
    faces["right"] = "R";
    faces["left"] = "L";
    faces["uturn"] = "U";
    faces["backup"] = "B";

    var detail = new Array();
    detail["right"] = "Right";
    detail["left"] = "Left";
    detail["backup"] = "Backup";
    detail["uturn"] = "U-Turn";
    detail["forward"] = "Move";

    var boxes = 9;

    // Start connection to player hub
    var cardControl = $.connection.playerHub;

    // Processes and displays cards dealt to the player
    cardControl.client.deal = (function (cards, lockedCards) {
        $('.executing').removeClass('executing');
        submitted = true;
        isShutdown = false;
        $(".slot ul").empty();
        if ($("#submitted").length != 0) {
            $("#submitted").remove();
        }
        $("#labelText").html("Shutdown Off");
        $("#shutdown").prop("checked", false);

        var _cards = $.parseJSON(cards);
        var _lockedCards = $.parseJSON(lockedCards);

        if (_cards.length == 0 && _lockedCards.length == 0) {
            $("#shutdownLabel").css("background", "red");
            $("#cardsContainer").html("
Robot shutdown
");
            isShutdown = true;
            return;
        }
        else
        {
            $("#cardsContainer").empty();
            $("#shutdownLabel").css("background", "none");
        }
        var i = 1;
        $.each(_cards, function () {
            var face;
            var details;
            if (this.direction == "forward") {
                face = this.magnitude;
                details = detail[this.direction] + " " + this.magnitude;
            }
            else {
                face = faces[this.direction];
                details = detail[this.direction];
            }
            // Append card to card container
            $("#cardsContainer").append("
\

\

" + this.priority + "
\

" + face + "
\

" + details + "
\
                    \

\

");
            $("#card" + i).data("cardinfo", this);
            i++;
        });
        // Makes the card slots droppable
        $(".slot").droppable("enable").css("border", "1px solid #DDD");
        // Reset locked card slots
        $(".locked").remove();

        var slot = 5;
        // Process locked cards
        $.each(_lockedCards, function () {
            var face;
            var details;
            if (this.direction == "forward") {
                face = this.magnitude;
                details = detail[this.direction] + " " + this.magnitude;
            }
            else {
                face = faces[this.direction];
                details = detail[this.direction];
            }
            // Add card to locked slot
            $("#slot" + slot + " ul").append("
\

\

" + this.priority + "
\

" + face + "
\

" + details + "
\
                    \

\

");
            $("#slot" + slot).droppable("disable").css("border", "3px solid red");
            $("#slot" + slot + " h4").append(" LOCKED!");
            $("#card" + i).data("cardinfo", this);
            slot--;
            i++;
        });
        // Minimum width of window is 7 slots worth
        boxes = ($(".dealtCard").length < 7) ? 7 : $(".dealtCard").length;

        // Set the width of the cards to fill the screen in one row
        var imageWidth = (($(window).width() - 80) / boxes);
        if (imageWidth < 350) {
            var percent = (imageWidth / 350);
            var imageHeight = percent * 520;
            $(".order").css("font-size", percent * 4 + "em");
            $(".face").css("font-size", percent * 11.8 + "em");
            $(".details").css("font-size", percent * 2.5 + "em");
            $("#cardsContainer img, .slot img").width(imageWidth);
            $("#cardsContainer img,.slot img").height(imageHeight);
            $("#cardsContainer li, .slot li").css({
                "height": "",
                "width": ""
            });
            $(".slot, #sendcards").width(imageWidth + 2);
            $(".slot, #sendcards").height(imageHeight + 28);
            $("#cardsContainer").css("min-height", imageHeight + 5);
        }

        // Let the card elements be draggable
        $("li", "#cardsContainer").draggable({
            revert: "invalid", // When not dropped, the item will revert back to its initial position
            containment: "document",
            cursor: "move"
        });
        // Enable the submit program button
        submitted = false;
        $("#submitButton").attr("src", "/images/cards/submit.png");
        // Get bot's current status
        cardControl.server.getHealth($('#playerNum').data("player")).done(function (damage) {
            updateHealth(damage);
        })
    });

    // Shows the current move being executed
    cardControl.client.showMove = (function (card, robot, register) {
        if (curDamage < 10) {
            $('.executing').removeClass('executing');
            $("#slot" + register + ' .ui-widget-header').addClass('executing');
            $("#cardsContainer").empty();
            var _card = $.parseJSON(card);
            var face;
            var details;
            if (_card.direction == "forward") {
                face = _card.magnitude;
                details = detail[_card.direction] + " " + _card.magnitude;
            }
            else {
                face = faces[_card.direction];
                details = detail[_card.direction];
            }
            // Add current card being executed to the card container
            $("#cardsContainer").append("
\

\

" + _card.priority + "
\

" + face + "
\

" + details + "
\
                    \

\

\

Robot moving: " + robot + "<\li>"
            );

            // Set the width of the cards to fill the screen in one row
            var imageWidth = (($(window).width() - 80) / 7);
            if (imageWidth < 350) {
                var percent = (imageWidth / 350);
                var imageHeight = percent * 520;
                $(".order").css("font-size", percent * 4 + "em");
                $(".face").css("font-size", percent * 11.8 + "em");
                $(".details").css("font-size", percent * 2.5 + "em");
                $("#cardsContainer img, .slot img").width(imageWidth);
                $("#cardsContainer img,.slot img").height(imageHeight);
                $("#cardsContainer li, .slot li").css({
                    "height": "",
                    "width": ""
                });
                $("#player").css("font-size", percent * 5.8 + "em");
                $(".slot, #sendcards").width(imageWidth + 2);
                $(".slot, #sendcards").height(imageHeight + 28);
                $("#cardsContainer").css("min-height", imageHeight + 5);
            }
        }
    });

    // Bind update damage function
    cardControl.client.UpdateHealth = (function (damage) {
        var curHealth = $.parseJSON(damage);
        var player = parseInt($('#playerNum').data("player"));
        var myDamage = curHealth[player - 1];
        updateHealth(myDamage);
    });

    // When called, requests a deal from the server
    cardControl.client.requestdeal = (function () {
        $("#shutdown").prop("checked", false).button("refresh");
        cardControl.server.dealMe($('#playerNum').data("player"));
    });

    // Once the page loads, get the player's first hand
    $.connection.hub.start().done(function () {
        cardControl.server.dealMe($('#playerNum').data("player"));
    });

    // Game has been reset, return to setup page
    cardControl.client.Reset = (function (resetAll) {
        if (resetAll == 0) {
            window.location = "/Player/playerSetup/" + $('#playerNum').data("player") + "?reset=1";
        }
        else
        {
            window.location = "/";
        }
    });

    // Displays a message from the server
    cardControl.client.displayMessage = (function (message, sound) {
        if (curDamage < 10) {
            $("#cardsContainer").html("
" + message + "
");
            switch (sound) {
                case "laser":
                    laserSound.play();
                    break;
                case "winner":
                    winnerSound.play();
                    break;
                case "flagTouch":
                    flagTouch.play();
                    break;
            }
        }
    });

    // Resize the cards as the window resizes, this is inelegant but works for now, should switch to entirely CSS solution
    $(window).resize(function () {
        var imageWidth = (($(window).width() - 80) / boxes);
        if (imageWidth < 350) {
            var percent = (imageWidth / 350);
            var imageHeight = percent * 520;
            $(".order").css("font-size", percent * 4 + "em");
            $(".face").css("font-size", percent * 11.8 + "em");
            $(".details").css("font-size", percent * 2.5 + "em");
            $("#cardsContainer img, .slot img").width(imageWidth);
            $("#cardsContainer img, .slot img").height(imageHeight);
            $("#cardsContainer li, .slot li").css({
                "height": "",
                "width": ""
            });
            $(".slot, #sendcards").width(imageWidth + 2);
            $(".slot, #sendcards").height(imageHeight + 28);
            $("#cardsContainer").css("min-height", imageHeight + 5);
        }
        else
        {
            $(".order").css("font-size", "2.15em");
            $("#cardsContainer img, .slot img").width(350);
            $("#cardsContainer img, .slot img").height(520);
            $("#cardsContainer li, .slot li").css({
                "height": "",
                "width": ""
            });
            $(".slot, #sendcards").width(352);
            $(".slot, #sendcards").height(548);
            $("#cardsContainer").css("min-height", 525);
        }
    });

    // Let the slots be droppable, accepting the card elements
    $(".slot").droppable({
        accept: "#cardsContainer > li, .slot li",
        hoverClass: "ui-state-hover",
        drop: function (event, ui) {
            if ($(ui.draggable).parent().hasClass("slotList")) {
                $(ui.draggable).closest("div").droppable("enable");
            }
            $(ui.draggable).css({
                "top": 0,
                "right": 0,
                "left": 0,
                "bottom": 0
            });
            $(ui.draggable).detach().appendTo($("ul", this));
            $(this).droppable("disable");
        }
    });

    // Let the card area be droppable as well, accepting elements from the slots
    $("#cardsContainer").droppable({
        accept: ".slot li",
        activeClass: "custom-state-active",
        drop: function (event, ui) {
            $(ui.draggable).closest("div").droppable("enable");
            $(ui.draggable).css({
                "top": 0,
                "right": 0,
                "left": 0,
                "bottom": 0
            });
            $(ui.draggable).appendTo($(this));
        }
    });

    // Receives the robot's current health from the server
    function updateHealth(damage)
    {
        if (damage > curDamage)
        {
            damageSound.play();
        }
        $(".damageBox").css('background', 'none');
        if (damage >= 10) {
            $("#damage").html("Robot is dead! ");
            $("#cardsContainer").html("
Your robot has died!
");
        }
        else {
            $("#damage").html("Robot damage: ");
        }
        for (var i = 0; i <= damage; i++)
        {
            $("#damageBox_" + i).css('background', 'red');
        }
        curDamage = damage;
        // Gets the flags the robot has touched
        $.get("/Setup/Status", function (data) {
            var player = data.players[parseInt($('#playerNum').data("player")) - 1];
            updateFlags(player);
            updateLives(player);
        });
    }

    // Draws the flags and touched flags
    function updateFlags(player) {
        if (player.totalFlags > 0) {
            $("#flagBoxes").empty();
            for (var i = 0; i < player.totalFlags; i++) {
                $("#flagBoxes").append(' ');
                if (player.flags > i) {
                    $("#flag" + i).addClass("touchedFlag");
                }
            }
        } else {
            $(".flagInfo").remove();
        }
    }

    // Updates the life boxes
    function updateLives(player) {
        $(".lifeBox").css("background", "none");
        for (var i = 1; i <= player.lives; i++) {
            $("#lifeBox_" + i).css("background", "blue");
        }
        if (player.lives <=0)
        {
            $("#cardsContainer").html("
You lose :-(
");
        }
    }

    // Sends the selected cards to the server
    function sendCards() {
        if (!submitted) {
            submitted = true;
            if ($(".slot").has("li").length != $(".slot").length) {
                alert("Please fill all movement slots");
                submitted = false;
            }
            else {
                window.clearInterval(timer);
                $("#timer").empty();
                $("#submitButton").attr("src", "/images/cards/submitted.png");
                var shutdown = false;
                var move = new Array();
                $(".slot").each(function () {
                    move.push($("li", this).data("cardinfo"));
                });
                $(".ui-draggable").draggable("option", "disabled", true).css("cursor", "default");
                if ($('#shutdown').prop("checked")) {
                    shutdown = true;
                }
                cardControl.server.sendCards($('#playerNum').data("player"), move, shutdown);
                $("#slots").prepend("
Program Submitted
");
            }
        }
    }

    // Starts the countdown timer
    cardControl.client.startTimer = (function () {
        if (!submitted && !isShutdown) {
            timeRemaining = 30;
            $("#timer").html("
Time remaining: " + timeRemaining + "
");
            timerStarted.play();
            timer = setInterval(timerHandler, 1000);
        }
    });

    // Handles the countdown timer
    function timerHandler()
    {
        // Count down
        timeRemaining--;
        $("#timer").html("
Time remaining: " + timeRemaining + "
");
        if (timeRemaining == 0)
        {
            clearInterval(timer);
            // Deal random cards into the register slots
            $(".slot").each(function () {
                if (!$(this).has("li").length)
                {
                    var number = Math.floor((Math.random() * $('#cardsContainer li').length) + 1);
                    $('#cardsContainer li:nth-child(' + number + ')').detach().appendTo($(this).find('.slotList'));
                }
            });
            $(".ui-draggable").draggable("option", "disabled", true).css("cursor", "default");
            setTimeout(sendCards, 1500);
        }
    }
});<|endoftext|>


<commit_before>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.core',
  name: 'Int',
  extends: 'Property',

  properties: [
    'units',
    [ 'value', 0 ],
    [ 'adapt', function adaptInt(_, v) {
        // FUTURE: replace with Math.trunc() when available everywhere.
        return typeof v === 'number' ? Math.trunc(v) :
          v ? parseInt(v) :
          0 ;
      }
    ],
    [ 'fromString', function intFromString(str) {
        return str ? parseInt(str) : 0;
      }
    ]
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'String',
  extends: 'Property',

  // documentation: 'StringProperties coerce their arguments into Strings.',

  properties: [
    { class: 'Int', name: 'width' },
    [ 'adapt', function(_, a) {
        return typeof a === 'function' ? foam.String.multiline(a) :
               typeof a === 'number'   ? String(a)                :
               a && a.toString         ? a.toString()             :
                                         ''                       ;
      }
    ],
    [ 'value', '' ]
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Date',
  extends: 'Property',

  // documentation: 'Describes properties of type Date.',
  label: 'Date',

  properties: [
    {
      name: 'adapt',
      value: function (_, d) {
        if ( typeof d === 'number' ) return new Date(d);
        if ( typeof d === 'string' ) {
          var ret = new Date(d);

          if ( ret.toUTCString() === 'InvalidDate' ) throw 'Invalid Date: ' + d;

          return ret;
        }
        return d;
      }
    },
    {
      name: 'comparePropertyValues',
      value: function(o1, o2) {
        if ( ! o1 ) return o2 ? -1 : 0;
        if ( ! o2 ) return 1;

        return foam.Date.compare(o1, o2);
      }
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'DateTime',
  extends: 'Date',

  // documentation: 'Describes properties of type DateTime.',
  label: 'Date and time'
});

foam.CLASS({
  package: 'foam.core',
  name:  'Long',
  extends: 'Int',

  // documentation:  'Describes properties of type Long.',
  label: 'Round long numbers'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Float',
  extends: 'Int',

  // documentation:  'Describes properties of type Float.',
  label: 'Decimal numbers',

  properties: [
    [
      'adapt',
      function (_, v) {
        return typeof v === 'number' ? v : v ? parseFloat(v) : 0.0 ;
      }
    ]
  ]
});

/**
 No different than Float for JS, but useful when targeting with other languages.
 **/
foam.CLASS({
  package: 'foam.core',
  name: 'Double',
  extends: 'Float'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Function',
  extends: 'Property',

  // documentation: 'Describes properties of type Function.',
  label: 'Code that can be run',

  properties: [
    [
      'value',
      function() {}
    ],
    [
      'assertValue',
      function(value, prop) {
        this.assert(typeof value === 'function', prop.name, 'Cannot set to non function type.');
      }
    ]
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Blob',
  extends: 'Property',

  // documentation: 'A chunk of binary data.',
  label: 'Binary data',
});

// FUTURE: to be used by or replaced by Relationship axiom
foam.CLASS({
  package: 'foam.core',
  name: 'Reference',
  extends: 'Property',

  documentation:  'A foreign key reference to another Entity.',
  label: 'Reference to another object',

  properties: [
    {
      name: 'of',
      value: '',
      // documentation: 'The FOAM sub-type of this property.'
    },
    {
      name: 'subKey',
      value: 'ID',
      // documentation: 'The name of the key (a property of the other object) that this property references.'
    }
  ],
});

foam.CLASS({
  package: 'foam.core',
  name: 'Object',
  extends: 'Property',

  documentation: '',

  properties: [
    {
      name: 'fromJSON',
      value: function(value, ctx) {
        return foam.json.parse(value, null, ctx);
      }
    }
  ]
});

// TODO(adam): Better name for this?
foam.CLASS({
  package: 'foam.core',
  name: 'FObjectProperty',
  extends: 'Property',

  properties: [
    {
      name: 'of',
      value: 'FObject'
    },
    {
      name: 'fromJSON',
      value: function(json, ctx, prop) {
        return foam.json.parse(json, prop.of, ctx);
      }
    },
    {
      name: 'adapt',
      value: function(_, v, prop) {
        var of = foam.lookup(prop.of);

        return of.isInstance(v) ? v :
          ( v.class ? foam.lookup(v.class) : of ).create(v);
      }
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Array',
  extends: 'Property',

  properties: [
    {
      name: 'fromJSON',
      value: function(value, opt_ctx) {
        return foam.json.parse(value, null, opt_ctx);
      }
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'StringArray',
  extends: 'Property',

  // documentation: 'An array of String values.',
  label: 'List of text strings',

  properties: [
    {
      name: 'of',
      value: 'String',
      // documentation: 'The FOAM sub-type of this property.'
    },
    [
      'adapt',
      function(_, v, prop) {
        if ( ! Array.isArray(v) ) return v;

        var copy;
        for ( var i = 0 ; i < v.length ; i++ ) {
          if ( typeof v[i] !== 'string' ) {
            if ( ! copy ) copy = v.slice();
            copy[i] = '' + v[i];
          }
        }

        return copy || v;
      }
    ],
    [
      'assertValue',
      function(v, prop) {
        this.assert(Array.isArray(v),
                    prop.name, 'Tried to set StringArray to non-array type.');
        for ( var i = 0 ; i < v.length ; i++ ) {
          this.assert(typeof v[i] === 'string',
                      prop.name, 'Element', i, 'is not a string', v[i]);
        }
      }
    ]
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Class',
  extends: 'Property',

  // documentation: 'Stores a class, and can accept a class name.',

  properties: [
    {
      /** FUTURE: adding to the default getter/setter chains is difficult
        when we want to preserve the existing behavior but add an additional
        step. This adapt work could be done in a getter that decorates the
        default getter, but dealing with normal and expression cases is necessary
        if writing back the looked-up class instance. */
      name: 'adapt',
      value: function(old, nu, prop) {
        if ( typeof nu === 'string' ) {
          if ( ! nu ) return '';
          var ret = this.__context__.lookup(nu);
          this.assert(ret && ret.isSubClass, 'Invalid class name ' +
             nu + ' specified for ' + prop.name);
          return ret;
        }
        this.assert(typeof nu === 'undefined' || ( nu && nu.isSubClass ),
          'Invalid class specified for ' +
          prop.name);
        return nu;
      }
    }
  ]
});

//TODO(adamvy): Replace Class property with Class2 property.
foam.CLASS({
  package: 'foam.core',
  name: 'Class2',
  extends: 'Property',

  methods: [
    function installInProto(proto) {
      this.SUPER(proto);

      var name = this.name;

      Object.defineProperty(proto, name + '$cls', {
        get: function classGetter() {
          if ( typeof this[name] !== 'string' ) return this[name];
          return this.__context__.lookup(this[name], true);
        },
        configurable: true
      });
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'ReferenceArray',
  extends: 'Reference',

  properties: [
    [ 'factory', function() { return []; } ]
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'EMail',
  extends: 'String',
  // FUTURE: verify
  label: 'Email address'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Image',
  extends: 'String',
  // FUTURE: verify
  label: 'Image data or link'
});

foam.CLASS({
  package: 'foam.core',
  name: 'URL',
  extends: 'String',
  // FUTURE: verify
  label: 'Web link (URL or internet address)'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Color',
  extends: 'String',
  label: 'Color'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Password',
  extends: 'String',
  label: 'Password that displays protected or hidden text'
});

foam.CLASS({
  package: 'foam.core',
  name: 'PhoneNumber',
  extends: 'String',
  label: 'Phone number'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Map',
  extends: 'Property',

  properties: [
    ['factory', function() { return {} }],
    'of'
  ]
});

// TODO(adamvy): Remove this once I take the class factory stuff out.
foam.CLASS({
  package: 'foam.core',
  name: 'Promised2',
  extends: 'Property',

  properties: [
    {
      name: 'of',
      required: true
    },
    'methods'
  ],

  methods: [
    function installInClass(cls) {
      var propName = this.name;

      var target = foam.lookup(this.of);

      var methods = target.getAxiomsByClass(foam.core.Method)
          .filter(function(m) { return target.hasOwnAxiom(m.name); });

      if ( this.methods ) {
        var ms = this.methods;
        methods = methods.filter(function(m) {
          return ms.indexOf(m.name) !== -1;
        });
      }

      methods.map(function(m) {
        var name = m.name;
        var returns = m.returns;

        if ( ! returns ) {
          var code = function() {
            var self = this;
            var args = arguments;
            this[propName].then(function(a) {
              a[name].apply(a, args);
            });
          };
        } else if ( returns === 'Promise' ) {
          code = function() {
            var self = this;
            var args = arguments;
            return this[propName].then(function(a) {
              return a[name].apply(a, args);
            });
          };
        } else {
          // TODO(adamvy): Use modelFactories

          var path = m.returns.split('.');
          path[path.length - 1] = 'Promised' + path[path.length - 1];

          var returnClsId = path.join('.');

          if ( ! foam.lookup(returnClsId) ) {
            foam.CLASS({
              package: path.slice(0, path.length - 1).join('.'),
              name: path[path.length - 1]
            });

            // Done in two passes to prevent infinite recursion.
            foam.CLASS({
              refines: returnClsId,
              properties: [
                {
                  class: 'Promised',
                  of: m.returns,
                  name: 'delegate'
                }
              ]
            });
          }

          code = function() {
            var self = this;
            var args = arguments;
            return foam.lookup(returnClsId).create({
              delegate: this[propName].then(function(d) {
                return d[name].apply(d, args);
              })
            });
          };
        }

        foam.Function.setName(code, name);

        return foam.core.Method.create({
          name: name,
          code: code
        });
      }).forEach(function(m) {
        cls.installAxiom(m);
      });

      cls.installAxiom(foam.core.Method.create({
        name: 'sub',
        code: function() {
          var innerSub = Array.from(arguments);
          var topic = innerSub.slice(0, innerSub.length-1);
          innerSub[innerSub.length-1] = foam.Function.bind(function(s) {
            var args = Array.from(arguments).slice(1);
            var c = this.pub.apply(this, args);
            if ( ! c ) s.destroy();
          }, this);

          this[propName].then(function(d) {
            d.sub.apply(d, innerSub);
          });

          return this.SUPER.apply(this, arguments);
        }
      }));
    }
  ]
});
<commit_msg>Formatting.<commit_after>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.core',
  name: 'Int',
  extends: 'Property',

  properties: [
    'units',
    [ 'value', 0 ],
    [ 'adapt', function adaptInt(_, v) {
        // FUTURE: replace with Math.trunc() when available everywhere.
        return typeof v === 'number' ? Math.trunc(v) :
          v ? parseInt(v) :
          0 ;
      }
    ],
    [ 'fromString', function intFromString(str) {
        return str ? parseInt(str) : 0;
      }
    ]
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'String',
  extends: 'Property',

  documentation: 'StringProperties coerce their arguments into Strings.',

  properties: [
    { class: 'Int', name: 'width' },
    [ 'adapt', function(_, a) {
        return typeof a === 'function' ? foam.String.multiline(a) :
               typeof a === 'number'   ? String(a)                :
               a && a.toString         ? a.toString()             :
                                         ''                       ;
      }
    ],
    [ 'value', '' ]
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Date',
  extends: 'Property',

  // documentation: 'Describes properties of type Date.',
  label: 'Date',

  properties: [
    {
      name: 'adapt',
      value: function (_, d) {
        if ( typeof d === 'number' ) return new Date(d);
        if ( typeof d === 'string' ) {
          var ret = new Date(d);

          if ( ret.toUTCString() === 'InvalidDate' ) throw 'Invalid Date: ' + d;

          return ret;
        }
        return d;
      }
    },
    {
      name: 'comparePropertyValues',
      value: function(o1, o2) {
        if ( ! o1 ) return o2 ? -1 : 0;
        if ( ! o2 ) return 1;

        return foam.Date.compare(o1, o2);
      }
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'DateTime',
  extends: 'Date',

  documentation: 'Describes properties of type DateTime.',
  label: 'Date and time'
});

foam.CLASS({
  package: 'foam.core',
  name:  'Long',
  extends: 'Int',

  documentation:  'Describes properties of type Long.',
  label: 'Round long numbers'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Float',
  extends: 'Int',

  // documentation:  'Describes properties of type Float.',
  label: 'Decimal numbers',

  properties: [
    [
      'adapt',
      function (_, v) {
        return typeof v === 'number' ? v : v ? parseFloat(v) : 0.0 ;
      }
    ]
  ]
});

/**
 No different than Float for JS, but useful when targeting with other languages.
 **/
foam.CLASS({
  package: 'foam.core',
  name: 'Double',
  extends: 'Float'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Function',
  extends: 'Property',

  documentation: 'Describes properties of type Function.',
  label: 'Code that can be run',

  properties: [
    [
      'value',
      function() {}
    ],
    [
      'assertValue',
      function(value, prop) {
        this.assert(typeof value === 'function', prop.name, 'Cannot set to non function type.');
      }
    ]
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Blob',
  extends: 'Property',

  // documentation: 'A chunk of binary data.',
  label: 'Binary data',
});

// FUTURE: to be used by or replaced by Relationship axiom
foam.CLASS({
  package: 'foam.core',
  name: 'Reference',
  extends: 'Property',

  documentation:  'A foreign key reference to another Entity.',
  label: 'Reference to another object',

  properties: [
    {
      name: 'of',
      value: '',
      documentation: 'The FOAM sub-type of this property.'
    },
    {
      name: 'subKey',
      value: 'ID',
      documentation: 'The name of the key (a property of the other object) that this property references.'
    }
  ],
});

foam.CLASS({
  package: 'foam.core',
  name: 'Object',
  extends: 'Property',

  documentation: '',

  properties: [
    {
      name: 'fromJSON',
      value: function(value, ctx) {
        return foam.json.parse(value, null, ctx);
      }
    }
  ]
});

// TODO(adam): Better name for this?
foam.CLASS({
  package: 'foam.core',
  name: 'FObjectProperty',
  extends: 'Property',

  properties: [
    {
      name: 'of',
      value: 'FObject'
    },
    {
      name: 'fromJSON',
      value: function(json, ctx, prop) {
        return foam.json.parse(json, prop.of, ctx);
      }
    },
    {
      name: 'adapt',
      value: function(_, v, prop) {
        var of = foam.lookup(prop.of);

        return of.isInstance(v) ? v :
          ( v.class ? foam.lookup(v.class) : of ).create(v);
      }
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Array',
  extends: 'Property',

  properties: [
    {
      name: 'fromJSON',
      value: function(value, opt_ctx) {
        return foam.json.parse(value, null, opt_ctx);
      }
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'StringArray',
  extends: 'Property',

  documentation: 'An array of String values.',
  label: 'List of text strings',

  properties: [
    {
      name: 'of',
      value: 'String',
      documentation: 'The FOAM sub-type of this property.'
    },
    [
      'adapt',
      function(_, v, prop) {
        if ( ! Array.isArray(v) ) return v;

        var copy;
        for ( var i = 0 ; i < v.length ; i++ ) {
          if ( typeof v[i] !== 'string' ) {
            if ( ! copy ) copy = v.slice();
            copy[i] = '' + v[i];
          }
        }

        return copy || v;
      }
    ],
    [
      'assertValue',
      function(v, prop) {
        this.assert(Array.isArray(v),
            prop.name, 'Tried to set StringArray to non-array type.');
        for ( var i = 0 ; i < v.length ; i++ ) {
          this.assert(typeof v[i] === 'string',
              prop.name, 'Element', i, 'is not a string', v[i]);
        }
      }
    ]
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'Class',
  extends: 'Property',

  documentation: 'Stores a class, and can accept a class name.',

  properties: [
    {
      /** FUTURE: adding to the default getter/setter chains is difficult
        when we want to preserve the existing behavior but add an additional
        step. This adapt work could be done in a getter that decorates the
        default getter, but dealing with normal and expression cases is necessary
        if writing back the looked-up class instance. */
      name: 'adapt',
      value: function(old, nu, prop) {
        if ( typeof nu === 'string' ) {
          if ( ! nu ) return '';
          var ret = this.__context__.lookup(nu);
          this.assert(ret && ret.isSubClass, 'Invalid class name ' +
             nu + ' specified for ' + prop.name);
          return ret;
        }
        this.assert(typeof nu === 'undefined' || ( nu && nu.isSubClass ),
          'Invalid class specified for ' +
          prop.name);
        return nu;
      }
    }
  ]
});

//TODO(adamvy): Replace Class property with Class2 property.
foam.CLASS({
  package: 'foam.core',
  name: 'Class2',
  extends: 'Property',

  methods: [
    function installInProto(proto) {
      this.SUPER(proto);

      var name = this.name;

      Object.defineProperty(proto, name + '$cls', {
        get: function classGetter() {
          if ( typeof this[name] !== 'string' ) return this[name];
          return this.__context__.lookup(this[name], true);
        },
        configurable: true
      });
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'ReferenceArray',
  extends: 'Reference',

  properties: [
    [ 'factory', function() { return []; } ]
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'EMail',
  extends: 'String',
  // FUTURE: verify
  label: 'Email address'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Image',
  extends: 'String',
  // FUTURE: verify
  label: 'Image data or link'
});

foam.CLASS({
  package: 'foam.core',
  name: 'URL',
  extends: 'String',
  // FUTURE: verify
  label: 'Web link (URL or internet address)'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Color',
  extends: 'String',
  label: 'Color'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Password',
  extends: 'String',
  label: 'Password that displays protected or hidden text'
});

foam.CLASS({
  package: 'foam.core',
  name: 'PhoneNumber',
  extends: 'String',
  label: 'Phone number'
});

foam.CLASS({
  package: 'foam.core',
  name: 'Map',
  extends: 'Property',

  properties: [
    ['factory', function() { return {} }],
    'of'
  ]
});

// TODO(adamvy): Remove this once I take the class factory stuff out.
foam.CLASS({
  package: 'foam.core',
  name: 'Promised2',
  extends: 'Property',

  properties: [
    {
      name: 'of',
      required: true
    },
    'methods'
  ],

  methods: [
    function installInClass(cls) {
      var propName = this.name;

      var target = foam.lookup(this.of);

      var methods = target.getAxiomsByClass(foam.core.Method)
          .filter(function(m) { return target.hasOwnAxiom(m.name); });

      if ( this.methods ) {
        var ms = this.methods;
        methods = methods.filter(function(m) {
          return ms.indexOf(m.name) !== -1;
        });
      }

      methods.map(function(m) {
        var name = m.name;
        var returns = m.returns;

        if ( ! returns ) {
          var code = function() {
            var self = this;
            var args = arguments;
            this[propName].then(function(a) {
              a[name].apply(a, args);
            });
          };
        } else if ( returns === 'Promise' ) {
          code = function() {
            var self = this;
            var args = arguments;
            return this[propName].then(function(a) {
              return a[name].apply(a, args);
            });
          };
        } else {
          // TODO(adamvy): Use modelFactories

          var path = m.returns.split('.');
          path[path.length - 1] = 'Promised' + path[path.length - 1];

          var returnClsId = path.join('.');

          if ( ! foam.lookup(returnClsId) ) {
            foam.CLASS({
              package: path.slice(0, path.length - 1).join('.'),
              name: path[path.length - 1]
            });

            // Done in two passes to prevent infinite recursion.
            foam.CLASS({
              refines: returnClsId,
              properties: [
                {
                  class: 'Promised',
                  of: m.returns,
                  name: 'delegate'
                }
              ]
            });
          }

          code = function() {
            var self = this;
            var args = arguments;
            return foam.lookup(returnClsId).create({
              delegate: this[propName].then(function(d) {
                return d[name].apply(d, args);
              })
            });
          };
        }

        foam.Function.setName(code, name);

        return foam.core.Method.create({
          name: name,
          code: code
        });
      }).forEach(function(m) {
        cls.installAxiom(m);
      });

      cls.installAxiom(foam.core.Method.create({
        name: 'sub',
        code: function() {
          var innerSub = Array.from(arguments);
          var topic = innerSub.slice(0, innerSub.length-1);
          innerSub[innerSub.length-1] = foam.Function.bind(function(s) {
            var args = Array.from(arguments).slice(1);
            var c = this.pub.apply(this, args);
            if ( ! c ) s.destroy();
          }, this);

          this[propName].then(function(d) {
            d.sub.apply(d, innerSub);
          });

          return this.SUPER.apply(this, arguments);
        }
      }));
    }
  ]
});
<|endoftext|>


<commit_before>(function($, $$){

	// TODO put default options here
	var defaults = {
		minZoom: 0.001,
		maxZoom: 1000,
		maxPan: -1 >>> 1,
		minPan: (-(-1>>>1)-1),
		selectionToPanDelay: 500,
		dragToSelect: true,
		dragToPan: true,

		defaultNodeStyle: {
			shape: "ellipse",
			height: 10,
			width: 10
		},

		defaultEdgeStyle: {
		}
	};

	function CanvasRenderer(options) {
		this.options = $.extend(true, {}, defaults, options);
		this.cy = options.cy;

		this.initStyle();
		this.transform = [1, 0, 0, 1, 0, 0];

		var container = this.options.cy.container();
		var canvas2d = document.createElement("canvas");
		canvas2d.width = container.width();
		canvas2d.height = container.height();

		this.context = canvas2d.getContext("2d");

		container.append(canvas2d);
	}

	CanvasRenderer.prototype.notify = function(params) {
		// console.log("notify call: " + params);
		// console.log(params);

		switch (params.type) {
			case "load":
				break;
			case "draw":
				console.log("draw call");
			default:
				console.log("event: " + params.type);
		}

		this.redraw();
	};

	CanvasRenderer.prototype.initStyle = function() {
		var nodes = this.options.cy.nodes();
		var edges = this.options.cy.edges();

		var node;
		for (var index = 0; index < nodes.length; index++) {
			node = nodes[index];

			node._private.style = defaults.defaultNodeStyle;

			node.boundingRadiusSquared = 6;
		}

		var edge;
		for (var index = 0; index < edges.length; index++) {
			edge = edges[index];

			edge._private.style = defaults.defaultEdgeStyle;
		}
	}

	CanvasRenderer.prototype.redraw = function() {
		var context = this.context;

		context.setTransform(1, 0, 0, 1, 0, 0);
		context.clearRect(0, 0, this.options.cy.container().width(),
			this.options.cy.container().height());
		context.setTransform(this.transform[0], this.transform[1], this.transform[2],
			this.transform[3], this.transform[4], this.transform[5]);

		//console.log("draw called");
		var nodes = this.options.cy.nodes();
		var edges = this.options.cy.edges();

		var edge;

		context.strokeStyle = "#CDCDCD";

		var startNode, endNode;
		for (var index = 0; index < edges.length; index++) {
			edge = edges[index];
			startNode = edge.source()[0];
			endNode = edge.target()[0];

			context.lineWidth = edge._private.data.weight / 16.0;
			context.beginPath();

			context.moveTo(startNode._private.position.x, startNode._private.position.y);

			context.quadraticCurveTo(startNode._private.position.x * 2 / 3,
				endNode._private.position.y, endNode._private.position.x,
				endNode._private.position.y);

			//context.lineTo(endNode._private.position.x, endNode._private.position.y);

			context.stroke();
		}

		var node;
		context.fillStyle = "#AAAAAA";
		for (var index = 0; index < nodes.length; index++) {
			node = nodes[index];

			context.beginPath();
			context.arc(node._private.position.x, node._private.position.y,
				node._private.data.weight / 5.0, 0, Math.PI * 2, false);
			context.closePath();
			context.fill();
		}
	};

	CanvasRenderer.prototype.zoom = function(params){
		// console.log(params);
		if (params != undefined) {
			this.transform[0] = params.level;
			this.transform[3] = params.level;

			/*
			this.transform[4] -= params.level;
			this.transform[5] -= params.level;
			*/
		}

		this.redraw();
	};

	CanvasRenderer.prototype.fit = function(params){

	};

	CanvasRenderer.prototype.pan = function(params){
		//console.log("pan called:");
		//console.log(params);

		if (this.context != undefined) {

		}
	};

	CanvasRenderer.prototype.panBy = function(params){
		this.transform[4] += params.x;
		this.transform[5] += params.y;

		this.redraw();
	};

	CanvasRenderer.prototype.showElements = function(element){

	};

	CanvasRenderer.prototype.hideElements = function(element){

	};

	CanvasRenderer.prototype.elementIsVisible = function(element){

	};

	CanvasRenderer.prototype.renderedDimensions = function(){

	};

	$$("renderer", "canvas", CanvasRenderer);

})( jQuery, jQuery.cytoscape );<commit_msg>Zoom now uses center of screen as origin, can now pan by dragging the background, initial implementation for mouse wheel zooming that notifies the Cytoscape Web slider GUI<commit_after>(function($, $$){

	// TODO put default options here
	var defaults = {
		minZoom: 0.001,
		maxZoom: 1000,
		maxPan: -1 >>> 1,
		minPan: (-(-1>>>1)-1),
		selectionToPanDelay: 500,
		dragToSelect: true,
		dragToPan: true,

		defaultNodeStyle: {
			shape: "ellipse",
			height: 10,
			width: 10
		},

		defaultEdgeStyle: {
		}
	};

	function CanvasRenderer(options) {
		this.options = $.extend(true, {}, defaults, options);
		this.cy = options.cy;

		this.init();
	}

	CanvasRenderer.prototype.notify = function(params) {
		console.log("notify call: " + params);
		console.log(params);

		switch (params.type) {
			case "load":
				break;
			case "draw":
				console.log("draw call");
				break;
			default:
				console.log("event: " + params.type);
		}

		this.redraw();
	};

	CanvasRenderer.prototype.init = function() {
		this.initStyle();

		var container = this.options.cy.container();
		var canvas2d = document.createElement("canvas");
		canvas2d.width = container.width();
		canvas2d.height = container.height();

		this.canvas = canvas2d;
		this.context = canvas2d.getContext("2d");

		container.append(canvas2d);

		this.center = [container.width() / 2, container.height() / 2];
		this.scale = [1, 1];
		this.zoomCenter = [container.width() / 2, container.height() / 2];

		var startX, startY;
		var initialCenter;

		$(window).bind("mousedown", function(mouseDownEvent) {
			if (mouseDownEvent.button != 0) {
				return;
			}

			if (mouseDownEvent.target != canvas2d) {
				return;
			}

			startX = mouseDownEvent.clientX;
			startY = mouseDownEvent.clientY;
			initialCenter = [cy.renderer().center[0], cy.renderer().center[1]];

			//console.log("mouse down");
			$(window).bind("mousemove", dragHandler);

			console.log(mouseDownEvent);
		});

		var dragHandler = function(mouseMoveEvent) {
			//console.log("mouseDrag");
			//console.log(mouseMoveEvent);
			//console.log("start: (" + startX + ", " + startY + ")");

			var offsetX = mouseMoveEvent.clientX - startX;
			var offsetY = mouseMoveEvent.clientY - startY;

			cy.renderer().center[0] = initialCenter[0] - offsetX / cy.renderer().scale[0];
			cy.renderer().center[1] = initialCenter[1] - offsetY / cy.renderer().scale[1];
			cy.renderer().redraw();
		};

		$(window).bind("mouseup", function(mouseUpEvent) {
			/*
			console.log("mouse up");
			console.log(mouseUpEvent);
			*/
			$(window).unbind("mousemove", dragHandler);
		});

		$(window).bind("mousewheel", function(event, delta, deltaX, deltaY){
			console.log("mousewheel");
			console.log(event);
			console.log(delta);
			console.log(deltaX);
			console.log(deltaY);

			// self.zoomAboutPoint(point, zoom);
			/*
			self.cy.trigger("zoom");
			self.cy.trigger("pan");
			*/
		});
	}

	CanvasRenderer.prototype.initStyle = function() {
		var nodes = this.options.cy.nodes();
		var edges = this.options.cy.edges();

		var node;
		for (var index = 0; index < nodes.length; index++) {
			node = nodes[index];

			node._private.style = defaults.defaultNodeStyle;

			node.boundingRadiusSquared = 6;
		}

		var edge;
		for (var index = 0; index < edges.length; index++) {
			edge = edges[index];

			edge._private.style = defaults.defaultEdgeStyle;
		}
	}

	CanvasRenderer.prototype.redraw = function() {
		var context = this.context;

		context.setTransform(1, 0, 0, 1, 0, 0);
		context.clearRect(0, 0, this.options.cy.container().width(),
			this.options.cy.container().height());

		context.translate(this.zoomCenter[0],
			this.zoomCenter[1]);

		context.scale(this.scale[0], this.scale[1])
		context.translate(-this.center[0], -this.center[1])

		/*
		context.transform(this.transform[0], this.transform[1], this.transform[2],
			this.transform[3], this.transform[4] * this.transform[0],
			this.transform[5] * this.transform[3]);
		*/

		//console.log("draw called");
		var nodes = this.options.cy.nodes();
		var edges = this.options.cy.edges();

		var edge;

		context.strokeStyle = "#CDCDCD";

		var startNode, endNode;
		for (var index = 0; index < edges.length; index++) {
			edge = edges[index];
			startNode = edge.source()[0];
			endNode = edge.target()[0];

			context.lineWidth = edge._private.data.weight / 16.0;
			context.beginPath();

			context.moveTo(startNode._private.position.x, startNode._private.position.y);

			context.quadraticCurveTo(startNode._private.position.x * 2 / 3,
				endNode._private.position.y, endNode._private.position.x,
				endNode._private.position.y);

			//context.lineTo(endNode._private.position.x, endNode._private.position.y);

			context.stroke();
		}

		var node;
		context.fillStyle = "#AAAAAA";
		for (var index = 0; index < nodes.length; index++) {
			node = nodes[index];

			context.beginPath();
			context.arc(node._private.position.x, node._private.position.y,
				node._private.data.weight / 5.0, 0, Math.PI * 2, false);
			context.closePath();
			context.fill();
		}
	};

	CanvasRenderer.prototype.zoom = function(params){
		// console.log(params);
		if (params != undefined && params.level != undefined) {

			this.scale[0] = params.level;
			this.scale[1] = params.level;

			/*
			this.transform[4] = this.transform[4] - 300 * params.level;
			this.transform[5] = this.transform[5] - 300 * params.level;
			*/
		}

		this.redraw();
	};

	CanvasRenderer.prototype.fit = function(params){

	};

	CanvasRenderer.prototype.pan = function(params){
		//console.log("pan called:");
		//console.log(params);

		if (this.context != undefined) {

		}
	};

	CanvasRenderer.prototype.panBy = function(params){
		// this.transform[4] += params.x;
		// this.transform[5] += params.y;

		this.center[0] -= params.x;
		this.center[1] -= params.y;

		this.redraw();
	};

	CanvasRenderer.prototype.showElements = function(element){

	};

	CanvasRenderer.prototype.hideElements = function(element){

	};

	CanvasRenderer.prototype.elementIsVisible = function(element){

	};

	CanvasRenderer.prototype.renderedDimensions = function(){

	};

	$$("renderer", "canvas", CanvasRenderer);

})( jQuery, jQuery.cytoscape );<|endoftext|>


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

    function denormalizeOrders(orders) {
        if (!orders || !orders.length) {
            return [];
        }

        var currentSum = 0;
        return orders.map(function (order) {
            var total = order.price * order.amount;
            currentSum += total;
            return {
                id: order.id,
                price: order.price,
                amount: order.amount,
                total: total,
                sum: currentSum
            };
        });
    }

    function calculateStringLength(n, precision) {
        // Get initial string length with a given precision.
        var len = n.toFixed(precision).length;
        // Add some length for commas (e.g. 10,000,000.0000).
        return len + Math.floor(n.toFixed(0).length / 3);
    }

    function getMaxLengths(orders, pair) {
        var price = 0,
            amount = 0,
            total = 0,
            sum = 0;

        // Get max value for each column.
        orders.forEach(function (order) {
            if (order.price > price) {
                price = order.price;
            }
            if (order.amount > amount) {
                amount = order.amount;
            }
            if (order.total > total) {
                total = order.total;
            }
            if (order.sum > sum) {
                sum = order.sum;
            }
        });

        return {
            price: calculateStringLength(price, pair.priceAsset.precision),
            amount: calculateStringLength(amount, pair.amountAsset.precision),
            total: calculateStringLength(total, pair.priceAsset.precision),
            sum: calculateStringLength(sum, pair.priceAsset.precision)
        };
    }

    function OrderbookController() {
        var ctrl = this;

        ctrl.lineClick = function (index) {
            var order = ctrl.orders[index],
                cumulativeAmount = ctrl.orders.slice(0, index + 1).reduce(function (amountSum, order) {
                    return amountSum + order.amount;
                }, 0);

            ctrl.onClick(order.price, cumulativeAmount, order.sum);
        };

        ctrl.$onChanges = function (changes) {
            if (!changes.rawOrders) {
                return;
            }

            var denormPreviousValue = denormalizeOrders(changes.rawOrders.previousValue),
                denormCurrentValue = denormalizeOrders(changes.rawOrders.currentValue);

            if (!_.isEqual(denormPreviousValue, denormCurrentValue)) {
                ctrl.orders = denormCurrentValue;
                ctrl.lengths = getMaxLengths(ctrl.orders, ctrl.pair);
            }
        };
    }

    angular
        .module('app.dex')
        .component('wavesDexOrderbook', {
            controller: OrderbookController,
            bindings: {
                type: '@',
                name: '@',
                pair: '<',
                onClick: '<',
                rawOrders: '<orders'
            },
            templateUrl: 'dex/orderbook.component'
        });
})();
<commit_msg>drop scientific formatting<commit_after>(function () {
    'use strict';

    function denormalizeOrders(orders) {
        if (!orders || !orders.length) {
            return [];
        }

        var currentSum = 0;
        return orders.map(function (order) {
            var total = order.price * order.amount;
            currentSum += total;
            return {
                id: order.id,
                price: order.price,
                amount: order.amount,
                total: total,
                sum: currentSum
            };
        });
    }

    function calculateStringLength(n, precision) {
        // Get initial string length with a given precision.
        var len = n.toFixed(precision).length;
        // Add some length for commas (e.g. 10,000,000.0000).
        return len + Math.floor(n.toFixed(0).length / 3);
    }

    function getMaxLengths(orders, pair) {
        var price = 0,
            amount = 0,
            total = 0,
            sum = 0;

        // Get max value for each column.
        orders.forEach(function (order) {
            if (order.price > price) {
                price = order.price;
            }
            if (order.amount > amount) {
                amount = order.amount;
            }
            if (order.total > total) {
                total = order.total;
            }
            if (order.sum > sum) {
                sum = order.sum;
            }
        });

        return {
            price: calculateStringLength(price, pair.priceAsset.precision),
            amount: calculateStringLength(amount, pair.amountAsset.precision),
            total: calculateStringLength(total, pair.priceAsset.precision),
            sum: calculateStringLength(sum, pair.priceAsset.precision)
        };
    }

    function OrderbookController() {
        var ctrl = this;

        ctrl.lineClick = function (index) {
            var order = ctrl.orders[index],
                cumulativeAmount = ctrl.orders.slice(0, index + 1).reduce(function (amountSum, order) {
                    return amountSum + order.amount;
                }, 0);

            ctrl.onClick(Number(order.price).toFixed(8).replace(/\.?0+$/,""), cumulativeAmount, order.sum);
        };

        ctrl.$onChanges = function (changes) {
            if (!changes.rawOrders) {
                return;
            }

            var denormPreviousValue = denormalizeOrders(changes.rawOrders.previousValue),
                denormCurrentValue = denormalizeOrders(changes.rawOrders.currentValue);

            if (!_.isEqual(denormPreviousValue, denormCurrentValue)) {
                ctrl.orders = denormCurrentValue;
                ctrl.lengths = getMaxLengths(ctrl.orders, ctrl.pair);
            }
        };
    }

    angular
        .module('app.dex')
        .component('wavesDexOrderbook', {
            controller: OrderbookController,
            bindings: {
                type: '@',
                name: '@',
                pair: '<',
                onClick: '<',
                rawOrders: '<orders'
            },
            templateUrl: 'dex/orderbook.component'
        });
})();
<|endoftext|>


<commit_before>/*----------------------------------------------------------------------------------*
 *                         Computed Style                                           *
 *----------------------------------------------------------------------------------*/

(function(window) {

var cssProperties = [
];

var useInternalComputedStyle = typeof window.getComputedStyle === "undefined";
if (!useInternalComputedStyle) {
  // Detect partial native implementations
  try {
    var computedStyle, width;

    computedStyle = document.defaultView.getComputedStyle(document.documentElement, null);
    width = computedStyle.getPropertyCSSValue('width');
    width = width.getFloatValue(CSSPrimitiveValue.CSS_PX);
  } catch (e) {
    useInternalComputedStyle = true;
    cssProperties = computedStyle;

    var _nativeGetComputedStyle = document.defaultView.getComputedStyle;
    var _internalGetCurrentStyle = function(element, property, ieProperty) {
      var computedStyle = _nativeGetComputedStyle.call(document.defaultView, element, null);
      return computedStyle.getPropertyValue(property);
    }
  }
} else {
  var _internalGetCurrentStyle = function(element, property, ieProperty) {
    var value = element.currentStyle[ieProperty];

    if (value == 'auto')
      value = element.runtimeStyle[ieProperty];

    return value;
  }
}

if (useInternalComputedStyle) {
  /**
    * Partial implementation of CSSPrimitiveValue.
    */
  function CSSPrimitiveValue(element, property, ieProperty) {
    if (arguments.length == 0)
      return;

    this._element = element;
    this._property = property;
    this._ieProperty = ieProperty;

    this.cssText = _internalGetCurrentStyle(this._element,
                                            this._property,
                                            this._ieProperty);
  }
  CSSPrimitiveValue.CSS_PX = 1;
  CSSPrimitiveValue._ValueRegExp = new RegExp('\(\\d+|\\d+.\\d+\)\(\\w+\)');

  CSSPrimitiveValue.prototype.getFloatValue = function(unit) {
    switch (unit) {
    case CSSPrimitiveValue.CSS_PX:
      if (this.cssText == "")
        return 0;

      var parentNode = this._element.parentNode;
      var testElement = this._element.ownerDocument.createElement('div');
      testElement.style.visibility = "hidden";
      testElement.style.padding = "0";
      testElement.style.margin = "0";
      testElement.style.border = "0";

      var matching = /border-(top|right|bottom|left)-width/.exec(this._property);
      var side = matching !== null ? matching[1] : null;

      // Test if the css value has a basic value (px, em, ex)
      matching = CSSPrimitiveValue._ValueRegExp.exec(this.cssText);
      if (matching != null) {
        var value = matching[1];
        var units = matching[2];
        if (units == "px") {
          // Value is already in pixels
          return parseInt(value);
        } else {
          testElement.style.height = this.cssText;
        }
      } else if ((matching == null) && (side != null)) {
        var property = 'border-' + side + '-style';
        var ieProperty = ComputedCSSStyleDeclaration.prototype._getIEProperty(property);
        var borderStyle = _internalGetCurrentStyle(this._element, property, ieProperty);
        if (borderStyle == "none")
          return 0;

        // border width accepts special values: medium, normal, ...
        var extraElement = this._element.ownerDocument.createElement('div');
        testElement.style.fontSize = "0";
        testElement.style.lineHeight = "0";
        extraElement.style.padding = "0";
        extraElement.style.margin = "0";
        extraElement.style.border = "0";
        extraElement.style.width = "1px";
        extraElement.style.borderTopWidth = this.cssText;
        extraElement.style.borderTopStyle = borderStyle;
        testElement.appendChild(extraElement);
      } else {
        throw new Error();
      }

      parentNode.appendChild(testElement);

      if (testElement.offsetHeight != null) {
        var result = testElement.offsetHeight;
      } else {
        throw new Error();
      }

      parentNode.removeChild(testElement);

      return result;
    default:
      throw new Error();
    }
  }

  CSSPrimitiveValue._rgbaColorParser = new RegExp('rgba\\\(\\s*\(\\d+\)\\s*,\\s*\(\\d+\)\\s*,\\s*\(\\d+\)\\s*\\\,\\s*\(\\d+\)\\s*\\\)');
  CSSPrimitiveValue._rgbColorParser = new RegExp('rgb\\\(\\s*\(\\d+\)\\s*,\\s*\(\\d+\)\\s*,\\s*\(\\d+\)\\s*\\\)');
  CSSPrimitiveValue._hexColorParser = new RegExp('#\([0-9A-F]{2}\)\([0-9A-F]{2}\)\([0-9A-F]{2}\)', 'i');
  /**
    *
    */
  CSSPrimitiveValue.prototype.getRGBColorValue = function() {
  switch (this._property) {
    case 'background-color':
    case 'color':
      var red, green, blue, alpha = '1';
      var matching = CSSPrimitiveValue._rgbColorParser.exec(this.cssText);
      if (matching !== null) {
        red = matching[1];
        green = matching[2];
        blue = matching[3];
      } else {
        matching = CSSPrimitiveValue._rgbaColorParser.exec(this.cssText);
        if (matching !== null) {
          red = matching[1];
          green = matching[2];
          blue = matching[3];
          alpha = matching[4];
        } else {
          matching = CSSPrimitiveValue._hexColorParser.exec(this.cssText);
          if (matching === null) {
            var parentNode = this._element.parentNode;
            var testElement = this._element.ownerDocument.createElement('table');
            testElement.setAttribute('bgcolor', this.cssText);
            testElement.style.visibility = "hidden";
            parentNode.appendChild(testElement);
            var bgColor = testElement.bgColor;
            matching = CSSPrimitiveValue._hexColorParser.exec(bgColor);
            if (matching === null)
              throw new Error('Error on getRGBColorValue');

            parentNode.removeChild(testElement);
          }

          function hex2value(hex) {
            hex = hex.toUpperCase();
            return ("0123456789ABCDEF".indexOf(hex.substr(0,1)) * 16) +
                    "0123456789ABCDEF".indexOf(hex.substr(1,1));
          }

          // Build the result
          var red = hex2value(matching[1]);
          var green = hex2value(matching[2]);
          var blue = hex2value(matching[3]);
        }
      }

      var result = new Object();
      result.red = new CSSColorComponentValue(red);
      result.green = new CSSColorComponentValue(green);
      result.blue = new CSSColorComponentValue(blue);
      result.alpha = new CSSColorComponentValue(alpha);
      return result;
    default:
      throw new Error();
    }
  }

  /**
    *
    */
  function CSSColorComponentValue(value) {
    this.cssText = "" + value;
  }
  CSSColorComponentValue.prototype = new CSSPrimitiveValue();

  CSSColorComponentValue.prototype.getFloatValue = function(unit) {
    return parseInt(this.cssText);
  }

  /**
    * Partial implementation of ComputedCSSStyleDeclaration
    */
  function ComputedCSSStyleDeclaration(element) {
    var i;

    this._element = element;
    if (Object.defineProperty) {
      for (i = 0; i < cssProperties.length; i += 1) {
        this._defProp(cssProperties[i]);
      }
    }
  }

  ComputedCSSStyleDeclaration.prototype._defProp = function(property) {
    Object.defineProperty(this, property, {
      get: function () { return this.getPropertyValue(property); },
      enumerable: true,
      configurable: false
    });
  }

  ComputedCSSStyleDeclaration.prototype._getIEProperty = function(property) {
    switch (property) {
    case 'float':
      return "styleFloat";
    default:
      return property.replace(/-\w/g, function(a){return a.substr(1,1).toUpperCase()});
    }
  }

  ComputedCSSStyleDeclaration.prototype.getPropertyCSSValue = function(property) {
    return new CSSPrimitiveValue(this._element, property, this._getIEProperty(property));
  }

  ComputedCSSStyleDeclaration.prototype.getPropertyValue = function(property) {
    return _internalGetCurrentStyle(this._element,
                                    property,
                                    this._getIEProperty(property));
  }

  /**
    * WARNING This is not a full implementation of the getComputedStyle, some
    * things will not work.
    *
    * @param element
    * @param context not used by this implementation
    */
  window.CSSPrimitiveValue = CSSPrimitiveValue;
  window.CSSColorComponentValue = CSSColorComponentValue;
  window.getComputedStyle = function(element, context) {
    if (element == null) {
        throw new Error('Operation is not supported');
    }
    return new ComputedCSSStyleDeclaration(element);
  }

  if (window.document.defaultView === undefined) {
    window.document.defaultView = window;
  }
}

})(window);
<commit_msg>Optimize computed style work around on Chrome<commit_after>/*----------------------------------------------------------------------------------*
 *                         Computed Style                                           *
 *----------------------------------------------------------------------------------*/

(function(window) {

var cssProperties = [
];

var useInternalComputedStyle = typeof window.getComputedStyle === "undefined";
if (!useInternalComputedStyle) {
  // Detect partial native implementations
  try {
    var computedStyle, width;

    computedStyle = document.defaultView.getComputedStyle(document.documentElement, null);
    width = computedStyle.getPropertyCSSValue('width');
    width = width.getFloatValue(CSSPrimitiveValue.CSS_PX);
  } catch (e) {
    useInternalComputedStyle = true;
    cssProperties = computedStyle;

    var _nativeGetComputedStyle = document.defaultView.getComputedStyle;
    var _internalGetCurrentStyle = function(element, property, ieProperty) {
      var computedStyle = _nativeGetComputedStyle.call(document.defaultView, element, null);
      return computedStyle.getPropertyValue(property);
    }
  }
} else {
  var _internalGetCurrentStyle = function(element, property, ieProperty) {
    var value = element.currentStyle[ieProperty];

    if (value == 'auto')
      value = element.runtimeStyle[ieProperty];

    return value;
  }
}

if (useInternalComputedStyle) {
  /**
    * Partial implementation of CSSPrimitiveValue.
    */
  function CSSPrimitiveValue(element, property, ieProperty) {
    if (arguments.length == 0)
      return;

    this._element = element;
    this._property = property;
    this._ieProperty = ieProperty;

    this.cssText = _internalGetCurrentStyle(this._element,
                                            this._property,
                                            this._ieProperty);
  }
  CSSPrimitiveValue.CSS_PX = 1;
  CSSPrimitiveValue._ValueRegExp = new RegExp('\(\\d+|\\d+.\\d+\)\(\\w+\)');

  CSSPrimitiveValue.prototype.getFloatValue = function(unit) {
    switch (unit) {
    case CSSPrimitiveValue.CSS_PX:
      if (this.cssText == "")
        return 0;

      var parentNode = this._element.parentNode;
      var testElement = this._element.ownerDocument.createElement('div');
      testElement.style.visibility = "hidden";
      testElement.style.padding = "0";
      testElement.style.margin = "0";
      testElement.style.border = "0";

      var matching = /border-(top|right|bottom|left)-width/.exec(this._property);
      var side = matching !== null ? matching[1] : null;

      // Test if the css value has a basic value (px, em, ex)
      matching = CSSPrimitiveValue._ValueRegExp.exec(this.cssText);
      if (matching != null) {
        var value = matching[1];
        var units = matching[2];
        if (units == "px") {
          // Value is already in pixels
          return parseInt(value);
        } else {
          testElement.style.height = this.cssText;
        }
      } else if ((matching == null) && (side != null)) {
        var property = 'border-' + side + '-style';
        var ieProperty = ComputedCSSStyleDeclaration.prototype._getIEProperty(property);
        var borderStyle = _internalGetCurrentStyle(this._element, property, ieProperty);
        if (borderStyle == "none")
          return 0;

        // border width accepts special values: medium, normal, ...
        var extraElement = this._element.ownerDocument.createElement('div');
        testElement.style.fontSize = "0";
        testElement.style.lineHeight = "0";
        extraElement.style.padding = "0";
        extraElement.style.margin = "0";
        extraElement.style.border = "0";
        extraElement.style.width = "1px";
        extraElement.style.borderTopWidth = this.cssText;
        extraElement.style.borderTopStyle = borderStyle;
        testElement.appendChild(extraElement);
      } else {
        throw new Error();
      }

      parentNode.appendChild(testElement);

      if (testElement.offsetHeight != null) {
        var result = testElement.offsetHeight;
      } else {
        throw new Error();
      }

      parentNode.removeChild(testElement);

      return result;
    default:
      throw new Error();
    }
  }

  CSSPrimitiveValue._rgbaColorParser = new RegExp('rgba\\\(\\s*\(\\d+\)\\s*,\\s*\(\\d+\)\\s*,\\s*\(\\d+\)\\s*\\\,\\s*\(\\d+\)\\s*\\\)');
  CSSPrimitiveValue._rgbColorParser = new RegExp('rgb\\\(\\s*\(\\d+\)\\s*,\\s*\(\\d+\)\\s*,\\s*\(\\d+\)\\s*\\\)');
  CSSPrimitiveValue._hexColorParser = new RegExp('#\([0-9A-F]{2}\)\([0-9A-F]{2}\)\([0-9A-F]{2}\)', 'i');
  /**
    *
    */
  CSSPrimitiveValue.prototype.getRGBColorValue = function() {
  switch (this._property) {
    case 'background-color':
    case 'color':
      var red, green, blue, alpha = '1';
      var matching = CSSPrimitiveValue._rgbColorParser.exec(this.cssText);
      if (matching !== null) {
        red = matching[1];
        green = matching[2];
        blue = matching[3];
      } else {
        matching = CSSPrimitiveValue._rgbaColorParser.exec(this.cssText);
        if (matching !== null) {
          red = matching[1];
          green = matching[2];
          blue = matching[3];
          alpha = matching[4];
        } else {
          matching = CSSPrimitiveValue._hexColorParser.exec(this.cssText);
          if (matching === null) {
            var parentNode = this._element.parentNode;
            var testElement = this._element.ownerDocument.createElement('table');
            testElement.setAttribute('bgcolor', this.cssText);
            testElement.style.visibility = "hidden";
            parentNode.appendChild(testElement);
            var bgColor = testElement.bgColor;
            matching = CSSPrimitiveValue._hexColorParser.exec(bgColor);
            if (matching === null)
              throw new Error('Error on getRGBColorValue');

            parentNode.removeChild(testElement);
          }

          function hex2value(hex) {
            hex = hex.toUpperCase();
            return ("0123456789ABCDEF".indexOf(hex.substr(0,1)) * 16) +
                    "0123456789ABCDEF".indexOf(hex.substr(1,1));
          }

          // Build the result
          var red = hex2value(matching[1]);
          var green = hex2value(matching[2]);
          var blue = hex2value(matching[3]);
        }
      }

      var result = new Object();
      result.red = new CSSColorComponentValue(red);
      result.green = new CSSColorComponentValue(green);
      result.blue = new CSSColorComponentValue(blue);
      result.alpha = new CSSColorComponentValue(alpha);
      return result;
    default:
      throw new Error();
    }
  }

  /**
    *
    */
  function CSSColorComponentValue(value) {
    this.cssText = "" + value;
  }
  CSSColorComponentValue.prototype = new CSSPrimitiveValue();

  CSSColorComponentValue.prototype.getFloatValue = function(unit) {
    return parseInt(this.cssText);
  }

  /**
    * Partial implementation of ComputedCSSStyleDeclaration
    */
  function ComputedCSSStyleDeclaration(element) {
    var i;

    this._element = element;
  }

    if (Object.defineProperty) {
        var _defProp = function(object, property) {
            Object.defineProperty(object, property, {
                get: function () { return this.getPropertyValue(property); },
                enumerable: true,
                configurable: false
            });
        }

        for (i = 0; i < cssProperties.length; i += 1) {
            _defProp(ComputedCSSStyleDeclaration.prototype, cssProperties[i]);
        }
    }

  ComputedCSSStyleDeclaration.prototype._getIEProperty = function(property) {
    switch (property) {
    case 'float':
      return "styleFloat";
    default:
      return property.replace(/-\w/g, function(a){return a.substr(1,1).toUpperCase()});
    }
  }

  ComputedCSSStyleDeclaration.prototype.getPropertyCSSValue = function(property) {
    return new CSSPrimitiveValue(this._element, property, this._getIEProperty(property));
  }

  ComputedCSSStyleDeclaration.prototype.getPropertyValue = function(property) {
    return _internalGetCurrentStyle(this._element,
                                    property,
                                    this._getIEProperty(property));
  }

  /**
    * WARNING This is not a full implementation of the getComputedStyle, some
    * things will not work.
    *
    * @param element
    * @param context not used by this implementation
    */
  window.CSSPrimitiveValue = CSSPrimitiveValue;
  window.CSSColorComponentValue = CSSColorComponentValue;
  window.getComputedStyle = function(element, context) {
    if (element == null) {
        throw new Error('Operation is not supported');
    }
    return new ComputedCSSStyleDeclaration(element);
  }

  if (window.document.defaultView === undefined) {
    window.document.defaultView = window;
  }
}

})(window);
<|endoftext|>


<commit_before>
const Dataware = require('../index')
const assert = require('power-assert')

describe('bucket', function() {

  const dw = new Dataware({
    endpoint: 'localhost:27017'
  })
  const bucket = dw.bucket('test/testbucket')
  let tmpId = ''

  it('post object', function* () {
    const ret = yield bucket.body({ title: 'hello' }).post()
    assert(ret.data.title = 'hello')
    tmpId = ret.data._id
  })

  it('batch objects', function* () {
    const ret = yield bucket.body([
      { title: 't1' },
      { title: 't2' },
      { title: 't3' }
    ]).batch()
    assert(ret.data.length === 3)
    assert(ret.meta.ok === 1)
    assert(ret.meta.n === 3)
  })

  it('query objects', function* () {
    const ret = yield bucket.query({
      where: {
        title: { $in: ['t1', 't2', 't3'] }
      },
      limit: 3
    })
    assert(ret.length === 3)
  })

  it('get object', function* () {
    const ret = yield bucket.get(tmpId)
    assert(ret.data.title === 'hello')
    assert(ret.data._id.toString() === tmpId.toString())
  })

  it('patch object by id', function* () {
    const ret = yield bucket.body({ title: 'abc', desc: 'def' }).post()
    assert(ret.data.title === 'abc')
    assert(ret.data.desc === 'def')

    const storyId = ret.data._id
    const ret2 = yield bucket.body({ title: 'def' }).patch(storyId)
    assert(ret2.meta.ok === 1)
    assert(ret2.meta.nModified === 1)
    assert(ret2.meta.n === 1)

    const ret3 = yield bucket.get(storyId)
    assert(ret3.data.title === 'def')
    assert(ret3.data.desc === 'def')
  })

  it('patch object by query', function* () {
    const ret1 = yield bucket.body({ title: 'a', type: 1 }).post()
    const ret2 = yield bucket.body({ title: 'b', type: 1 }).post()
    assert(ret1.data.title === 'a')
    assert(ret2.data.title === 'b')
    const ret3 = yield bucket.body({ title: 'c' }).patch({
      type: {
        $eq: 1
      }
    })
    assert(ret3.meta.ok === 1)
    assert(ret3.meta.nModified === 2)
  })

  it('put object by id', function* () {
    const ret1 = yield bucket.body({ title: 'abc', desc: 'def' }).post()
    assert(ret1.data.title === 'abc')
    assert(ret1.data.desc === 'def')

    const storyId = ret1.data._id
    const ret2 = yield bucket.body({ title: 'def' }).put(storyId)
    assert(ret2.meta.ok === 1)
    assert(ret2.meta.nModified === 1)
    assert(ret2.meta.n === 1)

    const ret3 = yield bucket.get(storyId)
    assert(ret3.data.title === 'def')
    assert(ret3.data.desc === undefined)
  })

  it('remove object', function* () {
    yield bucket.body({ title: 'story title' }).post('test-story')
    const ret = yield bucket.remove('test-story')
    assert(ret.meta.ok === 1)
    assert(ret.meta.n === 1)
  })

  it('other bucket', function* () {
    const bkt = dw.bucket('test/testbucket2')
    const obj = yield bkt.body({ title: 'other' }).post()
    assert(obj.data.title === 'other')
    assert(obj.meta.ok === 1)
    assert(obj.meta.n === 1)
  })

  it('drop bucket', function* () {
    const ret = yield bucket.drop()
    assert(ret === true)
  })

})
<commit_msg>test: modify by query.<commit_after>
const Dataware = require('../index')
const assert = require('power-assert')

describe('bucket', function() {

  const dw = new Dataware({
    endpoint: 'localhost:27017'
  })
  const bucket = dw.bucket('test/testbucket')
  let tmpId = ''

  it('post object', function* () {
    const ret = yield bucket.body({ title: 'hello' }).post()
    assert(ret.data.title = 'hello')
    tmpId = ret.data._id
  })

  it('batch objects', function* () {
    const ret = yield bucket.body([
      { title: 't1' },
      { title: 't2' },
      { title: 't3' }
    ]).batch()
    assert(ret.data.length === 3)
    assert(ret.meta.ok === 1)
    assert(ret.meta.n === 3)
  })

  it('query objects', function* () {
    const ret = yield bucket.query({
      where: {
        title: { $in: ['t1', 't2', 't3'] }
      },
      limit: 3
    })
    assert(ret.length === 3)
  })

  it('get object', function* () {
    const ret = yield bucket.get(tmpId)
    assert(ret.data.title === 'hello')
    assert(ret.data._id.toString() === tmpId.toString())
  })

  it('patch object by id', function* () {
    const ret = yield bucket.body({ title: 'abc', desc: 'def' }).post()
    assert(ret.data.title === 'abc')
    assert(ret.data.desc === 'def')

    const storyId = ret.data._id
    const ret2 = yield bucket.body({ title: 'def' }).patch(storyId)
    assert(ret2.meta.ok === 1)
    assert(ret2.meta.nModified === 1)
    assert(ret2.meta.n === 1)

    const ret3 = yield bucket.get(storyId)
    assert(ret3.data.title === 'def')
    assert(ret3.data.desc === 'def')
  })

  it('patch object by query', function* () {
    const ret1 = yield bucket.body({ title: 'a', type: 1 }).post()
    const ret2 = yield bucket.body({ title: 'b', type: 1 }).post()
    assert(ret1.data.title === 'a')
    assert(ret2.data.title === 'b')
    const ret3 = yield bucket.body({ title: 'c' }).patch({
      type: {
        $eq: 1
      }
    })
    assert(ret3.meta.ok === 1)
    assert(ret3.meta.nModified === 2)
  })

  it('put object by id', function* () {
    const ret1 = yield bucket.body({ title: 'abc', desc: 'def' }).post()
    assert(ret1.data.title === 'abc')
    assert(ret1.data.desc === 'def')

    const storyId = ret1.data._id
    const ret2 = yield bucket.body({ title: 'def' }).put(storyId)
    assert(ret2.meta.ok === 1)
    assert(ret2.meta.nModified === 1)
    assert(ret2.meta.n === 1)

    const ret3 = yield bucket.get(storyId)
    assert(ret3.data.title === 'def')
    assert(ret3.data.desc === undefined)
  })

  it('put object by query', function* (){
    const ret = yield bucket.body({ title: 'abc', type: 'put' }).post()
    assert(ret.data.title === 'abc')

    const ret2 = yield bucket.body({ title: 'abcd', type: 'putquery' }).put({
      type: {
        $eq: 'put'
      }
    })
    assert(ret2.meta.ok === 1)
    assert(ret2.meta.nModified === 1)

    const ret3 = yield bucket.get(ret.data._id)
    assert(ret3.data.title === 'abcd')
    assert(ret3.data.type === 'putquery')
  })

  it('remove object by id', function* () {
    yield bucket.body({ title: 'story title' }).post('test-story')
    const ret = yield bucket.remove('test-story')
    assert(ret.meta.ok === 1)
    assert(ret.meta.n === 1)
  })

  it('remove object by query', function* (){
    yield bucket.body([{ title: 'a' }, { title: 'a' }]).batch()
    const ret = yield bucket.remove({
      title: {
        $eq: 'a'
      }
    })
    assert(ret.meta.ok === 1)
    assert(ret.meta.n === 2)
  })

  it('other bucket', function* () {
    const bkt = dw.bucket('test/testbucket2')
    const obj = yield bkt.body({ title: 'other' }).post()
    assert(obj.data.title === 'other')
    assert(obj.meta.ok === 1)
    assert(obj.meta.n === 1)
  })

  it('drop bucket', function* () {
    const ret = yield bucket.drop()
    assert(ret === true)
  })

})
<|endoftext|>