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

    function addDieRollResults(response) {
        var DIE_SIZE = 40,
            MARGIN = 20,
            $canvas,
            dicePerRow;

        $canvas = $('#dieRollResults');

        $canvas.clearCanvas();

        dicePerRow = Math.floor(($canvas.width() - 2 * MARGIN) / (DIE_SIZE + MARGIN));
        response.dieRollResults.forEach(function (dieRollResult, index) {
            var column,
                i,
                j,
                props,
                row,
                vertices,
                x,
                y;

            column = index % dicePerRow;
            x = MARGIN + column * (DIE_SIZE + MARGIN) + DIE_SIZE / 2;
            row = Math.floor(index / dicePerRow);
            y = MARGIN + row * (DIE_SIZE + MARGIN) + DIE_SIZE / 2;

            if (dieRollResult.sides === 4) {
                $canvas.drawPolygon({
                    radius: DIE_SIZE / 2,
                    rounded: true,
                    sides: 3,
                    strokeStyle: 'black',
                    x: x,
                    y: y
                });
                $canvas.drawText({
                    fillStyle: 'black',
                    fontSize: '1em',
                    text: dieRollResult.value.toString(),
                    x: x,
                    y: y
                });
            } else if (dieRollResult.sides === 6) {
                $canvas.drawRect({
                    height: DIE_SIZE,
                    rounded: true,
                    strokeStyle: 'black',
                    width: DIE_SIZE,
                    x: x,
                    y: y
                });
                $canvas.drawText({
                    fillStyle: 'black',
                    fontSize: '1em',
                    text: dieRollResult.value.toString(),
                    x: x,
                    y: y
                });
            } else if (dieRollResult.sides === 8) {
                vertices = [
                    { x:  0.0000000, y: -0.8164966 },
                    { x:  0.7071068, y: -0.4082483 },
                    { x:  0.7071068, y:  0.4082483 },
                    { x:  0.0000000, y:  0.8164966 },
                    { x: -0.7071068, y:  0.4082483 },
                    { x: -0.7071068, y: -0.4082483 }
                ];
                vertices.forEach(function (vertex) {
                    vertex.x *= DIE_SIZE / 1.5;
                    vertex.y *= DIE_SIZE / 1.5;
                });

                // draw line through vertices 1-5 (outer edge)
                props = {
                    closed: true,
                    rounded: true,
                    strokeStyle: 'black'
                };
                j = 1;
                for (i = 0; i < 6; i += 1) {
                    props['x' + j] = x + vertices[i].x;
                    props['y' + j] = y + vertices[i].y;
                    j += 1;
                }
                $canvas.drawLine(props);

                // draw lines between the following vertices (to complete
                // rendering the edges of the other 3 facets):
                //
                //    1 -> 3; 1 -> 5; 3 -> 5
                props = {
                    strokeStyle: 'black'
                };
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[0].x, y1: y + vertices[0].y,
                    x2: x + vertices[2].x, y2: y + vertices[2].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[0].x, y1: y + vertices[0].y,
                    x2: x + vertices[4].x, y2: y + vertices[4].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[2].x, y1: y + vertices[2].y,
                    x2: x + vertices[4].x, y2: y + vertices[4].y
                }));

                $canvas.drawText({
                    fillStyle: 'black',
                    fontSize: '1em',
                    text: dieRollResult.value.toString(),
                    x: x,
                    y: y
                });
            } else if (dieRollResult.sides === 12) {
                vertices = [
                    { x:  0.000000, y: -1.0922415 },
                    { x:  1.000000, y: -0.3660254 },
                    { x:  0.618034, y:  0.8090170 },
                    { x: -0.618034, y:  0.8090170 },
                    { x: -1.000000, y: -0.3660254 },
                    { x:  0.000000, y: -1.7102755 },
                    { x:  1.000000, y: -1.3660254 },
                    { x:  1.618034, y: -0.5352331 },
                    { x:  1.618034, y:  0.5352331 },
                    { x:  1.000000, y:  1.3660254 },
                    { x:  0.000000, y:  1.7102755 },
                    { x: -1.000000, y:  1.3660254 },
                    { x: -1.618034, y:  0.5352331 },
                    { x: -1.618034, y: -0.5352331 },
                    { x: -1.000000, y: -1.3660254 }
                ];
                vertices.forEach(function (vertex) {
                    vertex.x *= DIE_SIZE / 3;
                    vertex.y *= DIE_SIZE / 3;
                });

                // draw line through vertices 1-5 (edges of top facet)
                props = {
                    closed: true,
                    rounded: true,
                    strokeStyle: 'black'
                };
                j = 1;
                for (i = 0; i < 5; i += 1) {
                    props['x' + j] = x + vertices[i].x;
                    props['y' + j] = y + vertices[i].y;
                    j += 1;
                }
                $canvas.drawLine(props);

                // draw line through vertices 6-15 (outer edge)
                j = 1;
                for (i = 5; i < 15; i += 1) {
                    props['x' + j] = x + vertices[i].x;
                    props['y' + j] = y + vertices[i].y;
                    j += 1;
                }
                $canvas.drawLine(props);

                // draw lines between the following vertices (to complete
                // rendering the edges of the other 5 facets):
                //
                //    1 -> 6; 2 -> 8; 3 -> 10; 4 -> 12; 5 -> 14
                props = {
                    strokeStyle: 'black'
                };
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[0].x, y1: y + vertices[0].y,
                    x2: x + vertices[5].x, y2: y + vertices[5].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[1].x, y1: y + vertices[1].y,
                    x2: x + vertices[7].x, y2: y + vertices[7].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[2].x, y1: y + vertices[2].y,
                    x2: x + vertices[9].x, y2: y + vertices[9].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[3].x, y1: y + vertices[3].y,
                    x2: x + vertices[11].x, y2: y + vertices[11].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[4].x, y1: y + vertices[4].y,
                    x2: x + vertices[13].x, y2: y + vertices[13].y
                }));

                $canvas.drawText({
                    fillStyle: 'black',
                    fontSize: '1em',
                    text: dieRollResult.value.toString(),
                    x: x,
                    y: y
                });
            } else if (dieRollResult.sides === 20) {
                vertices = [
                    { x:  0.000000, y: -1.1547005 },
                    { x:  1.000000, y:  0.5773503 },
                    { x: -1.000000, y:  0.5773503 },
                    { x:  0.000000, y: -1.8683447 },
                    { x:  1.618034, y: -0.9341724 },
                    { x:  1.618034, y:  0.9341724 },
                    { x:  0.000000, y:  1.8683447 },
                    { x: -1.618034, y:  0.9341724 },
                    { x: -1.618034, y: -0.9341724 }
                ];
                vertices.forEach(function (vertex) {
                    vertex.x *= DIE_SIZE / 3;
                    vertex.y *= DIE_SIZE / 3;
                });

                // draw line through vertices 1-3 (edges of top facet)
                props = {
                    closed: true,
                    rounded: true,
                    strokeStyle: 'black'
                };
                j = 1;
                for (i = 0; i < 3; i += 1) {
                    props['x' + j] = x + vertices[i].x;
                    props['y' + j] = y + vertices[i].y;
                    j += 1;
                }
                $canvas.drawLine(props);

                // draw line through vertices 4-9 (outer edge)
                j = 1;
                for (i = 3; i < 9; i += 1) {
                    props['x' + j] = x + vertices[i].x;
                    props['y' + j] = y + vertices[i].y;
                    j += 1;
                }
                $canvas.drawLine(props);

                // draw lines between the following vertices (to complete
                // rendering the edges of the other 5 facets):
                //
                //    1 -> 4; 1 -> 5; 1 -> 9;
                //    2 -> 5; 2 -> 6; 2 -> 7;
                //    3 -> 7; 3 -> 8; 3 -> 9
                props = {
                    strokeStyle: 'black'
                };
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[0].x, y1: y + vertices[0].y,
                    x2: x + vertices[3].x, y2: y + vertices[3].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[0].x, y1: y + vertices[0].y,
                    x2: x + vertices[4].x, y2: y + vertices[4].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[0].x, y1: y + vertices[0].y,
                    x2: x + vertices[8].x, y2: y + vertices[8].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[1].x, y1: y + vertices[1].y,
                    x2: x + vertices[4].x, y2: y + vertices[4].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[1].x, y1: y + vertices[1].y,
                    x2: x + vertices[5].x, y2: y + vertices[5].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[1].x, y1: y + vertices[1].y,
                    x2: x + vertices[6].x, y2: y + vertices[6].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[2].x, y1: y + vertices[2].y,
                    x2: x + vertices[6].x, y2: y + vertices[6].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[2].x, y1: y + vertices[2].y,
                    x2: x + vertices[7].x, y2: y + vertices[7].y
                }));
                $canvas.drawLine($.extend(props, {
                    x1: x + vertices[2].x, y1: y + vertices[2].y,
                    x2: x + vertices[8].x, y2: y + vertices[8].y
                }));

                $canvas.drawText({
                    fillStyle: 'black',
                    fontSize: '1em',
                    text: dieRollResult.value.toString(),
                    x: x,
                    y: y
                });
            } else {
                $canvas.drawEllipse({
                    height: DIE_SIZE,
                    strokeStyle: 'black',
                    width: DIE_SIZE,
                    x: x,
                    y: y
                });
                $canvas.drawText({
                    fillStyle: 'black',
                    fontSize: '0.5em',
                    text: dieRollResult.sides.toString(),
                    x: x + DIE_SIZE / 2,
                    y: y + DIE_SIZE / 2
                });
                $canvas.drawText({
                    fillStyle: 'black',
                    fontSize: '1em',
                    text: dieRollResult.value.toString(),
                    x: x,
                    y: y
                });
            }
        });
    }

    function addExpressionResult(response) {
        var $actionsCell,
            $expressionCanonicalTextCell,
            $expressionResultRow,
            $expressionResultTextCell,
            $expressionResultValueCell,
            $expressionTextCell,
            $reevaluateButton,
            $removeButton;

        $expressionTextCell = $('<td>').text(response.expression.text);
        $expressionCanonicalTextCell = $('<td>').text(response.expression.canonicalText);
        $expressionResultTextCell = $('<td>').text(response.expressionResult.text);
        $expressionResultValueCell = $('<td>').text(response.expressionResult.value.toString());

        $reevaluateButton = $('<button>').attr('name', 'reevaluate').text('Reevaluate').click(function () {
            evaluateExpression($expressionTextCell.text());
        });
        $removeButton = $('<button>').attr('name', 'remove').text('Remove').click(function (event) {
            $(event.target).closest('tr').remove();
        });
        $actionsCell = $('<td>').append($reevaluateButton, $removeButton);

        $expressionResultRow = $('<tr>').append(
            $expressionTextCell,
            $expressionCanonicalTextCell,
            $expressionResultTextCell,
            $expressionResultValueCell,
            $actionsCell
        );
        $('#expressionResults').prepend($expressionResultRow);
    }

    function clearExpressionText() {
        $('#expressionText').val('');
    }

    function evaluateExpression(expressionText) {
        var randomNumberGeneratorJson,
            requestBody;

        requestBody = {
            expression: {
                text: expressionText
            }
        };

        randomNumberGeneratorJson = $('#randomNumberGeneratorJson').val();
        if (randomNumberGeneratorJson) {
            requestBody.randomNumberGenerator = JSON.parse(randomNumberGeneratorJson);
        }

        $.postJSON('/expression/evaluate', requestBody, processResponse, processErrorResponse);
    }

    function getExpressionText() {
        var expressionText,
            roundingFunction;

        expressionText = $('#expressionText').val();
        roundingFunction = $('input[name="roundingMode"]:checked').val();
        if (roundingFunction) {
            expressionText = roundingFunction + '(' + expressionText + ')';
        }
        return expressionText;
    }

    function hideErrorMessage() {
        $('#errorMessage').invisible();
    }

    function hideHelp() {
        $('#help').hide();
    }

    function initialize() {
        hideHelp();
        hideErrorMessage();

        $('#expressionForm').submit(function (event) {
            evaluateExpression(getExpressionText());
            event.preventDefault();
        });
        $('#toggleHelp').click(toggleHelp);
        $('#removeAllResults').click(removeAllResults);
    }

    function installJQueryPlugins() {
        jQuery.fn.visible = function () {
            return this.css('visibility', 'visible');
        };

        jQuery.fn.invisible = function () {
            return this.css('visibility', 'hidden');
        };

        jQuery.extend({
            postJSON: function (url, data, successCallback, errorCallback) {
                return this.ajax({
                    contentType: 'application/json; charset=utf-8',
                    data: JSON.stringify(data),
                    dataType: 'json',
                    error: errorCallback,
                    success: successCallback,
                    type: 'POST',
                    url: url
                });
            }
        });
    }

    function processErrorResponse(jqxhr) {
        var responseBody = jqxhr.responseJSON;

        if (responseBody && responseBody.error) {
            showErrorMessage(responseBody.error.message);
        }
    }

    function processResponse(responseBody) {
        clearExpressionText();
        addDieRollResults(responseBody);
        addExpressionResult(responseBody);
        hideErrorMessage();
    }

    function removeAllResults() {
        $('#expressionResults').empty();
    }

    function showErrorMessage(message) {
        $('#errorMessage').text(message).visible();
    }

    function toggleHelp() {
        var $help,
            isHelpVisible,
            wasHelpVisible;

        $help = $('#help');
        wasHelpVisible = $help.is(':visible');
        $help.toggle(400);

        isHelpVisible = !wasHelpVisible;
        $('#toggleHelp').text(isHelpVisible ? 'hide help' : 'help');
    }

    function main() {
        installJQueryPlugins();
        initialize();
    }

    $(document).ready(main);
})();
<commit_msg>Extract common functions for drawing dice<commit_after>(function () {
    'use strict';

    function addDieRollResults(response) {
        var DIE_SIZE = 40,
            MARGIN = 20,
            $canvas,
            dicePerRow;

        function drawDie(x, y, scale, vertices, vertex_indexes_list) {
            vertices.forEach(function (vertex) {
                vertex.x = x + scale * vertex.x;
                vertex.y = y + scale * vertex.y;
            });

            vertex_indexes_list.forEach(function (vertex_indexes) {
                var i = 1,
                    props = {
                        strokeStyle: 'black'
                    };

                vertex_indexes.forEach(function (vertex_index) {
                    props['x' + i] = vertices[vertex_index].x;
                    props['y' + i] = vertices[vertex_index].y;
                    i += 1;
                });
                $canvas.drawLine(props);
            });
        }

        function drawDieRollResultValue(x, y, dieRollResult) {
            $canvas.drawText({
                fillStyle: 'black',
                fontSize: '1em',
                text: dieRollResult.value.toString(),
                x: x,
                y: y
            });
        }

        $canvas = $('#dieRollResults');

        $canvas.clearCanvas();

        dicePerRow = Math.floor(($canvas.width() - 2 * MARGIN) / (DIE_SIZE + MARGIN));
        response.dieRollResults.forEach(function (dieRollResult, index) {
            var column,
                row,
                x,
                y;

            column = index % dicePerRow;
            x = MARGIN + column * (DIE_SIZE + MARGIN) + DIE_SIZE / 2;
            row = Math.floor(index / dicePerRow);
            y = MARGIN + row * (DIE_SIZE + MARGIN) + DIE_SIZE / 2;

            if (dieRollResult.sides === 4) {
                $canvas.drawPolygon({
                    radius: DIE_SIZE / 2,
                    sides: 3,
                    strokeStyle: 'black',
                    x: x,
                    y: y
                });
                drawDieRollResultValue(x, y, dieRollResult);
            } else if (dieRollResult.sides === 6) {
                $canvas.drawRect({
                    height: DIE_SIZE,
                    strokeStyle: 'black',
                    width: DIE_SIZE,
                    x: x,
                    y: y
                });
                drawDieRollResultValue(x, y, dieRollResult);
            } else if (dieRollResult.sides === 8) {
                drawDie(x, y, DIE_SIZE / 1.5, [
                    { x:  0.0000000, y: -0.8164966 },
                    { x:  0.7071068, y: -0.4082483 },
                    { x:  0.7071068, y:  0.4082483 },
                    { x:  0.0000000, y:  0.8164966 },
                    { x: -0.7071068, y:  0.4082483 },
                    { x: -0.7071068, y: -0.4082483 }
                ], [
                    [0, 1, 2, 3, 4, 5, 0],
                    [0, 2],
                    [0, 4],
                    [2, 4]
                ]);
                drawDieRollResultValue(x, y, dieRollResult);
            } else if (dieRollResult.sides === 12) {
                drawDie(x, y, DIE_SIZE / 3, [
                    { x:  0.000000, y: -1.0922415 },
                    { x:  1.000000, y: -0.3660254 },
                    { x:  0.618034, y:  0.8090170 },
                    { x: -0.618034, y:  0.8090170 },
                    { x: -1.000000, y: -0.3660254 },
                    { x:  0.000000, y: -1.7102755 },
                    { x:  1.000000, y: -1.3660254 },
                    { x:  1.618034, y: -0.5352331 },
                    { x:  1.618034, y:  0.5352331 },
                    { x:  1.000000, y:  1.3660254 },
                    { x:  0.000000, y:  1.7102755 },
                    { x: -1.000000, y:  1.3660254 },
                    { x: -1.618034, y:  0.5352331 },
                    { x: -1.618034, y: -0.5352331 },
                    { x: -1.000000, y: -1.3660254 }
                ], [
                    [0, 1, 2, 3, 4, 0],
                    [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 5],
                    [0, 5],
                    [1, 7],
                    [2, 9],
                    [3, 11],
                    [4, 13]
                ]);
                drawDieRollResultValue(x, y, dieRollResult);
            } else if (dieRollResult.sides === 20) {
                drawDie(x, y, DIE_SIZE / 3, [
                    { x:  0.000000, y: -1.1547005 },
                    { x:  1.000000, y:  0.5773503 },
                    { x: -1.000000, y:  0.5773503 },
                    { x:  0.000000, y: -1.8683447 },
                    { x:  1.618034, y: -0.9341724 },
                    { x:  1.618034, y:  0.9341724 },
                    { x:  0.000000, y:  1.8683447 },
                    { x: -1.618034, y:  0.9341724 },
                    { x: -1.618034, y: -0.9341724 }
                ], [
                    [0, 1, 2, 0],
                    [3, 4, 5, 6, 7, 8, 3],
                    [0, 3],
                    [0, 4],
                    [0, 8],
                    [1, 4],
                    [1, 5],
                    [1, 6],
                    [2, 6],
                    [2, 7],
                    [2, 8]
                ]);
                drawDieRollResultValue(x, y, dieRollResult);
            } else {
                $canvas.drawEllipse({
                    height: DIE_SIZE,
                    strokeStyle: 'black',
                    width: DIE_SIZE,
                    x: x,
                    y: y
                });
                $canvas.drawText({
                    fillStyle: 'black',
                    fontSize: '0.5em',
                    text: dieRollResult.sides.toString(),
                    x: x + DIE_SIZE / 2,
                    y: y + DIE_SIZE / 2
                });
                drawDieRollResultValue(x, y, dieRollResult);
            }
        });
    }

    function addExpressionResult(response) {
        var $actionsCell,
            $expressionCanonicalTextCell,
            $expressionResultRow,
            $expressionResultTextCell,
            $expressionResultValueCell,
            $expressionTextCell,
            $reevaluateButton,
            $removeButton;

        $expressionTextCell = $('<td>').text(response.expression.text);
        $expressionCanonicalTextCell = $('<td>').text(response.expression.canonicalText);
        $expressionResultTextCell = $('<td>').text(response.expressionResult.text);
        $expressionResultValueCell = $('<td>').text(response.expressionResult.value.toString());

        $reevaluateButton = $('<button>').attr('name', 'reevaluate').text('Reevaluate').click(function () {
            evaluateExpression($expressionTextCell.text());
        });
        $removeButton = $('<button>').attr('name', 'remove').text('Remove').click(function (event) {
            $(event.target).closest('tr').remove();
        });
        $actionsCell = $('<td>').append($reevaluateButton, $removeButton);

        $expressionResultRow = $('<tr>').append(
            $expressionTextCell,
            $expressionCanonicalTextCell,
            $expressionResultTextCell,
            $expressionResultValueCell,
            $actionsCell
        );
        $('#expressionResults').prepend($expressionResultRow);
    }

    function clearExpressionText() {
        $('#expressionText').val('');
    }

    function evaluateExpression(expressionText) {
        var randomNumberGeneratorJson,
            requestBody;

        requestBody = {
            expression: {
                text: expressionText
            }
        };

        randomNumberGeneratorJson = $('#randomNumberGeneratorJson').val();
        if (randomNumberGeneratorJson) {
            requestBody.randomNumberGenerator = JSON.parse(randomNumberGeneratorJson);
        }

        $.postJSON('/expression/evaluate', requestBody, processResponse, processErrorResponse);
    }

    function getExpressionText() {
        var expressionText,
            roundingFunction;

        expressionText = $('#expressionText').val();
        roundingFunction = $('input[name="roundingMode"]:checked').val();
        if (roundingFunction) {
            expressionText = roundingFunction + '(' + expressionText + ')';
        }
        return expressionText;
    }

    function hideErrorMessage() {
        $('#errorMessage').invisible();
    }

    function hideHelp() {
        $('#help').hide();
    }

    function initialize() {
        hideHelp();
        hideErrorMessage();

        $('#expressionForm').submit(function (event) {
            evaluateExpression(getExpressionText());
            event.preventDefault();
        });
        $('#toggleHelp').click(toggleHelp);
        $('#removeAllResults').click(removeAllResults);
    }

    function installJQueryPlugins() {
        jQuery.fn.visible = function () {
            return this.css('visibility', 'visible');
        };

        jQuery.fn.invisible = function () {
            return this.css('visibility', 'hidden');
        };

        jQuery.extend({
            postJSON: function (url, data, successCallback, errorCallback) {
                return this.ajax({
                    contentType: 'application/json; charset=utf-8',
                    data: JSON.stringify(data),
                    dataType: 'json',
                    error: errorCallback,
                    success: successCallback,
                    type: 'POST',
                    url: url
                });
            }
        });
    }

    function processErrorResponse(jqxhr) {
        var responseBody = jqxhr.responseJSON;

        if (responseBody && responseBody.error) {
            showErrorMessage(responseBody.error.message);
        }
    }

    function processResponse(responseBody) {
        clearExpressionText();
        addDieRollResults(responseBody);
        addExpressionResult(responseBody);
        hideErrorMessage();
    }

    function removeAllResults() {
        $('#expressionResults').empty();
    }

    function showErrorMessage(message) {
        $('#errorMessage').text(message).visible();
    }

    function toggleHelp() {
        var $help,
            isHelpVisible,
            wasHelpVisible;

        $help = $('#help');
        wasHelpVisible = $help.is(':visible');
        $help.toggle(400);

        isHelpVisible = !wasHelpVisible;
        $('#toggleHelp').text(isHelpVisible ? 'hide help' : 'help');
    }

    function main() {
        installJQueryPlugins();
        initialize();
    }

    $(document).ready(main);
})();
<|endoftext|>


<commit_before>/**
 * Copyright 2016 The AMP HTML Authors. 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.
 */

import {Services} from '../../../src/services';
import {ancestorElementsByTag} from '../../../src/dom';
import {getAdContainer} from '../../../src/ad-helper';

export class AmpAdUIHandler {
  /**
   * @param {!AMP.BaseElement} baseInstance
   */
  constructor(baseInstance) {
    /** @private {!AMP.BaseElement} */
    this.baseInstance_ = baseInstance;

    /** @private {!Element} */
    this.element_ = baseInstance.element;

    /** @private @const {!Document} */
    this.doc_ = baseInstance.win.document;

    this.containerElement_ = null;

    if (this.element_.hasAttribute('data-ad-container-id')) {
      const id = this.element_.getAttribute('data-ad-container-id');
      const container = this.doc_.getElementById(id);
      if (
        container &&
        container.tagName == 'AMP-LAYOUT' &&
        container.contains(this.element_)
      ) {
        // Parent <amp-layout> component with reference id can serve as the
        // ad container
        this.containerElement_ = container;
      }
    }

    if (!baseInstance.getFallback()) {
      const fallback = this.addDefaultUiComponent_('fallback');
      if (fallback) {
        this.baseInstance_.element.appendChild(fallback);
      }
    }
  }

  /**
   * Apply UI for laid out ad with no-content
   * Order: try collapse -> apply provided fallback -> apply default fallback
   */
  applyNoContentUI() {
    if (getAdContainer(this.element_) === 'AMP-STICKY-AD') {
      // Special case: force collapse sticky-ad if no content.
      this.baseInstance_./*OK*/ collapse();
      return;
    }

    if (getAdContainer(this.element_) === 'AMP-FX-FLYING-CARPET') {
      /**
       * Special case: Force collapse the ad if it is the,
       * only and direct child of a flying carpet.
       * Also, this will not handle
       * the amp-layout case for now, as it could be
       * inefficient. And we have not seen an amp-layout
       * used with flying carpet and ads yet.
       */

      const flyingCarpetElements = ancestorElementsByTag(
        this.element_,
        'amp-fx-flying-carpet'
      );
      const flyingCarpetElement = flyingCarpetElements[0];

      flyingCarpetElement.getImpl().then((implementation) => {
        const children = implementation.getChildren();

        if (children.length === 1 && children[0] === this.element_) {
          this.baseInstance_./*OK*/ collapse();
        }
      });
      return;
    }

    let attemptCollapsePromise;
    if (this.containerElement_) {
      // Collapse the container element if there's one
      attemptCollapsePromise = Services.mutatorForDoc(
        this.element_.getAmpDoc()
      ).attemptCollapse(this.containerElement_);
      attemptCollapsePromise.then(() => {});
    } else {
      attemptCollapsePromise = this.baseInstance_.attemptCollapse();
    }

    // The order here is collapse > user provided fallback > default fallback
    attemptCollapsePromise.catch(() => {
      this.baseInstance_.mutateElement(() => {
        this.baseInstance_.togglePlaceholder(false);
        this.baseInstance_.toggleFallback(true);
      });
    });
  }

  /**
   * Apply UI for unlaid out ad: Hide fallback.
   * Note: No need to togglePlaceholder here, unlayout show it by default.
   */
  applyUnlayoutUI() {
    this.baseInstance_.mutateElement(() => {
      this.baseInstance_.toggleFallback(false);
    });
  }

  /**
   * @param {string} name
   * @return {?Element}
   * @private
   */
  addDefaultUiComponent_(name) {
    if (this.element_.tagName == 'AMP-EMBED') {
      // Do nothing for amp-embed element;
      return null;
    }
    const uiComponent = this.doc_.createElement('div');
    uiComponent.setAttribute(name, '');

    const content = this.doc_.createElement('div');
    content.classList.add('i-amphtml-ad-default-holder');

    // TODO(aghassemi, #4146) i18n
    content.setAttribute('data-ad-holder-text', 'Ad');
    uiComponent.appendChild(content);

    return uiComponent;
  }

  /**
   * @param {number|string|undefined} height
   * @param {number|string|undefined} width
   * @param {number} iframeHeight
   * @param {number} iframeWidth
   * @param {!MessageEvent} event
   * @return {!Promise<!Object>}
   */
  updateSize(height, width, iframeHeight, iframeWidth, event) {
    // Calculate new width and height of the container to include the padding.
    // If padding is negative, just use the requested width and height directly.
    let newHeight, newWidth;
    height = parseInt(height, 10);
    if (!isNaN(height)) {
      newHeight = Math.max(
        this.element_./*OK*/ offsetHeight + height - iframeHeight,
        height
      );
    }
    width = parseInt(width, 10);
    if (!isNaN(width)) {
      newWidth = Math.max(
        this.element_./*OK*/ offsetWidth + width - iframeWidth,
        width
      );
    }

    /** @type {!Object<boolean, number|undefined, number|undefined>} */
    const resizeInfo = {
      success: true,
      newWidth,
      newHeight,
    };

    if (!newHeight && !newWidth) {
      return Promise.reject(new Error('undefined width and height'));
    }

    if (getAdContainer(this.element_) == 'AMP-STICKY-AD') {
      // Special case: force collapse sticky-ad if no content.
      resizeInfo.success = false;
      return Promise.resolve(resizeInfo);
    }
    return this.baseInstance_
      .attemptChangeSize(newHeight, newWidth, event)
      .then(
        () => resizeInfo,
        () => {
          resizeInfo.success = false;
          return resizeInfo;
        }
      );
  }
}

// Make the class available to other late loaded amp-ad implementations
// without them having to depend on it directly.
AMP.AmpAdUIHandler = AmpAdUIHandler;
<commit_msg>Restrict amp-ad sticky ad size to 20% viewport size and 50% height (#30079)<commit_after>/**
 * Copyright 2016 The AMP HTML Authors. 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.
 */

import {Services} from '../../../src/services';
import {ancestorElementsByTag} from '../../../src/dom';
import {getAdContainer} from '../../../src/ad-helper';

const STICKY_AD_MAX_SIZE_LIMIT = 0.2;
const STICKY_AD_MAX_HEIGHT_LIMIT = 0.5;

export class AmpAdUIHandler {
  /**
   * @param {!AMP.BaseElement} baseInstance
   */
  constructor(baseInstance) {
    /** @private {!AMP.BaseElement} */
    this.baseInstance_ = baseInstance;

    /** @private {!Element} */
    this.element_ = baseInstance.element;

    /** @private @const {!Document} */
    this.doc_ = baseInstance.win.document;

    this.containerElement_ = null;

    if (this.element_.hasAttribute('data-ad-container-id')) {
      const id = this.element_.getAttribute('data-ad-container-id');
      const container = this.doc_.getElementById(id);
      if (
        container &&
        container.tagName == 'AMP-LAYOUT' &&
        container.contains(this.element_)
      ) {
        // Parent <amp-layout> component with reference id can serve as the
        // ad container
        this.containerElement_ = container;
      }
    }

    if (!baseInstance.getFallback()) {
      const fallback = this.addDefaultUiComponent_('fallback');
      if (fallback) {
        this.baseInstance_.element.appendChild(fallback);
      }
    }
  }

  /**
   * Apply UI for laid out ad with no-content
   * Order: try collapse -> apply provided fallback -> apply default fallback
   */
  applyNoContentUI() {
    if (getAdContainer(this.element_) === 'AMP-STICKY-AD') {
      // Special case: force collapse sticky-ad if no content.
      this.baseInstance_./*OK*/ collapse();
      return;
    }

    if (getAdContainer(this.element_) === 'AMP-FX-FLYING-CARPET') {
      /**
       * Special case: Force collapse the ad if it is the,
       * only and direct child of a flying carpet.
       * Also, this will not handle
       * the amp-layout case for now, as it could be
       * inefficient. And we have not seen an amp-layout
       * used with flying carpet and ads yet.
       */

      const flyingCarpetElements = ancestorElementsByTag(
        this.element_,
        'amp-fx-flying-carpet'
      );
      const flyingCarpetElement = flyingCarpetElements[0];

      flyingCarpetElement.getImpl().then((implementation) => {
        const children = implementation.getChildren();

        if (children.length === 1 && children[0] === this.element_) {
          this.baseInstance_./*OK*/ collapse();
        }
      });
      return;
    }

    let attemptCollapsePromise;
    if (this.containerElement_) {
      // Collapse the container element if there's one
      attemptCollapsePromise = Services.mutatorForDoc(
        this.element_.getAmpDoc()
      ).attemptCollapse(this.containerElement_);
      attemptCollapsePromise.then(() => {});
    } else {
      attemptCollapsePromise = this.baseInstance_.attemptCollapse();
    }

    // The order here is collapse > user provided fallback > default fallback
    attemptCollapsePromise.catch(() => {
      this.baseInstance_.mutateElement(() => {
        this.baseInstance_.togglePlaceholder(false);
        this.baseInstance_.toggleFallback(true);
      });
    });
  }

  /**
   * Apply UI for unlaid out ad: Hide fallback.
   * Note: No need to togglePlaceholder here, unlayout show it by default.
   */
  applyUnlayoutUI() {
    this.baseInstance_.mutateElement(() => {
      this.baseInstance_.toggleFallback(false);
    });
  }

  /**
   * @param {string} name
   * @return {?Element}
   * @private
   */
  addDefaultUiComponent_(name) {
    if (this.element_.tagName == 'AMP-EMBED') {
      // Do nothing for amp-embed element;
      return null;
    }
    const uiComponent = this.doc_.createElement('div');
    uiComponent.setAttribute(name, '');

    const content = this.doc_.createElement('div');
    content.classList.add('i-amphtml-ad-default-holder');

    // TODO(aghassemi, #4146) i18n
    content.setAttribute('data-ad-holder-text', 'Ad');
    uiComponent.appendChild(content);

    return uiComponent;
  }

  /**
   * @param {number|string|undefined} height
   * @param {number|string|undefined} width
   * @param {number} iframeHeight
   * @param {number} iframeWidth
   * @param {!MessageEvent} event
   * @return {!Promise<!Object>}
   */
  updateSize(height, width, iframeHeight, iframeWidth, event) {
    // Calculate new width and height of the container to include the padding.
    // If padding is negative, just use the requested width and height directly.
    let newHeight, newWidth;
    height = parseInt(height, 10);
    if (!isNaN(height)) {
      newHeight = Math.max(
        this.element_./*OK*/ offsetHeight + height - iframeHeight,
        height
      );
    }
    width = parseInt(width, 10);
    if (!isNaN(width)) {
      newWidth = Math.max(
        this.element_./*OK*/ offsetWidth + width - iframeWidth,
        width
      );
    }

    /** @type {!Object<boolean, number|undefined, number|undefined>} */
    const resizeInfo = {
      success: true,
      newWidth,
      newHeight,
    };

    if (!newHeight && !newWidth) {
      return Promise.reject(new Error('undefined width and height'));
    }

    if (getAdContainer(this.element_) == 'AMP-STICKY-AD') {
      // Special case: force collapse sticky-ad if no content.
      resizeInfo.success = false;
      return Promise.resolve(resizeInfo);
    }

    // Special case: for sticky ads, we enforce 20% size limit and 50% height limit
    if (this.element_.hasAttribute('sticky')) {
      const viewport = this.baseInstance_.getViewport();
      if (
        newHeight * newWidth >
          STICKY_AD_MAX_SIZE_LIMIT *
            viewport.getHeight() *
            viewport.getWidth() ||
        newHeight > STICKY_AD_MAX_HEIGHT_LIMIT * viewport.getHeight()
      ) {
        resizeInfo.success = false;
        return Promise.resolve(resizeInfo);
      }
    }
    return this.baseInstance_
      .attemptChangeSize(newHeight, newWidth, event)
      .then(
        () => resizeInfo,
        () => {
          resizeInfo.success = false;
          return resizeInfo;
        }
      );
  }
}

// Make the class available to other late loaded amp-ad implementations
// without them having to depend on it directly.
AMP.AmpAdUIHandler = AmpAdUIHandler;
<|endoftext|>


<commit_before>'use strict';
(function(root) {
    /****************************
     Public Constructor
     ****************************/

    function Promise(resolver) {
        var promise = new PendingPromise();
        var self = this;

        this.then = function then(onFulfilled, onRejected) {
            var deferred = new Deferred(self.constructor);
            return promise.resolve(
                deferred,
                isFunction(onFulfilled) ? onFulfilled : deferred.resolve,
                isFunction(onRejected) ? onRejected : deferred.reject,
                self
            );
        };

        var _reject = function reject() {
            _resolve = _reject = noop;
            var reasons = toArray.apply(void 0, arguments);
            var p = new RejectedPromise(reasons);
            promise.resolveQueued(p);
            promise = p;
        };
        var _resolve = function resolve() {
            var deferred = {
                promise: self,
                reject: _reject,
                resolve: function resolve() {
                    var values = toArray.apply(void 0, arguments);
                    var p = new FulfilledPromise(values);
                    promise.resolveQueued(p);
                    promise = p;
                }
            };
            _resolve = _reject = noop;
            doResolve.apply(deferred, arguments);
        };

        tryCatchResolver(resolver, function resolve() {
            apply(_resolve, arguments);
        }, function reject() {
            apply(_reject, arguments);
        });
    }

    /****************************
     Public Instance Methods
     ****************************/

    Promise.prototype.catch = function(onRejected) {
        return this.then(void 0, onRejected);
    };

    Promise.prototype.throw = function() {
        return this.catch(function(error) {
            // Defer it, so our promise doesn't catch
            // it and turn it into a rejected promise.
            defer(function() {
                throw error;
            });

            throw error;
        });
    };

    /****************************
     Public Static Methods
     ****************************/

    Promise.resolve = function resolve(obj) {
        if (isObject(obj) && obj.constructor === this) {
            return obj;
        }

        var values = toArray.apply(void 0, arguments);
        return new this(function(resolve) {
            resolve.apply(void 0, values);
        });
    };

    Promise.reject = function reject() {
        var reasons = toArray.apply(void 0, arguments);
        return new this(function(_, reject) {
            reject.apply(void 0, reasons);
        });
    };

    Promise.deferred = function deferred() {
        return new Deferred(this);
    };

    Promise.all = function all(promises) {
        var Constructor = this;
        return new Constructor(function(resolve, reject) {
            var l = promises.length;
            var values = new Array(l);
            var times = l;

            if (times === 0) {
                return resolve(values);
            }
            var resolveAfter = function() {
                if (--times === 0) { resolve(values); }
            };

            for (var i = 0; i < l; i++) {
                Constructor.resolve(promises[i]).then(fillSlot(values, i, resolveAfter), reject);
            }
        });
    };

    Promise.race = function race(promises) {
        var Constructor = this;
        return new Constructor(function(resolve, reject) {
            for (var i = 0, l = promises.length; i < l; i++) {
                Constructor.resolve(promises[i]).then(resolve, reject);
            }
        });
    };

    /****************************
      Private functions
     ****************************/

    function Deferred(Promise) {
        var deferred = this;
        this.promise = new Promise(function(resolve, reject) {
            deferred.resolve = resolve;
            deferred.reject = reject;
        });
    }

    function FulfilledPromise(values) {
        this.values = values;
    }
    FulfilledPromise.prototype.resolve = function(deferred, onFulfilled, _, previous) {
        if (!onFulfilled) { return previous; }
        defer(tryCatchDeferred(deferred, onFulfilled, this.values));
        return deferred.promise;
    };

    function RejectedPromise(reasons) {
        this.reasons = reasons;
    }
    RejectedPromise.prototype.resolve = function(deferred, _, onRejected, previous) {
        if (!onRejected) { return previous; }
        defer(tryCatchDeferred(deferred, onRejected, this.reasons));
        return deferred.promise;
    };

    function PendingPromise() {
        this.queue = [];
    }
    PendingPromise.prototype.resolve = function(deferred, onFulfilled, onRejected) {
        this.queue.push({
            deferred: deferred,
            onFulfilled: onFulfilled,
            onRejected: onRejected
        });
        return deferred.promise;
    };
    PendingPromise.prototype.resolveQueued = function(promise) {
        var queue = this.queue;
        for (var i = 0, l = queue.length; i < l; i++) {
            var next = queue[i];
            promise.resolve(next.deferred, next.onFulfilled, next.onRejected);
        }
    };

    function noop() {}
    function isFunction(fn) {
        return typeof fn === 'function';
    }
    function isObject(obj) {
        return obj && (typeof obj === 'object' || typeof obj === 'function');
    }
    function fillSlot(array, index, fn) {
        return function(value) {
            array[index] = value;
            if (fn) { fn(); }
        };
    }
    function toArray() {
        var l = arguments.length;
        var array = new Array(l);
        for (var i = 0; i < l; i++) {
            array[i] = arguments[i];
        }
        return array;
    }
    function tryCatchResolver(resolver, resolve, reject) {
        try {
            resolver(resolve, reject);
        } catch (e) {
            reject(e);
        }
    }
    function tryCatchDeferred(deferred, fn, args) {
        return function() {
            try {
                doResolve.call(deferred, fn.apply(void 0, args));
            } catch (e) {
                deferred.reject(e);
            }
        };
    }

    var nextTick = typeof process !== 'undefined' && isFunction(process.nextTick) ? process.nextTick
     : typeof setImmediate !== 'undefined' ? setImmediate
     : function(fn) { setTimeout(fn, 0); };
    var defer = (function() {
        var queue = [];
        var l = 0;
        function flush() {
            for (var i = 0; i < l; i++) {
                queue[i]();
            }
            queue = [];
            l = 0;
        }
        return function defer(fn) {
            l = queue.push(fn);
            if (l === 1) { nextTick(flush); }
        };
    })();

    function doResolve(x) {
        var deferred = this;
        var _reject = deferred.reject;
        var then;
        try {
            if (x === deferred.promise) {
                throw new TypeError('A promise cannot be fulfilled with itself.');
            }
            if (isObject(x) && (then = x.then) && isFunction(then)) {
                var _resolve = function resolvePromise() {
                    _resolve = _reject = noop;
                    doResolve.apply(deferred, arguments);
                };
                _reject = function rejectPromise() {
                    _resolve = _reject = noop;
                    deferred.reject.apply(void 0, arguments);
                };
                then.call(
                    x,
                    function() { _resolve.apply(void 0, arguments); },
                    function() { _reject.apply(void 0, arguments); }
                );
            } else {
                deferred.resolve.apply(void 0, arguments);
            }
        } catch (e) {
            _reject(e);
        }
    }

    if (typeof exports !== 'undefined') {
        if (typeof module !== 'undefined' && module.exports) {
            exports = module.exports = Promise;
        }
        exports.Promise = Promise;
    } else {
        root.Promise = Promise;
    }
})(this);
<commit_msg>Avoid double calling defered's methods<commit_after>'use strict';
(function(root) {
    /****************************
     Public Constructor
     ****************************/

    function Promise(resolver) {
        var promise = new PendingPromise();
        var self = this;

        this.then = function then(onFulfilled, onRejected) {
            var deferred = new Deferred(self.constructor);
            return promise.resolve(
                deferred,
                isFunction(onFulfilled) ? onFulfilled : deferred.resolve,
                isFunction(onRejected) ? onRejected : deferred.reject,
                self
            );
        };

        var _reject = function reject() {
            _resolve = _reject = noop;
            var reasons = toArray.apply(void 0, arguments);
            var p = new RejectedPromise(reasons);
            promise.resolveQueued(p);
            promise = p;
        };
        var _resolve = function resolve() {
            var deferred = {
                promise: self,
                reject: _reject,
                resolve: function resolve() {
                    var values = toArray.apply(void 0, arguments);
                    var p = new FulfilledPromise(values);
                    promise.resolveQueued(p);
                    promise = p;
                }
            };
            _resolve = _reject = noop;
            doResolve.apply(deferred, arguments);
        };

        tryCatchResolver(resolver, function resolve() {
            apply(_resolve, arguments);
        }, function reject() {
            apply(_reject, arguments);
        });
    }

    /****************************
     Public Instance Methods
     ****************************/

    Promise.prototype.catch = function(onRejected) {
        return this.then(void 0, onRejected);
    };

    Promise.prototype.throw = function() {
        return this.catch(function(error) {
            // Defer it, so our promise doesn't catch
            // it and turn it into a rejected promise.
            defer(function() {
                throw error;
            });

            throw error;
        });
    };

    /****************************
     Public Static Methods
     ****************************/

    Promise.resolve = function resolve(obj) {
        if (isObject(obj) && obj.constructor === this) {
            return obj;
        }

        var values = toArray.apply(void 0, arguments);
        return new this(function(resolve) {
            resolve.apply(void 0, values);
        });
    };

    Promise.reject = function reject() {
        var reasons = toArray.apply(void 0, arguments);
        return new this(function(_, reject) {
            reject.apply(void 0, reasons);
        });
    };

    Promise.deferred = function deferred() {
        return new Deferred(this);
    };

    Promise.all = function all(promises) {
        var Constructor = this;
        return new Constructor(function(resolve, reject) {
            var l = promises.length;
            var values = new Array(l);
            var times = l;

            if (times === 0) {
                return resolve(values);
            }
            var resolveAfter = function() {
                if (--times === 0) { resolve(values); }
            };

            for (var i = 0; i < l; i++) {
                Constructor.resolve(promises[i]).then(fillSlot(values, i, resolveAfter), reject);
            }
        });
    };

    Promise.race = function race(promises) {
        var Constructor = this;
        return new Constructor(function(resolve, reject) {
            for (var i = 0, l = promises.length; i < l; i++) {
                Constructor.resolve(promises[i]).then(resolve, reject);
            }
        });
    };

    /****************************
      Private functions
     ****************************/

    function Deferred(Promise) {
        var deferred = this;
        this.promise = new Promise(function(resolve, reject) {
            deferred.resolve = resolve;
            deferred.reject = reject;
        });
    }

    function FulfilledPromise(values) {
        this.values = values;
    }
    FulfilledPromise.prototype.resolve = function(deferred, onFulfilled, _, previous) {
        if (!onFulfilled) { return previous; }
        defer(tryCatchDeferred(deferred, onFulfilled, this.values));
        return deferred.promise;
    };

    function RejectedPromise(reasons) {
        this.reasons = reasons;
    }
    RejectedPromise.prototype.resolve = function(deferred, _, onRejected, previous) {
        if (!onRejected) { return previous; }
        defer(tryCatchDeferred(deferred, onRejected, this.reasons));
        return deferred.promise;
    };

    function PendingPromise() {
        this.queue = [];
    }
    PendingPromise.prototype.resolve = function(deferred, onFulfilled, onRejected) {
        this.queue.push({
            deferred: deferred,
            onFulfilled: onFulfilled,
            onRejected: onRejected
        });
        return deferred.promise;
    };
    PendingPromise.prototype.resolveQueued = function(promise) {
        var queue = this.queue;
        for (var i = 0, l = queue.length; i < l; i++) {
            var next = queue[i];
            promise.resolve(next.deferred, next.onFulfilled, next.onRejected);
        }
    };

    function noop() {}
    function isFunction(fn) {
        return typeof fn === 'function';
    }
    function isObject(obj) {
        return obj && (typeof obj === 'object' || typeof obj === 'function');
    }
    function fillSlot(array, index, fn) {
        return function(value) {
            array[index] = value;
            if (fn) { fn(); }
        };
    }
    function toArray() {
        var l = arguments.length;
        var array = new Array(l);
        for (var i = 0; i < l; i++) {
            array[i] = arguments[i];
        }
        return array;
    }
    function tryCatchResolver(resolver, resolve, reject) {
        try {
            resolver(resolve, reject);
        } catch (e) {
            reject(e);
        }
    }
    function tryCatchDeferred(deferred, fn, args) {
        return function() {
            try {
                var result = fn.apply(void 0, args);
                if (deferred.resolve === fn || deferred.reject === fn) { return; }
                doResolve.call(deferred, result);
            } catch (e) {
                deferred.reject(e);
            }
        };
    }

    var nextTick = typeof process !== 'undefined' && isFunction(process.nextTick) ? process.nextTick
     : typeof setImmediate !== 'undefined' ? setImmediate
     : function(fn) { setTimeout(fn, 0); };
    var defer = (function() {
        var queue = [];
        var l = 0;
        function flush() {
            for (var i = 0; i < l; i++) {
                queue[i]();
            }
            queue = [];
            l = 0;
        }
        return function defer(fn) {
            l = queue.push(fn);
            if (l === 1) { nextTick(flush); }
        };
    })();

    function doResolve(x) {
        var deferred = this;
        var _reject = deferred.reject;
        var then;
        try {
            if (x === deferred.promise) {
                throw new TypeError('A promise cannot be fulfilled with itself.');
            }
            if (isObject(x) && (then = x.then) && isFunction(then)) {
                var _resolve = function resolvePromise() {
                    _resolve = _reject = noop;
                    doResolve.apply(deferred, arguments);
                };
                _reject = function rejectPromise() {
                    _resolve = _reject = noop;
                    deferred.reject.apply(void 0, arguments);
                };
                then.call(
                    x,
                    function() { _resolve.apply(void 0, arguments); },
                    function() { _reject.apply(void 0, arguments); }
                );
            } else {
                deferred.resolve.apply(void 0, arguments);
            }
        } catch (e) {
            _reject(e);
        }
    }

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


<commit_before>// ------------------------------ CRUD -------------------------------------
var Requests = {
  // Record create by ajax
  createByAjax: function(grid, continue_on, afterCreated) {
    var createFormElement, ajaxOptions;
    createFormElement = $('div#'+grid.name+'_form form');
    // clear all the error messages
    createFormElement.find(".field_error").text("");
    ajaxOptions = {
      url: grid.path + '.json',
      success: function(request) {
        if (typeof afterCreated == "function") {
          return afterCreated(request);
        }
        if (request.success) {
          grid.resetActiveCell();
          grid.operatedIds = [request.id];
          grid.loader.reloadData();
          if (grid.reloadMasterAfterUpdates && grid.master_grid) {
            grid.master_grid.loader.reloadData();
          }
          if (continue_on) {
            if (window._always_reset_form) {
              Ui.refreshCreateForm(grid);
            }
          } else {
            if (grid.loader.isDataLoaded()) {
              setTimeout(function(){ Ui.closeModal(grid.name); }, 100);
            }
          }
          displayNewNotification(grid.model + ' successfully created');
        } else {
          for(var k in request.error_message){
            createFormElement.find(".field[name=" + k + "]").find(".field_error").text(request.error_message[k].join());
            createFormElement.find(".field[name=" + k + "]").find("input").addClass('invalid');
          }
          if (request.error_message['base']) {
            $('.base_error', createFormElement).text(request.error_message['base']);
          }
          saveMessage('Error creating ' + grid.model.toLowerCase(), 'error');
        }
      }
    };
    createFormElement.ajaxSubmit(ajaxOptions);
  },

  // Record update by ajax
  updateByAjax: function(grid, item, editCommand) {
    delete item.slick_index;
    var currentRow = this.getCurrentRows(grid, [item.id])[1];
    $.ajax({
      type: "POST",
      dateType: 'json',
      url: grid.path + "/" + item.id + ".json" + grid.query,
      data: {_method: 'PUT', item: item, authenticity_token: decodeURIComponent(window._token)},
      success: function(msg) {
        if(msg.success) {
          var from = parseInt(currentRow / 200, 10) * 200;
          grid.loader.reloadData(from, currentRow);
        } else {
          displayErrorMessage(msg.error_message);
          if(editCommand) {
            editCommand.undo();
          } else {
            grid.loader.reloadData();
          }
        }
      }
    });
  },

  // Delete rows along ajax
  deleteByAjax: function(grid, ids, force) {
    if (ids.length > 350) {
      displayErrorMessage('You select too many rows, please select less than 350 rows.');
      return;
    }
    if(force === undefined) force = false;
    var range = this.getCurrentRows(grid, ids);
    if (ids.length == 0) return;
    $.ajax({
      type: 'POST',
      url: grid.path + '/' + ids + '.json' + grid.query + '&force=' + force,
      data: decodeURIComponent($.param({_method: 'DELETE', authenticity_token: window._token})),
      success: function(msg) {
        if(msg.success) {
          grid.resetActiveCell();
          var from = parseInt(range[0] / 200, 10) * 200;
          var to = range[1]+1;
          grid.loader.reloadData(from, to);
          if (grid.reloadMasterAfterUpdates && grid.master_grid) {
            grid.master_grid.loader.reloadData();
          }
          grid.container.find('.toolbar-select').addClass('hide');
          var recordSize = $.isArray(ids) ? ids.length : ids.split(',').length;
          var message;
          if (recordSize > 1) {
            message = recordSize + ' ' + grid.model.toLowerCase() + 's deleted';
          } else {
            message = '1 ' + grid.model.toLowerCase() + ' deleted';
          }
          displayNewNotification(message);
        } else if(msg.confirm) {
          if(msg.warning_message) $('#confirm-content').text(msg.warning_message);
          $('#confirm-modal').modal('open');
          $('#confirmed-btn').on('click', function() {
            Requests.deleteByAjax(grid, ids, true);
          });
        } else {
          displayErrorMessage(msg.error_message);
          saveMessage('Error deleting ' + grid.model.toLowerCase(), 'error');
        }
      }
    });
  },

  getCurrentRows: function(grid, ids) {
    var indexes = $.map(ids, function(id) {
      return parseInt(grid.getRowByRecordId(id).index, 10);
    });
    indexes = indexes.sort();
    return [indexes[0], indexes[indexes.length-1]];
  }
}; // Requests
<commit_msg>MISC #117 - prevent form submit multiple times<commit_after>// ------------------------------ CRUD -------------------------------------
var Requests = {
  // Record create by ajax
  createByAjax: function(grid, continue_on, afterCreated) {
    var createFormElement, ajaxOptions, smtBtns;
    createFormElement = $('div#'+grid.name+'_form form');
    smtBtns = createFormElement.find("input[type='submit']");
    // clear all the error messages
    createFormElement.find(".field_error").text("");
    ajaxOptions = {
      url: grid.path + '.json',
      beforeSend: function() {
        smtBtns.prop('disabled', 'disabled')
      },
      success: function(request) {
        if (typeof afterCreated == "function") {
          return afterCreated(request);
        }
        if (request.success) {
          grid.resetActiveCell();
          grid.operatedIds = [request.id];
          grid.loader.reloadData();
          if (grid.reloadMasterAfterUpdates && grid.master_grid) {
            grid.master_grid.loader.reloadData();
          }
          if (continue_on) {
            if (window._always_reset_form) {
              Ui.refreshCreateForm(grid);
            }
          } else {
            if (grid.loader.isDataLoaded()) {
              setTimeout(function(){ Ui.closeModal(grid.name); }, 100);
            }
          }
          displayNewNotification(grid.model + ' successfully created');
        } else {
          for(var k in request.error_message){
            createFormElement.find(".field[name=" + k + "]").find(".field_error").text(request.error_message[k].join());
            createFormElement.find(".field[name=" + k + "]").find("input").addClass('invalid');
          }
          if (request.error_message['base']) {
            $('.base_error', createFormElement).text(request.error_message['base']);
          }
          saveMessage('Error creating ' + grid.model.toLowerCase(), 'error');
        }
      },
      complete: function() {
        smtBtns.prop('disabled', null)
      }
    };
    createFormElement.ajaxSubmit(ajaxOptions);
  },

  // Record update by ajax
  updateByAjax: function(grid, item, editCommand) {
    delete item.slick_index;
    var currentRow = this.getCurrentRows(grid, [item.id])[1];
    $.ajax({
      type: "POST",
      dateType: 'json',
      url: grid.path + "/" + item.id + ".json" + grid.query,
      data: {_method: 'PUT', item: item, authenticity_token: decodeURIComponent(window._token)},
      success: function(msg) {
        if(msg.success) {
          var from = parseInt(currentRow / 200, 10) * 200;
          grid.loader.reloadData(from, currentRow);
        } else {
          displayErrorMessage(msg.error_message);
          if(editCommand) {
            editCommand.undo();
          } else {
            grid.loader.reloadData();
          }
        }
      }
    });
  },

  // Delete rows along ajax
  deleteByAjax: function(grid, ids, force) {
    if (ids.length > 350) {
      displayErrorMessage('You select too many rows, please select less than 350 rows.');
      return;
    }
    if(force === undefined) force = false;
    var range = this.getCurrentRows(grid, ids);
    if (ids.length == 0) return;
    $.ajax({
      type: 'POST',
      url: grid.path + '/' + ids + '.json' + grid.query + '&force=' + force,
      data: decodeURIComponent($.param({_method: 'DELETE', authenticity_token: window._token})),
      success: function(msg) {
        if(msg.success) {
          grid.resetActiveCell();
          var from = parseInt(range[0] / 200, 10) * 200;
          var to = range[1]+1;
          grid.loader.reloadData(from, to);
          if (grid.reloadMasterAfterUpdates && grid.master_grid) {
            grid.master_grid.loader.reloadData();
          }
          grid.container.find('.toolbar-select').addClass('hide');
          var recordSize = $.isArray(ids) ? ids.length : ids.split(',').length;
          var message;
          if (recordSize > 1) {
            message = recordSize + ' ' + grid.model.toLowerCase() + 's deleted';
          } else {
            message = '1 ' + grid.model.toLowerCase() + ' deleted';
          }
          displayNewNotification(message);
        } else if(msg.confirm) {
          if(msg.warning_message) $('#confirm-content').text(msg.warning_message);
          $('#confirm-modal').modal('open');
          $('#confirmed-btn').on('click', function() {
            Requests.deleteByAjax(grid, ids, true);
          });
        } else {
          displayErrorMessage(msg.error_message);
          saveMessage('Error deleting ' + grid.model.toLowerCase(), 'error');
        }
      }
    });
  },

  getCurrentRows: function(grid, ids) {
    var indexes = $.map(ids, function(id) {
      return parseInt(grid.getRowByRecordId(id).index, 10);
    });
    indexes = indexes.sort();
    return [indexes[0], indexes[indexes.length-1]];
  }
}; // Requests
<|endoftext|>


<commit_before>const webpack = require('webpack');
const path = require('path');
const GoogleFontsPlugin = require("google-fonts-webpack-plugin");
const HappyPack = require('happypack');

const BUILD_DIR = path.resolve(__dirname, 'dist');
const APP_DIR = path.resolve(__dirname, 'app');
const RESOURCES_DIR = path.resolve(__dirname, 'resources');

const config = {
  entry: [
    "react-hot-loader/patch",
    'webpack-dev-server/client?http://localhost:8080',
    'webpack/hot/only-dev-server',
    path.resolve(APP_DIR, 'index.js')
  ],
  output: {
    path: BUILD_DIR,
    filename: 'bundle.js',
    publicPath: 'http://localhost:8080/'
  },
  devServer: {
    hot: true,
    contentBase: BUILD_DIR,
    publicPath: 'http://localhost:8080/'
  },
  node: {
    fs: "empty"
  },
  module: {
    loaders: [
      {
	test: /.jsx?$/,
	use: 'happypack/loader?id=jsx',
	include: APP_DIR
      },
      {
	test: /.scss$/,
	use: 'happypack/loader?id=scss'
      },
      {
        test: /\.css/,
        loader: 'style-loader!css-loader?modules=true&localIdentName=[name]__[local]___[hash:base64:5]'
      }, {
        test: /\.(png|jpg|gif)$/,
        loader: 'file-loader',
        include: RESOURCES_DIR
      }
    ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
    new GoogleFontsPlugin({
      fonts: [
        {
          family: 'lato',
          variants: ['regular', '300', '700']
        }
      ]
    }),
    new HappyPack({
      id: 'jsx',
      loaders: [ 'babel-loader' ]
    }),
    new HappyPack({
      id: 'scss',
      loaders: [ 'style-loader!css-loader?importLoaders=1&modules&localIdentName=[local]!sass-loader' ]
    })
  ],
  target: 'electron-renderer'
};

module.exports = config;
<commit_msg>Use url-loader instead of file-loader in dev config<commit_after>const webpack = require('webpack');
const path = require('path');
const GoogleFontsPlugin = require("google-fonts-webpack-plugin");
const HappyPack = require('happypack');

const BUILD_DIR = path.resolve(__dirname, 'dist');
const APP_DIR = path.resolve(__dirname, 'app');
const RESOURCES_DIR = path.resolve(__dirname, 'resources');

const config = {
  entry: [
    "react-hot-loader/patch",
    'webpack-dev-server/client?http://localhost:8080',
    'webpack/hot/only-dev-server',
    path.resolve(APP_DIR, 'index.js')
  ],
  output: {
    path: BUILD_DIR,
    filename: 'bundle.js',
    publicPath: 'http://localhost:8080/'
  },
  devServer: {
    hot: true,
    contentBase: BUILD_DIR,
    publicPath: 'http://localhost:8080/'
  },
  node: {
    fs: "empty"
  },
  module: {
    loaders: [
      {
	test: /.jsx?$/,
	use: 'happypack/loader?id=jsx',
	include: APP_DIR
      },
      {
	test: /.scss$/,
	use: 'happypack/loader?id=scss'
      },
      {
        test: /\.css/,
        loader: 'style-loader!css-loader?modules=true&localIdentName=[name]__[local]___[hash:base64:5]'
      }, {
        test: /\.(png|jpg|gif)$/,
        loader: 'url-loader',
        include: RESOURCES_DIR
      }
    ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
    new GoogleFontsPlugin({
      fonts: [
        {
          family: 'lato',
          variants: ['regular', '300', '700']
        }
      ]
    }),
    new HappyPack({
      id: 'jsx',
      loaders: [ 'babel-loader' ]
    }),
    new HappyPack({
      id: 'scss',
      loaders: [ 'style-loader!css-loader?importLoaders=1&modules&localIdentName=[local]!sass-loader' ]
    })
  ],
  target: 'electron-renderer'
};

module.exports = config;
<|endoftext|>


<commit_before>import express from 'express';
import expressWs from 'express-ws';

const app = express();
const port = process.env.PORT || 3001;

expressWs(app);

app.ws('/rsvps', (ws, req) => {
  ws.on('message'; (message) => {
    ws.send(message);
  });
});

app.listen(port, () => {
  console.log(`Listening on port ${port}.`);
});
<commit_msg>typo semicolon<commit_after>import express from 'express';
import expressWs from 'express-ws';

const app = express();
const port = process.env.PORT || 3001;

expressWs(app);

app.ws('/rsvps', (ws, req) => {
  ws.on('message', (message) => {
    ws.send(message);
  });
});

app.listen(port, () => {
  console.log(`Listening on port ${port}.`);
});
<|endoftext|>


<commit_before>//expects array of file objects
//everything will be 0 levels deep

function Tarifier(files) {
  this.files = files;
}

Tarifier.prototype.tar = function(callback) {
  var files = this.files;
  this.filesLeft = files.length;
  this.callback = callback;

  var size = 512*files.length;
  for(var i = 0; i < files.length; i++) {
    size += Math.ceil(files[i].size/512)*512;
  }
  console.log("creating a file of size: "+size);

  var arrayBuffer = new ArrayBuffer(size);
  var array = new Uint8Array(arrayBuffer);

  var offset = 0;
  for(var i = 0; i < files.length; i++) {
    this.putHeader(files[i], array, offset);
    offset += 512;
    var alignedSize = Math.ceil(files[i].size/512)*512;
    this.putFile(files[i], array, offset);
    offset += alignedSize;
  }
};

Tarifier.prototype.putHeader = function(file, array, base) {
  this.putString(file.name, array, base);

  var offset;

  for(offset = file.name.length; offset < 100; offset++)
    array[base+offset] = 0;

  this.putString("000644 \0", array,base+100); //file mode
  this.putString("000000 \0", array,base+108); //UID
  this.putString("000000 \0", array,base+116); //GID
  var octalSize = file.size.toString(8);
  while(octalSize.length < 11)
    octalSize = "0"+octalSize; //inefficient, but whatever

  octalSize += " ";
  this.putString(octalSize, array, base+124);
  this.putString("00000000000 ", array, base+136); //last modified time
  this.putString("        ", array, base+148); //checksum placeholder
  this.putString("0", array, base+156);

  for(offset = 157; offset < 512; offset++)
    array[base+offset] = 0;

  var sum = 0;
  for(offset = 0; offset < 512; offset++)
    sum += array[base+offset];
  sum = sum.toString(8);
  while(sum.length < 6)
    sum = "0"+sum;
  sum += " \0";
  this.putString(sum, array, base+148); //calculated checksum
};

Tarifier.prototype.putFile = function(file, array, base) {
  var fileReader = new FileReader();
  var self = this;

  fileReader.onload = function(event) {
    var buf = event.target.result;
    var data = new Uint8Array(buf);
    for(var offset = 0; offset < data.length; offset++) {
      array[base+offset] = data[offset];
    }
    var alignedLength = Math.ceil(data.length/512)*512;
    for(var offset = data.length; offset < alignedLength; offset++) {
      array[base+offset] = 0;
    }
    self.filesLeft -= 1;
    if(self.filesLeft === 0) {
      self.callback(array);
    }
  };

  fileReader.readAsArrayBuffer(file);
};

Tarifier.prototype.putString = function(str, array, base) {
  var offset;
  for(offset = 0; offset < str.length; offset++) {
    array[offset+base] = str.charCodeAt(offset);
  }
  return base + str.length;
};

<commit_msg>Fix infinite loop when handling 0 byte files<commit_after>//expects array of file objects
//everything will be 0 levels deep

function Tarifier(files) {
  this.files = files;
}

Tarifier.prototype.tar = function(callback) {
  var files = this.files;
  this.filesLeft = files.length;
  this.callback = callback;

  var size = 512*files.length;
  for(var i = 0; i < files.length; i++) {
    size += Math.ceil(files[i].size/512)*512;
  }
  console.log("creating a file of size: "+size);

  var arrayBuffer = new ArrayBuffer(size);
  var array = new Uint8Array(arrayBuffer);

  var offset = 0;
  for(i = 0; i < files.length; i++) {
    this.putHeader(files[i], array, offset);
    offset += 512;
    var alignedSize = Math.ceil(files[i].size/512)*512;
    this.putFile(files[i], array, offset);
    offset += alignedSize;
  }
};

Tarifier.prototype.putHeader = function(file, array, base) {
  this.putString(file.name, array, base);

  var offset;

  for(offset = file.name.length; offset < 100; offset++)
    array[base+offset] = 0;

  this.putString("000644 \0", array,base+100); //file mode
  this.putString("000000 \0", array,base+108); //UID
  this.putString("000000 \0", array,base+116); //GID
  var octalSize = file.size.toString(8);
  while(octalSize.length < 11)
    octalSize = "0"+octalSize; //inefficient, but whatever

  octalSize += " ";
  this.putString(octalSize, array, base+124);
  this.putString("00000000000 ", array, base+136); //last modified time
  this.putString("        ", array, base+148); //checksum placeholder
  this.putString("0", array, base+156);

  for(offset = 157; offset < 512; offset++)
    array[base+offset] = 0;

  var sum = 0;
  for(offset = 0; offset < 512; offset++)
    sum += array[base+offset];
  sum = sum.toString(8);
  while(sum.length < 6)
    sum = "0"+sum;
  sum += " \0";
  this.putString(sum, array, base+148); //calculated checksum
};

Tarifier.prototype.putFile = function(file, array, base) {
  if(file.size === 0) {
    this.filesLeft -= 1;
    if(this.filesLeft === 0) {
      this.callback(array);
    }
    return;
  }

  var fileReader = new FileReader();
  var self = this;

  fileReader.onload = function(event) {
    var buf = event.target.result;
    var data = new Uint8Array(buf);
    for(var offset = 0; offset < data.length; offset++) {
      array[base+offset] = data[offset];
    }
    var alignedLength = Math.ceil(data.length/512)*512;
    for(offset = data.length; offset < alignedLength; offset++) {
      array[base+offset] = 0;
    }
    self.filesLeft -= 1;
    if(self.filesLeft === 0) {
      self.callback(array);
    }
  };

  fileReader.readAsArrayBuffer(file);
};

Tarifier.prototype.putString = function(str, array, base) {
  var offset;
  for(offset = 0; offset < str.length; offset++) {
    array[offset+base] = str.charCodeAt(offset);
  }
  return base + str.length;
};

<|endoftext|>


<commit_before>//since we only need centers of elements x y will be center
//var myTimer = setInterval(req, 5);
//function req(){requestAnimationFrame(test);}
//var firstArc=function(canvas,context,x, y, size, radians1, radians2, bool){

var canvas;
var context;
var hexaMap;

//not sure why these used
var angle=Math.random()*360;
var differentSpeed=angle;
var differentSpeed2=angle;
var x=0;
var y=0;

var firstArc={
	x:0,
	y:0,
	size:0,
	rad1:0,
	rad2:0,
	clockwise:true,

	execute:function(x,y,size,rad1,rad2){
		context.beginPath();
		context.arc(x,y,size,rad1,rad2,this.clockwise);
		context.lineWidth = 3;
		context.strokeStyle = hexaMap[Math.floor(Math.random())];
		context.stroke();
		context.closePath();
	}
};

var mouse = {x: 0, y: 0};

document.addEventListener('mousemove', function(e){
    mouse.x = e.clientX || e.pageX;
    mouse.y = e.clientY || e.pageY
}, false);

function start(){
	canvas=document.getElementById("igju");
	context=canvas.getContext("2d");
	hexaMap=newHexMap(1000);
	animate();
}

function animate(){
	draw();
	window.requestAnimationFrame(animate);
}

function draw(){
	angle+=1;
	if(angle>=360){angle=0;}
	if(differentSpeed>=360){differentSpeed=0;}
	var size=15;

	differentSpeed+=0.03;
	differentSpeed2+=0.02;

	//alert(angle);
	var radians = angle * (Math.PI/180);
	var r1=Math.random();
	var r2=Math.random();

	context.clearRect(0, 0, canvas.width, canvas.height);
	x=Math.cos(radians)*50.1+mouse.x;
	y=Math.sin(radians)*50.1+mouse.y;

	firstArc.execute(x,y,size,0,2*Math.PI);

	x=Math.cos(radians-Math.PI/3*2)*50.1+mouse.x;
	y=Math.sin(radians-Math.PI/3*2)*50.1+mouse.y;
	firstArc.execute(x,y,size,0,2*Math.PI);

	x=Math.cos(radians+Math.PI/3*2)*50.1+mouse.x;
	y=Math.sin(radians+Math.PI/3*2)*50.1+mouse.y;
	firstArc.execute(x,y,size,0,2*Math.PI);

	x=mouse.x;
	y=mouse.y;
	firstArc.clockwise=true;
	firstArc.execute(x,y,size+65,differentSpeed-0.2,differentSpeed+0.2);

	firstArc.execute(x,y,size,differentSpeed2-0.3,differentSpeed2+0.3);
	shootLaser(angle, mouse.x,mouse.y, 10);

}

function draw3(){
	//window.requestAnimationFrame(animate);
	updateObjects();
	drawObjects();
}

function updateObjects(){
	updateCircle();
	if(shoot()){updateLaser();}
	updateBoss();
}

function testState(){isColliding();}

//SOURCE or TARGET

var source = {
	x: "",
	y: "",
	w: "",
	h: "",
	facingAngle:"" //to determine which way is aiming

};

function shootLaser(angle, toX,toY, length){
	var radians =0;
	var x=0;
	var y=0;

	for(var i=0;i<length;i++){
		check(radians);
		radians=angle * (Math.PI/180);
		x=Math.cos(radians)*(i+i*15)+toX;
		y=Math.sin(radians)*(i+i*15)+toY;

		context.beginPath();
		//getAngleForArc(radians);
		context.arc(x, y, length, radians-0.2, radians+0.2, true);
		//context.fillStyle = hexaMap2[i];
		//context.fill();
		context.lineWidth = 3;
		context.strokeStyle = hexaMap[i];
		context.stroke();
	}
}

function getAngleForArc(angle){

	return angle;
}

function shoot(source,target){

}

function boxColission(source,target){
	if (source.x < target.x + target.width &&
		source.x + source.width > target.x &&
		source.y < target.y + target.height &&
		source.height + source.y > target.y) {
		return true;
	}
}

function circleColission(source,target){
	var dx = (source.x + source.radius) - (target.x + target.radius);
	var dy = (source.y + source.radius) - (target.y + target.radius);
	var distance = Math.sqrt(dx * dx + dy * dy);
	if (distance < source.radius + target.radius) {
		return true;
	}
}

//each time you shoot, detect collisions
//so maybe no need for interval
//but boss might need interval when he is shooting
//each time boss shoots, detect collisions

//function detectCollisions(){
//	setInterval(detectCollision,33,source,lazerAngle,arrayOfLocations);
//}

//what is source is an object ?

//NEED average minimum required to fit in to gap, because 100% aim is not possible
function isAimingRight(x1,y1,aimAngle,x2,y2,precision){

}

function isColliding(sourceObject,targetObject){

}

function isColliding2(source,lazerAngle,arrayOfLocations){
	//detect collision with what...
  source=source.split(",");

	var id=arrayOfLocations[0].split(",");
	var x=arrayOfLocations[1].split(",");
	var y=arrayOfLocations[2].split(",");
	//check angles of each location
	//check if lazer angle ¬ each location angle
	//for(var i=0;i<arrayOfLocations.length;i++){
		//if(lazer angle ¬ calculate angle source vs array of locations){
			//execute damagethis(current id);
		//}
	//}
}

//this function might be helpful when deciding which quadrant what angle
function angleConvertor(angle){
	var incrementor={
		x:0,
		y:0
	};
	if(angle===360){angle=0;}

	if(angle<=89 && angle >=0){

	}

	if(angle<=179 && angle >=90){
		angle-=90;
	}

	if(angle<=269 && angle >=180){
		angle-=180;
	}

	if(angle<=359 && angle >=270){
		angle-=270;
	}

	//var angel=
	return incrementor;
}

function randomDivLocation(idIn){
	positionDiv(idIn,Math.floor(Math.random()*1600),Math.floor(Math.random()*800));
}

function positionDiv(idIn,x,y){
	document.getElementById(idIn).style.left=x+"px";
	document.getElementById(idIn).style.top=y+"px";
}

function rotateDiv(idToRotate,angle) {
	// transform rotate for all browsers woohoo
	document.getElementById(idToRotate).style.WebkitTransform = "rotate("+angle+"deg)";
	document.getElementById(idToRotate).style.msTransform = "rotate("+angle+"deg)";
	document.getElementById(idToRotate).style.transform = "rotate("+angle+"deg)";
}

function getAngle(sourceX,sourceY,targetX,targetY){
	var x=targetX-sourceX;
	var y=targetY-sourceY;
	var radians=Math.atan2(y, x);//x y to radians
	var angle=radians * 180/Math.PI; //radians to degrees
	return angle;
}

function getDivCenterX(idIn){
	var element=document.getElementById(idIn);
	var offset = element.offsetLeft;
	var width = element.offsetWidth ;
	var x = offset + (width / 2);
	return x;
}

function getDivCenterY(idIn){
	var element=document.getElementById(idIn);
	var offset = element.offsetTop;
	var height = element.offsetHeight ;
	var y = offset + (height / 2);
	return y;
}

//mite be useful later since it gives correct quadrants
function getTargetQuadrant(x,y){
	if(x>0 && y>0){return 1;}//both positive
	if(x<0 && y<0){return 3;}//both negative
	if(x>0 && y<0){return 4;}//x positive
	if(x<0 && y>0){return 2;}//y positive
	//test for zeros
	if(x===0 && y>0){return 21;}//90% 90% above
	if(x===0 && y<0){return 34;}//270% 90% below
	if(x>0 && y===0){return 14;}//0% to the right
	if(x<0 && y===0){return 23;}//180% to the left
	if(x===0 && y===0){return 0;}//should not be allowed since it means on top of each
}

// OBJECTS LOCATION

var firstArc2=function(x, y, size, radians1, radians2){
		context.beginPath();
		context.arc(x, y, size, radians1, radians2, true);
		context.lineWidth = 3;
		context.strokeStyle = "#ffffff";
		context.stroke();
		context.closePath();
}
<commit_msg>cleaned, added<commit_after>//AVAILABLE FUNCTIONS
//var myTimer = setInterval(req, 5);
//start();	starts whole thing
//animate();	animates all
//draw();	draws once whatever is currently set up
//shootLaser(angle,toX,toY,size,length);
//listenMouse();
//boxColission(source,target);
//circleColission(source,target);
//radianToDegree(radian);
//getAngle(sourceX,sourceY,targetX,targetY);
//getTargetQuadrant(x,y);
//testCollisions();
//setSource(x,y,size,radians,shieldSpeed,laserSpeed,colorSpeed,laserWidth,shieldWidth,shieldColor,first,second,third,clockwise); SHOULD INSTEAD ACCEPT SOURCE OBJECT WHICH HAS ALL THESE VARIABLES

//VARIABLES
var canvas;
var context;
var hexaMap;
var angle=Math.random()*360;
var differentSpeed=angle;
var differentSpeed2=angle;

//OBJECTS
var mouse = {x:0, y:0, clicked:false};
var source = {x:"",y:"",w:"",h:"",angle:"",shieldColor:"",first:"",second:"",third:""};//each circle color in hex
var target = {x:"",y:"",w:"",h:"",angle:"",shieldColor:"",first:"",second:"",third:""};
var sourceLaser = {x:"",y:"",w:"",h:"",angle:"",color:""};
var targetLaser = {x:"",y:"",w:"",h:"",angle:"",color:""};

function start(){
	canvas=document.getElementById("igju");
	context=canvas.getContext("2d");
	hexaMap=newHexMap(1000);
	listenMouse();
	//------------------------------------------------------
	//this is just to test collisions
	source.w=100;
	source.h=100;

	target.w=100;
	target.h=100;
	//------------------------------------------------------
	setInterval(listenCollisions, 100);
	animate();
}

function animate(){
	draw();
	window.requestAnimationFrame(animate);
}

function draw(){
	context.clearRect(0, 0, canvas.width, canvas.height);
	var radians = angle * (Math.PI/180);
	angle+=1;
	differentSpeed+=0.03;
	differentSpeed2+=0.02;
	if(angle>=360){angle=0;}
	if(differentSpeed>=2*Math.PI){differentSpeed=0;}

	setSource(mouse.x,mouse.y,20,radians,differentSpeed2,differentSpeed,differentSpeed2,0.3,0.3,hexaMap[0],hexaMap[1],hexaMap[2],hexaMap[3],true);

	//------------------------------------------------------
	//this is just to test target colission (not with laser)
	var tarX=Math.random()*200+100;
	var tarY=Math.random()*200+100;
	setSource(tarX,tarY,20,radians,differentSpeed2,differentSpeed,differentSpeed2,0.3,0.3,hexaMap[6],hexaMap[7],hexaMap[8],hexaMap[9],true);
	source.x=mouse.x;
	source.y=mouse.y;
	target.x=tarX;
	target.y=tarY;
	//------------------------------------------------------
	//set the source object variable, should be done everywhere instead of functions accepting so many parameters
	source.angle=differentSpeed;
	if(mouse.clicked){shootLaser(source.angle, mouse.x,mouse.y,10, 100);}
}

function setSource(x,y,size,radians,shieldSpeed,laserSpeed,colorSpeed,laserWidth,shieldWidth,shieldColor,first,second,third,clockwise){
	drawArc(x,y,size,shieldSpeed+shieldWidth,shieldSpeed-shieldWidth,shieldColor,clockwise);//shield
	drawArc(x,y,size+60,laserSpeed+laserWidth,laserSpeed-laserWidth,shieldColor,clockwise);//laser
	//first
	drawArc(Math.cos(radians)*50.1+x,Math.sin(radians)*50.1+y,size,0,2*Math.PI,first,clockwise);
	//second
	drawArc(Math.cos(radians-Math.PI/3*2)*50.1+x,Math.sin(radians-Math.PI/3*2)*50.1+y,size,0,2*Math.PI,second,clockwise);
	//third
	drawArc(Math.cos(radians+Math.PI/3*2)*50.1+x,Math.sin(radians+Math.PI/3*2)*50.1+y,size,0,2*Math.PI,third,clockwise);
}

function drawArc(x,y,size,rad1,rad2,color,clockwise){
	context.beginPath();
	context.arc(x,y,size,rad1,rad2,this.clockwise);
	context.lineWidth = 5;//add parameter line width !!!
	context.strokeStyle = color;
	context.stroke();
	context.closePath();
}

function shootLaser(angle,toX,toY,size,length){
	var radians =0;
	var x=0;
	var y=0;

	for(var i=0;i<length;i++){
		//check(radians);
		radians=angle * (Math.PI/180);
		radians=angle;
		x=Math.cos(radians)*(i+i*15)+toX;
		y=Math.sin(radians)*(i+i*15)+toY;

		context.beginPath();
		//getAngleForArc(radians);
		context.arc(x, y, size, radians-0.2, radians+0.2, true);
		//context.fillStyle = hexaMap[i];
		//context.fill();
		context.lineWidth = 5;
		context.strokeStyle = hexaMap[i];
		context.stroke();
	}
}

//MOUSE LISTENERS
function listenMouse(){
		document.addEventListener('mousemove', function(e){
		mouse.x = e.clientX || e.pageX;
		mouse.y = e.clientY || e.pageY
	}, false);

	document.addEventListener('mousedown', function(e){
		mouse.x = e.clientX || e.pageX;
		mouse.y = e.clientY || e.pageY;
		mouse.clicked=true;
	}, false);

	document.addEventListener('mouseup', function(e){
		mouse.x = e.clientX || e.pageX;
		mouse.y = e.clientY || e.pageY;
		mouse.clicked=false;
	}, false);
}

//COLLISION DETECTION
function listenCollisions(){if(boxColission(source,target)){check("Source and Target Collided");} else{check("No Collision");}}

function boxColission(source,target){
	if (source.x < target.x + target.w &&
		source.x + source.w > target.x &&
		source.y < target.y + target.h &&
		source.h + source.y > target.y) {
		return true;
	}
	return false;
}

function circleColission(source,target){
	var dx = (source.x + source.radius) - (target.x + target.radius);
	var dy = (source.y + source.radius) - (target.y + target.radius);
	var distance = Math.sqrt(dx * dx + dy * dy);
	if (distance < source.radius + target.radius) {
		return true;
	}
	return false;
}

//ANGLE DETECTION
function radianToDegree(radian){var degree=radian * 180/Math.PI;return degree;}

function getAngle(sourceX,sourceY,targetX,targetY){
	var x=targetX-sourceX;
	var y=targetY-sourceY;
	var radians=Math.atan2(y, x);//x y to radians
	return angle;
}

//gives quadrants
function getTargetQuadrant(x,y){
	if(x>0 && y>0){return 1;}//both positive
	if(x<0 && y<0){return 3;}//both negative
	if(x>0 && y<0){return 4;}//x positive
	if(x<0 && y>0){return 2;}//y positive
	//test for zeros
	if(x===0 && y>0){return 21;}//90% 90% above
	if(x===0 && y<0){return 34;}//270% 90% below
	if(x>0 && y===0){return 14;}//0% to the right
	if(x<0 && y===0){return 23;}//180% to the left
	if(x===0 && y===0){return 0;}//should not be allowed since it means on top of each
}
<|endoftext|>


<commit_before>// Generated by CoffeeScript 1.3.3

/*
  jquery.turbolinks.js ~ v0.2.1 ~ https://github.com/kossnocorp/jquery.turbolinks

  jQuery plugin for drop-in fix binded events problem caused by Turbolinks

  The MIT License

  Copyright (c) 2012 Sasha Koss
*/

(function() {
  var $, callbacks, ready;

  $ = (typeof require === "function" ? require('jquery') : void 0) || window.jQuery;

  callbacks = [];

  ready = function() {
    var callback, _i, _len, _results;
    _results = [];
    for (_i = 0, _len = callbacks.length; _i < _len; _i++) {
      callback = callbacks[_i];
      _results.push(callback($));
    }
    return _results;
  };

  $(ready);

  $.fn.ready = function(callback) {
    return callbacks.push(callback);
  };

  $.setReadyEvent = function(event) {
    return $(document).off('.turbolinks').on(event + '.turbolinks', ready);
  };

  $.setReadyEvent('page:load');

}).call(this);
<commit_msg>Build js file for v1.0.0-rc<commit_after>// Generated by CoffeeScript 1.3.3

/*
  jquery.turbolinks.js ~ v1.0.0-rc ~ https://github.com/kossnocorp/jquery.turbolinks

  jQuery plugin for drop-in fix binded events problem caused by Turbolinks

  The MIT License

  Copyright (c) 2012 Sasha Koss
*/

(function() {
  var $, callbacks, ready;

  $ = (typeof require === "function" ? require('jquery') : void 0) || window.jQuery;

  callbacks = [];

  ready = function() {
    var callback, _i, _len, _results;
    _results = [];
    for (_i = 0, _len = callbacks.length; _i < _len; _i++) {
      callback = callbacks[_i];
      _results.push(callback($));
    }
    return _results;
  };

  $(ready);

  $.fn.ready = function(callback) {
    callbacks.push(callback);
    if ($.isReady) {
      return callback($);
    }
  };

  $.setReadyEvent = function(event) {
    return $(document).off('.turbolinks').on(event + '.turbolinks', ready);
  };

  $.setReadyEvent('page:load');

}).call(this);
<|endoftext|>