<commit_before>var actorCanvas, boardCanvas, pelletCanvas;
var gameBoard = new Board();

var drawPellets = function(context) {
  context.fillStyle = "#FCF";

  gameBoard.forEach(function(row, rIndex) {
    row.forEach(function(col, cIndex) {
      if(col == ".") {
        context.fillRect((8 * cIndex) + 3, (8 * rIndex) + 27, 2, 2);
      }
      else if(col == "o") {
        context.beginPath();
        context.arc((8 * cIndex) + 4, (8 * rIndex) + 28, 4, 0, 2 * Math.PI, false);
        context.closePath();
        context.fill();
      }
      else if(col == "-") {
        context.fillRect((8 * cIndex), (8 * rIndex) + 29, 8, 2);
      }
    });
  });
}

var aCxt, pacOsc, pacGain, pacModOsc, pacModGain;

var initAudio = function() {
  aCxt = !!AudioContext ? new AudioContext() : new webkitAudioContext();
  pacOsc = aCxt.createOscillator();
  pacModOsc = aCxt.createOscillator();
  pacGain = aCxt.createGain();
  pacModGain = aCxt.createGain();

  pacOsc.connect(pacGain);
  pacGain.connect(aCxt.destination);
  pacModOsc.connect(pacModGain);
  pacModGain.connect(pacOsc.frequency);

  pacModOsc.type = "triangle";
  pacOsc.type = "triangle";
  pacOsc.frequency.value = 415;
  pacGain.gain.value = 0.1;
  pacModOsc.frequency.value = 2.67;
  pacModGain.gain.value = 100;
}

var startPacAudio = function(seconds) {
  var runSeconds = seconds || 2;
  pacOsc.start();
  pacModOsc.start();
  pacOsc.stop(runSeconds);
  pacModOsc.stop(runSeconds);
}

var ready = function(fun) {
  if(document.readyState != "loading") {
    fun();
  }
  else if(document.addEventListener) {
    document.addEventListener("DOMContentLoaded", fun);
  }
  else {
    document.attachEvent("onreadystatechange", function() {
      if(document.readyState != "loading") {
        fun();
      }
    });
  }
}

ready(function() {
  actorCanvas = new View("actors");
  boardCanvas = new View("board");
  pelletCanvas = new View("pellets");

  var alignCanvases = function() {
    var x = boardCanvas.canvas.offsetLeft + boardCanvas.canvas.clientLeft + "px";
    var y = boardCanvas.canvas.offsetTop + boardCanvas.canvas.clientTop + "px";

    actorCanvas.canvas.style["left"] = x;
    actorCanvas.canvas.style["top"] = y;
    pelletCanvas.canvas.style["left"] = x;
    pelletCanvas.canvas.style["top"] = y;
  }
  alignCanvases();

  window.pac = new Actor({
    context: actorCanvas.context,
    startX: 113,
    startY: 212,
    name: "m",
    direction: "right"
  });

  addEventListener("keydown", pac.handleKeyDown.bind(pac));
  addEventListener("keyup", pac.handleKeyUp.bind(pac));

  var debugDisp = document.getElementById("debug");

  var x = 8;
  var y = 8;
  for(var prop in charset) {
    boardCanvas.drawObject({
      x: x,
      y: y,
      objectArr: charset[prop],
      color: {r: 255, g: 255, b: 255, a: 255}
    });
    x += 8;
    if(x + 8 > BOARD_WIDTH) {
      x = 8;
      y += 8;
    }
  }

  boardCanvas.context.putImageData(boardCanvas.canvasData, 0, 0);

  drawBorders(boardCanvas.context);
  drawPellets(pelletCanvas.context);

  // Green grid to delineate 8 x 8 tiles
  // context.fillStyle = "#080";
  // for(var x = 0; x < BOARD_WIDTH; x += 8) {
  //   context.fillRect(x, 0, 1, BOARD_HEIGHT);
  // }
  // for(var y = 0; y < BOARD_HEIGHT; y += 8) {
  //   context.fillRect(0, y, BOARD_WIDTH, 1);
  // }

  pac.render();

  var blinky = new Ghost({
    context: actorCanvas.context,
    direction: "left",
    name: "b",
    startX: 112,
    startY: 115
  });
  var inky = new Ghost({
    context: actorCanvas.context,
    direction: "up",
    name: "i",
    startX: 96,
    startY: 139
  });
  var pinky = new Ghost({
    context: actorCanvas.context,
    direction: "right",
    name: "p",
    startX: 112,
    startY: 139
  });
  var clyde = new Ghost({
    context: actorCanvas.context,
    direction: "down",
    name: "c",
    startX: 128,
    startY: 139
  });
});
<commit_msg>Correct gameBoard.forEach to gameBoard.board.forEach<commit_after>var actorCanvas, boardCanvas, pelletCanvas;
var gameBoard = new Board();

var drawPellets = function(context) {
  context.fillStyle = "#FCF";

  gameBoard.board.forEach(function(row, rIndex) {
    row.forEach(function(col, cIndex) {
      if(col == ".") {
        context.fillRect((8 * cIndex) + 3, (8 * rIndex) + 27, 2, 2);
      }
      else if(col == "o") {
        context.beginPath();
        context.arc((8 * cIndex) + 4, (8 * rIndex) + 28, 4, 0, 2 * Math.PI, false);
        context.closePath();
        context.fill();
      }
      else if(col == "-") {
        context.fillRect((8 * cIndex), (8 * rIndex) + 29, 8, 2);
      }
    });
  });
}

var aCxt, pacOsc, pacGain, pacModOsc, pacModGain;

var initAudio = function() {
  aCxt = !!AudioContext ? new AudioContext() : new webkitAudioContext();
  pacOsc = aCxt.createOscillator();
  pacModOsc = aCxt.createOscillator();
  pacGain = aCxt.createGain();
  pacModGain = aCxt.createGain();

  pacOsc.connect(pacGain);
  pacGain.connect(aCxt.destination);
  pacModOsc.connect(pacModGain);
  pacModGain.connect(pacOsc.frequency);

  pacModOsc.type = "triangle";
  pacOsc.type = "triangle";
  pacOsc.frequency.value = 415;
  pacGain.gain.value = 0.1;
  pacModOsc.frequency.value = 2.67;
  pacModGain.gain.value = 100;
}

var startPacAudio = function(seconds) {
  var runSeconds = seconds || 2;
  pacOsc.start();
  pacModOsc.start();
  pacOsc.stop(runSeconds);
  pacModOsc.stop(runSeconds);
}

var ready = function(fun) {
  if(document.readyState != "loading") {
    fun();
  }
  else if(document.addEventListener) {
    document.addEventListener("DOMContentLoaded", fun);
  }
  else {
    document.attachEvent("onreadystatechange", function() {
      if(document.readyState != "loading") {
        fun();
      }
    });
  }
}

ready(function() {
  actorCanvas = new View("actors");
  boardCanvas = new View("board");
  pelletCanvas = new View("pellets");

  var alignCanvases = function() {
    var x = boardCanvas.canvas.offsetLeft + boardCanvas.canvas.clientLeft + "px";
    var y = boardCanvas.canvas.offsetTop + boardCanvas.canvas.clientTop + "px";

    actorCanvas.canvas.style["left"] = x;
    actorCanvas.canvas.style["top"] = y;
    pelletCanvas.canvas.style["left"] = x;
    pelletCanvas.canvas.style["top"] = y;
  }
  alignCanvases();

  window.pac = new Actor({
    context: actorCanvas.context,
    startX: 113,
    startY: 212,
    name: "m",
    direction: "right"
  });

  addEventListener("keydown", pac.handleKeyDown.bind(pac));
  addEventListener("keyup", pac.handleKeyUp.bind(pac));

  var debugDisp = document.getElementById("debug");

  var x = 8;
  var y = 8;
  for(var prop in charset) {
    boardCanvas.drawObject({
      x: x,
      y: y,
      objectArr: charset[prop],
      color: {r: 255, g: 255, b: 255, a: 255}
    });
    x += 8;
    if(x + 8 > BOARD_WIDTH) {
      x = 8;
      y += 8;
    }
  }

  boardCanvas.context.putImageData(boardCanvas.canvasData, 0, 0);

  drawBorders(boardCanvas.context);
  drawPellets(pelletCanvas.context);

  // Green grid to delineate 8 x 8 tiles
  // context.fillStyle = "#080";
  // for(var x = 0; x < BOARD_WIDTH; x += 8) {
  //   context.fillRect(x, 0, 1, BOARD_HEIGHT);
  // }
  // for(var y = 0; y < BOARD_HEIGHT; y += 8) {
  //   context.fillRect(0, y, BOARD_WIDTH, 1);
  // }

  pac.render();

  var blinky = new Ghost({
    context: actorCanvas.context,
    direction: "left",
    name: "b",
    startX: 112,
    startY: 115
  });
  var inky = new Ghost({
    context: actorCanvas.context,
    direction: "up",
    name: "i",
    startX: 96,
    startY: 139
  });
  var pinky = new Ghost({
    context: actorCanvas.context,
    direction: "right",
    name: "p",
    startX: 112,
    startY: 139
  });
  var clyde = new Ghost({
    context: actorCanvas.context,
    direction: "down",
    name: "c",
    startX: 128,
    startY: 139
  });
});
<|endoftext|>


<commit_before>/**
 * Shopware 5
 * Copyright (c) shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 *
 * @category   Shopware
 * @package    Order
 * @subpackage Controller
 * @version    $Id$
 * @author shopware AG
 */

//{namespace name=backend/order/main}

/**
 * Shopware Controller - Order backend module
 */
//{block name="backend/order/controller/mail"}
Ext.define('Shopware.apps.Order.controller.Mail', {

    /**
     * Extend from the standard ExtJS 4 controller
     *
     * @type { String }
     */
    extend:'Ext.app.Controller',

   /**
    * all references to get the elements by the applicable selector
    *
    * @type { Array }
    */
    refs:[
        { ref:'mailWindow', selector:'order-mail-window' }
    ],

    /**
     * Contains all snippets for the this component
     *
     * @type { Object }
     */
    snippets: {
        growlMessage: '{s name=growlMessage}Order{/s}',

        successTitle: '{s name=sent_success_title}Email has been sent to customer [0]{/s}',
        successMessage: '{s name=sent_success_message}Email sent to customer [0]{/s}',

        errorTitle: '{s name=sent_error_title}Email could not be sent.{/s}',
        errorMessage: '{s name=sent_error_message}An error has occurred while sending the status mail:{/s}'
    },

    /**
     * A template method that is called when your application boots.
     * It is called before the Application's launch function is executed
     * so gives a hook point to run any code before your Viewport is created.
     */
    init:function () {
        var me = this;

        me.control({
            'order-mail-window order-mail-form': {
                sendMail: me.onSendMail
            }
        });

        me.callParent(arguments);
    },

    /**
     * Event listener method which is fired when the user clicks the "send email button" to send the displayed
     * email to the customer.
     *
     * @param { Ext.form.Panel } form
     */
    onSendMail: function(form) {
        var me = this,
            snippets = me.snippets,
            mail = form.getRecord(),
            rawData,
            message;

        form.getForm().updateRecord(mail);
        mail.setDirty();

        mail.save({
            callback: function(record, operation) {
                rawData = record.getProxy().getReader().rawData;

                if (!operation.success) {
                    Shopware.Notification.createGrowlMessage(snippets.errorTitle, snippets.errorMessage + '
' + rawData.message, snippets.growlMessage);
                    return;
                }

                mail.set('set', true);
                message = Ext.String.format(snippets.successMessage, mail.get('to'));
                Shopware.Notification.createGrowlMessage(snippets.successTitle, message, snippets.growlMessage);

                me.getMailWindow().destroy();
            }
        });
    }
});
//{/block}
<commit_msg>SW-10015 - add loading indicator to mail window<commit_after>/**
 * Shopware 5
 * Copyright (c) shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 *
 * @category   Shopware
 * @package    Order
 * @subpackage Controller
 * @version    $Id$
 * @author shopware AG
 */

//{namespace name=backend/order/main}

/**
 * Shopware Controller - Order backend module
 */
//{block name="backend/order/controller/mail"}
Ext.define('Shopware.apps.Order.controller.Mail', {

    /**
     * Extend from the standard ExtJS 4 controller
     *
     * @type { String }
     */
    extend:'Ext.app.Controller',

   /**
    * all references to get the elements by the applicable selector
    *
    * @type { Array }
    */
    refs:[
        { ref:'mailWindow', selector:'order-mail-window' }
    ],

    /**
     * Contains all snippets for the this component
     *
     * @type { Object }
     */
    snippets: {
        growlMessage: '{s name=growlMessage}Order{/s}',

        successTitle: '{s name=sent_success_title}Email has been sent to customer [0]{/s}',
        successMessage: '{s name=sent_success_message}Email sent to customer [0]{/s}',

        errorTitle: '{s name=sent_error_title}Email could not be sent.{/s}',
        errorMessage: '{s name=sent_error_message}An error has occurred while sending the status mail:{/s}'
    },

    /**
     * A template method that is called when your application boots.
     * It is called before the Application's launch function is executed
     * so gives a hook point to run any code before your Viewport is created.
     */
    init:function () {
        var me = this;

        me.control({
            'order-mail-window order-mail-form': {
                sendMail: me.onSendMail
            }
        });

        me.callParent(arguments);
    },

    /**
     * Event listener method which is fired when the user clicks the "send email button" to send the displayed
     * email to the customer.
     *
     * @param { Ext.form.Panel } form
     */
    onSendMail: function(form) {
        var me = this,
            win = me.getMailWindow(),
            snippets = me.snippets,
            mail = form.getRecord(),
            rawData,
            message;

        win.setLoading(true);

        form.getForm().updateRecord(mail);
        mail.setDirty();

        mail.save({
            callback: function(record, operation) {
                win.setLoading(false);

                rawData = record.getProxy().getReader().rawData;

                if (!operation.success) {
                    Shopware.Notification.createGrowlMessage(snippets.errorTitle, snippets.errorMessage + '
' + rawData.message, snippets.growlMessage);
                    return;
                }

                mail.set('set', true);
                message = Ext.String.format(snippets.successMessage, mail.get('to'));
                Shopware.Notification.createGrowlMessage(snippets.successTitle, message, snippets.growlMessage);

                win.destroy();
            }
        });
    }
});
//{/block}
<|endoftext|>


<commit_before>'use strict';

/* Controllers */
angular.module('phonecat')
    .controller('PhoneListCtrl', ['$location','$scope', '$http', '$log', 'Session','AuthenticationSharedService',
        function ($location,$scope, $http, $log, Session, AuthenticationSharedService )
        {
            $http.get('./Index:phones').success(function(data) {$scope.phones = data;});
            $scope.logout = function() {
                AuthenticationSharedService.logout();
            };
            $scope.orderProp = 'age';
            $scope.login = Session.login;

}]);

angular.module('phonecat')
    .controller('PhoneDetailCtrl', ['$scope','$rootScope', '$routeParams', '$http','CommentService',
        function ($scope,$rootScope, $routeParams, $http,CommentService) {

        $http.get('./Index:phoneDetails/' + $routeParams.phoneId ).success(function(data) {
            $scope.phone = data;
        });

        $scope.comments = CommentService.query({id:$routeParams.phoneId});

        /** Creates a new comment. */

        $scope.addedComment = new CommentService();

        /** Increments the number of likes of a comment, and saves the changes. */
        $scope.addLike = function(comment) {
            comment.$like(comment.id);
        };

        /** Delete a comment. */
        $scope.deleteComment = function(comment) {
            comment.$delete(comment.id).then(function() {
                $scope.comments.splice($scope.comments.indexOf(comment),1);
            }).catch(function() {
                $scope.error = 'ERROR';
            });

        };

        /** Adds a comment. */
        $scope.addComment = function() {
            if($rootScope.account != null)
                $scope.addedComment.author = $rootScope.account.login;
            $scope.addedComment.phoneId = $routeParams.phoneId;
            $scope.addedComment.$save(function(){

                $scope.comments.push($scope.addedComment);
                $scope.addedComment = new CommentService();
            });

        };

        $scope.showButton = function(){
                return $rootScope.authenticated;
        }

        $scope.requestLogin = function(){
            $rootScope.$emit('event:auth-loginRequired');
        }
    }]);

phonecat.controller('LoginCtrl', [ '$rootScope','$scope', '$location','AuthenticationSharedService',
    function ( $rootScope,$scope, $location,AuthenticationSharedService)  {
        $scope.rememberMe = true;
        $scope.login = function () {
            AuthenticationSharedService.login({
                username: $scope.username,
                password: $scope.password,
                rememberMe: $scope.rememberMe
            }).then(function () {
                $scope.authenticationError = false;
                $rootScope.authenticated = true;
                $location.path("/");
            }).catch(function () {
                $scope.authenticationError = true;
                $rootScope.authenticated = false;
            });
        }
    }]);

phonecat.controller('LogoutController', ['$location', 'AuthenticationSharedService',
    function ($location, AuthenticationSharedService) {
        AuthenticationSharedService.logout();
    }]);

phonecat.controller('RegisterController', ['$scope', 'Register',
    function ($scope, Register) {
        $scope.success = null;
        $scope.error = null;
        $scope.doNotMatch = null;
        $scope.errorUserExists = null;
        $scope.register = function () {
            if ($scope.registerAccount.password != $scope.confirmPassword) {
                $scope.doNotMatch = "ERROR";
            } else {
                $scope.doNotMatch = null;
                Register.save($scope.registerAccount,
                    function (value, responseHeaders) {
                        $scope.error = null;
                        $scope.errorUserExists = null;
                        $scope.success = 'OK';
                    },
                    function (httpResponse) {
                        $scope.success = null;
                        if (httpResponse.status === 304 &&
                            httpResponse.data.error && httpResponse.data.error === "Not Modified") {
                            $scope.error = null;
                            $scope.errorUserExists = "ERROR";
                        } else {
                            $scope.error = "ERROR";
                            $scope.errorUserExists = null;
                        }
                    });
            }
        }
    }]);<commit_msg>#2 : use $stateParams instead of $routeParams<commit_after>'use strict';

/* Controllers */
angular.module('phonecat')
    .controller('PhoneListCtrl', ['$location','$scope', '$http', '$log', 'Session','AuthenticationSharedService',
        function ($location,$scope, $http, $log, Session, AuthenticationSharedService )
        {
            $http.get('./Index:phones').success(function(data) {$scope.phones = data;});
            $scope.logout = function() {
                AuthenticationSharedService.logout();
            };
            $scope.orderProp = 'age';
            $scope.login = Session.login;

}]);

angular.module('phonecat')
    .controller('PhoneDetailCtrl', ['$scope','$rootScope', '$stateParams', '$http','CommentService',
        function ($scope,$rootScope, $stateParams, $http,CommentService) {

        $http.get('./Index:phoneDetails/' + $stateParams.phoneId ).success(function(data) {
            $scope.phone = data;
        });

        $scope.comments = CommentService.query({id:$stateParams.phoneId});

        /** Creates a new comment. */

        $scope.addedComment = new CommentService();

        /** Increments the number of likes of a comment, and saves the changes. */
        $scope.addLike = function(comment) {
            comment.$like(comment.id);
        };

        /** Delete a comment. */
        $scope.deleteComment = function(comment) {
            comment.$delete(comment.id).then(function() {
                $scope.comments.splice($scope.comments.indexOf(comment),1);
            }).catch(function() {
                $scope.error = 'ERROR';
            });

        };

        /** Adds a comment. */
        $scope.addComment = function() {
            if($rootScope.account != null)
                $scope.addedComment.author = $rootScope.account.login;
            $scope.addedComment.phoneId = $stateParams.phoneId;
            $scope.addedComment.$save(function(){

                $scope.comments.push($scope.addedComment);
                $scope.addedComment = new CommentService();
            });

        };

        $scope.showButton = function(){
                return $rootScope.authenticated;
        }

        $scope.requestLogin = function(){
            $rootScope.$emit('event:auth-loginRequired');
        }
    }]);

phonecat.controller('LoginCtrl', [ '$rootScope','$scope', '$location','AuthenticationSharedService',
    function ( $rootScope,$scope, $location,AuthenticationSharedService)  {
        $scope.rememberMe = true;
        $scope.login = function () {
            AuthenticationSharedService.login({
                username: $scope.username,
                password: $scope.password,
                rememberMe: $scope.rememberMe
            }).then(function () {
                $scope.authenticationError = false;
                $rootScope.authenticated = true;
                $location.path("/");
            }).catch(function () {
                $scope.authenticationError = true;
                $rootScope.authenticated = false;
            });
        }
    }]);

phonecat.controller('LogoutController', ['$location', 'AuthenticationSharedService',
    function ($location, AuthenticationSharedService) {
        AuthenticationSharedService.logout();
    }]);

phonecat.controller('RegisterController', ['$scope', 'Register',
    function ($scope, Register) {
        $scope.success = null;
        $scope.error = null;
        $scope.doNotMatch = null;
        $scope.errorUserExists = null;
        $scope.register = function () {
            if ($scope.registerAccount.password != $scope.confirmPassword) {
                $scope.doNotMatch = "ERROR";
            } else {
                $scope.doNotMatch = null;
                Register.save($scope.registerAccount,
                    function (value, responseHeaders) {
                        $scope.error = null;
                        $scope.errorUserExists = null;
                        $scope.success = 'OK';
                    },
                    function (httpResponse) {
                        $scope.success = null;
                        if (httpResponse.status === 304 &&
                            httpResponse.data.error && httpResponse.data.error === "Not Modified") {
                            $scope.error = null;
                            $scope.errorUserExists = "ERROR";
                        } else {
                            $scope.error = "ERROR";
                            $scope.errorUserExists = null;
                        }
                    });
            }
        }
    }]);<|endoftext|>


<commit_before>var path = require('path');
var url = require('url');
var fs = require('fs');
var mapnik = require('mapnik');
var Step = require('step');
var millstone = require('millstone');

models.Datasource.prototype.sync = function(method, model, success, error) {
    if (method !== 'read') return error('Method not supported.');

    var options = model.options;
    var config = Bones.plugin.config;

    if (!options) return error(new Error('options are required.'));
    if (!options.id) return error(new Error('id is required.'));
    if (!options.project) return error(new Error('project is required.'));

    millstone.resolve({
        mml: {
            Stylesheet: [{ id: 'layer', data: '' }],
            Layer: [{
                name: options.id,
                srs: options.srs || '',
                Datasource: options
            }]
        },
        base: path.join(config.files, 'project', options.project),
        cache: path.join(config.files, 'cache')
    }, function(err, mml) {
        if (err) return error(err);

        try {
            mml.Layer[0].Datasource = _(mml.Layer[0].Datasource).defaults(options);

            // Some mapnik datasources accept 'row_limit` (like postgis, shape)
            // those that do not will be restricted during the featureset loop below
            var row_limit = 500;
            mml.Layer[0].Datasource = _(mml.Layer[0].Datasource).defaults({
                row_limit: row_limit
                });

            // simplistic validation that subselects have the key_field string present
            // not a proper parser, but this is not the right place to be parsing SQL
            // https://github.com/mapbox/tilemill/issues/1509
            if (mml.Layer[0].Datasource.table !== undefined
                && mml.Layer[0].Datasource.key_field !== undefined
                && mml.Layer[0].Datasource.table.match(/select /i)
                && mml.Layer[0].Datasource.table.search(mml.Layer[0].Datasource.key_field) == -1) {
                    return error(new Error("Your SQL subquery needs to contain the custom key_field supplied: '" + mml.Layer[0].Datasource.key_field + "'"));
            }

            var source = new mapnik.Datasource(mml.Layer[0].Datasource);

            var features = [];
            if (!(source.type == "raster") && (options.features || options.info)) {
                var featureset = source.featureset();
                for (var i = 0, feat;
                    i < row_limit && (feat = featureset.next(true));
                    i++) {
                    features.push(feat.attributes());
                }
            }

            // Convert datasource extent to lon/lat when saving
            var layerProj = new mapnik.Projection(mml.Layer[0].srs),
                unProj = new mapnik.Projection('+proj=longlat +ellps=WGS84 +no_defs'),
                trans = new mapnik.ProjTransform(layerProj, unProj),
                extent = trans.forward(source.extent());
            // clamp to valid extents
            (extent[0] < -180) && (extent[0] = -180);
            (extent[1] < -85.051) && (extent[1] = -85.051);
            (extent[2] > 180) && (extent[2] = 180);
            (extent[3] > 85.051) && (extent[3] = 85.051);

            var desc = source.describe();
            var datasource = {
                id: options.id,
                project: options.project,
                url: options.file,
                fields: desc.fields,
                features: options.features ? features : [],
                type: desc.type,
                geometry_type: desc.type === 'raster' ? 'raster' : desc.geometry_type,
                extent: extent
            };

            // Process fields and calculate min/max values.
            for (var f in datasource.fields) {
                var values = _(features).pluck(f);
                var type = datasource.fields[f];
                datasource.fields[f] = { type: type };
                if (options.features || options.info) {
                    datasource.fields[f].max = type === 'String'
                        ? _(values).max(function(v) { return (v||'').length })
                        : _(values).max();
                    datasource.fields[f].min = type === 'String'
                        ? _(values).min(function(v) { return (v||'').length })
                        : _(values).min();
                }
            }
        } catch(err) {
            return error(err);
        }

        success(datasource);
    });
};
<commit_msg>relax naive sql query validation so that 'select *' is okay again - closes #1549<commit_after>var path = require('path');
var url = require('url');
var fs = require('fs');
var mapnik = require('mapnik');
var Step = require('step');
var millstone = require('millstone');

models.Datasource.prototype.sync = function(method, model, success, error) {
    if (method !== 'read') return error('Method not supported.');

    var options = model.options;
    var config = Bones.plugin.config;

    if (!options) return error(new Error('options are required.'));
    if (!options.id) return error(new Error('id is required.'));
    if (!options.project) return error(new Error('project is required.'));

    millstone.resolve({
        mml: {
            Stylesheet: [{ id: 'layer', data: '' }],
            Layer: [{
                name: options.id,
                srs: options.srs || '',
                Datasource: options
            }]
        },
        base: path.join(config.files, 'project', options.project),
        cache: path.join(config.files, 'cache')
    }, function(err, mml) {
        if (err) return error(err);

        try {
            mml.Layer[0].Datasource = _(mml.Layer[0].Datasource).defaults(options);

            // Some mapnik datasources accept 'row_limit` (like postgis, shape)
            // those that do not will be restricted during the featureset loop below
            var row_limit = 500;
            mml.Layer[0].Datasource = _(mml.Layer[0].Datasource).defaults({
                row_limit: row_limit
                });

            // simplistic validation that subselects have the key_field string present
            // not a proper parser, but this is not the right place to be parsing SQL
            // https://github.com/mapbox/tilemill/issues/1509
            if (mml.Layer[0].Datasource.table !== undefined
                && mml.Layer[0].Datasource.key_field !== undefined
                && mml.Layer[0].Datasource.table.match(/select /i)
                && mml.Layer[0].Datasource.table.indexOf('*') == -1
                && mml.Layer[0].Datasource.table.search(mml.Layer[0].Datasource.key_field) == -1) {
                    return error(new Error("Your SQL subquery needs to explicitly include the custom key_field: '" + mml.Layer[0].Datasource.key_field + "' or use 'select *' to request all fields"));
            }

            var source = new mapnik.Datasource(mml.Layer[0].Datasource);

            var features = [];
            if (!(source.type == "raster") && (options.features || options.info)) {
                var featureset = source.featureset();
                for (var i = 0, feat;
                    i < row_limit && (feat = featureset.next(true));
                    i++) {
                    features.push(feat.attributes());
                }
            }

            // Convert datasource extent to lon/lat when saving
            var layerProj = new mapnik.Projection(mml.Layer[0].srs),
                unProj = new mapnik.Projection('+proj=longlat +ellps=WGS84 +no_defs'),
                trans = new mapnik.ProjTransform(layerProj, unProj),
                extent = trans.forward(source.extent());
            // clamp to valid extents
            (extent[0] < -180) && (extent[0] = -180);
            (extent[1] < -85.051) && (extent[1] = -85.051);
            (extent[2] > 180) && (extent[2] = 180);
            (extent[3] > 85.051) && (extent[3] = 85.051);

            var desc = source.describe();
            var datasource = {
                id: options.id,
                project: options.project,
                url: options.file,
                fields: desc.fields,
                features: options.features ? features : [],
                type: desc.type,
                geometry_type: desc.type === 'raster' ? 'raster' : desc.geometry_type,
                extent: extent
            };

            // Process fields and calculate min/max values.
            for (var f in datasource.fields) {
                var values = _(features).pluck(f);
                var type = datasource.fields[f];
                datasource.fields[f] = { type: type };
                if (options.features || options.info) {
                    datasource.fields[f].max = type === 'String'
                        ? _(values).max(function(v) { return (v||'').length })
                        : _(values).max();
                    datasource.fields[f].min = type === 'String'
                        ? _(values).min(function(v) { return (v||'').length })
                        : _(values).min();
                }
            }
        } catch(err) {
            return error(err);
        }

        success(datasource);
    });
};
<|endoftext|>


<commit_before>/*global define*/
define([
        '../Core/defaultValue',
        '../Core/defined',
        '../Core/defineProperties',
        '../Core/destroyObject',
        '../Core/DeveloperError',
        '../Core/getMagic',
        '../Core/loadArrayBuffer',
        '../Core/Request',
        '../Core/RequestScheduler',
        '../Core/RequestType',
        '../ThirdParty/when',
        './Cesium3DTileContentState'
    ], function(
        defaultValue,
        defined,
        defineProperties,
        destroyObject,
        DeveloperError,
        getMagic,
        loadArrayBuffer,
        Request,
        RequestScheduler,
        RequestType,
        when,
        Cesium3DTileContentState) {
    'use strict';

    /**
     * Represents the contents of a
     * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Composite/README.md|Composite}
     * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset.
     *
     * @alias Composite3DTileContent
     * @constructor
     *
     * @private
     */
    function Composite3DTileContent(tileset, tile, url, factory) {
        this._url = url;
        this._tileset = tileset;
        this._tile = tile;
        this._contents = [];
        this._factory = factory;

        /**
         * The following properties are part of the {@link Cesium3DTileContent} interface.
         */
        this.state = Cesium3DTileContentState.UNLOADED;
        this.batchTable = undefined;

        this._contentReadyToProcessPromise = when.defer();
        this._readyPromise = when.defer();
    }

    defineProperties(Composite3DTileContent.prototype, {
        /**
         * Part of the {@link Cesium3DTileContent} interface.
         */
        featurePropertiesDirty : {
            get : function() {
                var contents = this._contents;
                var length = contents.length;
                for (var i = 0; i < length; ++i) {
                    if (contents[i].featurePropertiesDirty) {
                        return true;
                    }
                }

                return false;
            },
            set : function(value) {
                var contents = this._contents;
                var length = contents.length;
                for (var i = 0; i < length; ++i) {
                    contents[i].featurePropertiesDirty = value;
                }
            }
        },

        /**
         * Part of the {@link Cesium3DTileContent} interface.  Composite3DTileContent
         * always returns 0.  Instead call featuresLength for a tile in the composite.
         */
        featuresLength : {
            get : function() {
                return 0;
            }
        },

        /**
         * Part of the {@link Cesium3DTileContent} interface.  Composite3DTileContent
         * always returns 0.  Instead call pointsLength for a tile in the composite.
         */
        pointsLength : {
            get : function() {
                return 0;
            }
        },

        /**
         * Gets the array of {@link Cesium3DTileContent} objects that represent the
         * content of the composite's inner tiles, which can also be composites.
         */
        innerContents : {
            get : function() {
                return this._contents;
            }
        },

        /**
         * Part of the {@link Cesium3DTileContent} interface.
         */
        contentReadyToProcessPromise : {
            get : function() {
                return this._contentReadyToProcessPromise.promise;
            }
        },

        /**
         * Part of the {@link Cesium3DTileContent} interface.
         */
        readyPromise : {
            get : function() {
                return this._readyPromise.promise;
            }
        }
    });

    /**
     * Part of the {@link Cesium3DTileContent} interface.  Composite3DTileContent
     * always returns false.  Instead call hasProperty for a tile in the composite.
     */
    Composite3DTileContent.prototype.hasProperty = function(batchId, name) {
        return false;
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.  Composite3DTileContent
     * always returns undefined.  Instead call getFeature for a tile in the composite.
     */
    Composite3DTileContent.prototype.getFeature = function(batchId) {
        return undefined;
    };

    var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.request = function() {
        var that = this;

        var distance = this._tile.distanceToCamera;
        var promise = RequestScheduler.schedule(new Request({
            url : this._url,
            server : this._tile.requestServer,
            requestFunction : loadArrayBuffer,
            type : RequestType.TILES3D,
            distance : distance
        }));

        if (!defined(promise)) {
            return false;
        }

        this.state = Cesium3DTileContentState.LOADING;
        promise.then(function(arrayBuffer) {
            if (that.isDestroyed()) {
                return when.reject('tileset is destroyed');
            }
            that.initialize(arrayBuffer);
        }).otherwise(function(error) {
            that.state = Cesium3DTileContentState.FAILED;
            that._readyPromise.reject(error);
        });
        return true;
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.initialize = function(arrayBuffer, byteOffset) {
        byteOffset = defaultValue(byteOffset, 0);

        var uint8Array = new Uint8Array(arrayBuffer);
        var magic = getMagic(uint8Array, byteOffset);
        if (magic !== 'cmpt') {
            throw new DeveloperError('Invalid Composite Tile. Expected magic=cmpt. Read magic=' + magic);
        }

        var view = new DataView(arrayBuffer);

        byteOffset += sizeOfUint32;  // Skip magic number

        //>>includeStart('debug', pragmas.debug);
        var version = view.getUint32(byteOffset, true);
        if (version !== 1) {
            throw new DeveloperError('Only Composite Tile version 1 is supported. Version ' + version + ' is not.');
        }
        //>>includeEnd('debug');
        byteOffset += sizeOfUint32;

        // Skip byteLength
        byteOffset += sizeOfUint32;

        var tilesLength = view.getUint32(byteOffset, true);
        byteOffset += sizeOfUint32;

        this.state = Cesium3DTileContentState.PROCESSING;
        this._contentReadyToProcessPromise.resolve(this);

        var contentPromises = [];

        for (var i = 0; i < tilesLength; ++i) {
            var tileType = getMagic(uint8Array, byteOffset);

            // Tile byte length is stored after magic and version
            var tileByteLength = view.getUint32(byteOffset + sizeOfUint32 * 2, true);

            var contentFactory = this._factory[tileType];

            if (defined(contentFactory)) {
                var content = contentFactory(this._tileset, this._tile, this._url);
                content.initialize(arrayBuffer, byteOffset);
                this._contents.push(content);
                contentPromises.push(content.readyPromise);
            } else {
                throw new DeveloperError('Unknown tile content type, ' + tileType + ', inside Composite tile');
            }

            byteOffset += tileByteLength;
        }

        var that = this;

        when.all(contentPromises).then(function() {
            that.state = Cesium3DTileContentState.READY;
            that._readyPromise.resolve(that);
        }).otherwise(function(error) {
            that.state = Cesium3DTileContentState.FAILED;
            that._readyPromise.reject(error);
        });
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.applyDebugSettings = function(enabled, color) {
        var contents = this._contents;
        var length = contents.length;
        for (var i = 0; i < length; ++i) {
            contents[i].applyDebugSettings(enabled, color);
        }
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.update = function(tileset, context, frameState, commandList) {
        var contents = this._contents;
        var length = contents.length;
        for (var i = 0; i < length; ++i) {
            contents[i].update(tileset, context, frameState, commandList);
        }
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.isDestroyed = function() {
        return false;
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.destroy = function() {
        var contents = this._contents;
        var length = contents.length;
        for (var i = 0; i < length; ++i) {
            contents[i].destroy();
        }
        return destroyObject(this);
    };

    return Composite3DTileContent;
});
<commit_msg>Add memory getters to Composite3DTileContent<commit_after>/*global define*/
define([
        '../Core/defaultValue',
        '../Core/defined',
        '../Core/defineProperties',
        '../Core/destroyObject',
        '../Core/DeveloperError',
        '../Core/getMagic',
        '../Core/loadArrayBuffer',
        '../Core/Request',
        '../Core/RequestScheduler',
        '../Core/RequestType',
        '../ThirdParty/when',
        './Cesium3DTileContentState'
    ], function(
        defaultValue,
        defined,
        defineProperties,
        destroyObject,
        DeveloperError,
        getMagic,
        loadArrayBuffer,
        Request,
        RequestScheduler,
        RequestType,
        when,
        Cesium3DTileContentState) {
    'use strict';

    /**
     * Represents the contents of a
     * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Composite/README.md|Composite}
     * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset.
     *
     * @alias Composite3DTileContent
     * @constructor
     *
     * @private
     */
    function Composite3DTileContent(tileset, tile, url, factory) {
        this._url = url;
        this._tileset = tileset;
        this._tile = tile;
        this._contents = [];
        this._factory = factory;

        /**
         * The following properties are part of the {@link Cesium3DTileContent} interface.
         */
        this.state = Cesium3DTileContentState.UNLOADED;
        this.batchTable = undefined;

        this._contentReadyToProcessPromise = when.defer();
        this._readyPromise = when.defer();
    }

    defineProperties(Composite3DTileContent.prototype, {
        /**
         * Part of the {@link Cesium3DTileContent} interface.
         */
        featurePropertiesDirty : {
            get : function() {
                var contents = this._contents;
                var length = contents.length;
                for (var i = 0; i < length; ++i) {
                    if (contents[i].featurePropertiesDirty) {
                        return true;
                    }
                }

                return false;
            },
            set : function(value) {
                var contents = this._contents;
                var length = contents.length;
                for (var i = 0; i < length; ++i) {
                    contents[i].featurePropertiesDirty = value;
                }
            }
        },

        /**
         * Part of the {@link Cesium3DTileContent} interface.  Composite3DTileContent
         * always returns 0.  Instead call featuresLength for a tile in the composite.
         */
        featuresLength : {
            get : function() {
                return 0;
            }
        },

        /**
         * Part of the {@link Cesium3DTileContent} interface.  Composite3DTileContent
         * always returns 0.  Instead call pointsLength for a tile in the composite.
         */
        pointsLength : {
            get : function() {
                return 0;
            }
        },

        /**
         * Part of the {@link Cesium3DTileContent} interface.
         */
        vertexMemoryInBytes : {
            get : function() {
                return 0;
            }
        },

        /**
         * Part of the {@link Cesium3DTileContent} interface.
         */
        textureMemoryInBytes : {
            get : function() {
                return 0;
            }
        },

        /**
         * Gets the array of {@link Cesium3DTileContent} objects that represent the
         * content of the composite's inner tiles, which can also be composites.
         */
        innerContents : {
            get : function() {
                return this._contents;
            }
        },

        /**
         * Part of the {@link Cesium3DTileContent} interface.
         */
        contentReadyToProcessPromise : {
            get : function() {
                return this._contentReadyToProcessPromise.promise;
            }
        },

        /**
         * Part of the {@link Cesium3DTileContent} interface.
         */
        readyPromise : {
            get : function() {
                return this._readyPromise.promise;
            }
        }
    });

    /**
     * Part of the {@link Cesium3DTileContent} interface.  Composite3DTileContent
     * always returns false.  Instead call hasProperty for a tile in the composite.
     */
    Composite3DTileContent.prototype.hasProperty = function(batchId, name) {
        return false;
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.  Composite3DTileContent
     * always returns undefined.  Instead call getFeature for a tile in the composite.
     */
    Composite3DTileContent.prototype.getFeature = function(batchId) {
        return undefined;
    };

    var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT;

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.request = function() {
        var that = this;

        var distance = this._tile.distanceToCamera;
        var promise = RequestScheduler.schedule(new Request({
            url : this._url,
            server : this._tile.requestServer,
            requestFunction : loadArrayBuffer,
            type : RequestType.TILES3D,
            distance : distance
        }));

        if (!defined(promise)) {
            return false;
        }

        this.state = Cesium3DTileContentState.LOADING;
        promise.then(function(arrayBuffer) {
            if (that.isDestroyed()) {
                return when.reject('tileset is destroyed');
            }
            that.initialize(arrayBuffer);
        }).otherwise(function(error) {
            that.state = Cesium3DTileContentState.FAILED;
            that._readyPromise.reject(error);
        });
        return true;
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.initialize = function(arrayBuffer, byteOffset) {
        byteOffset = defaultValue(byteOffset, 0);

        var uint8Array = new Uint8Array(arrayBuffer);
        var magic = getMagic(uint8Array, byteOffset);
        if (magic !== 'cmpt') {
            throw new DeveloperError('Invalid Composite Tile. Expected magic=cmpt. Read magic=' + magic);
        }

        var view = new DataView(arrayBuffer);

        byteOffset += sizeOfUint32;  // Skip magic number

        //>>includeStart('debug', pragmas.debug);
        var version = view.getUint32(byteOffset, true);
        if (version !== 1) {
            throw new DeveloperError('Only Composite Tile version 1 is supported. Version ' + version + ' is not.');
        }
        //>>includeEnd('debug');
        byteOffset += sizeOfUint32;

        // Skip byteLength
        byteOffset += sizeOfUint32;

        var tilesLength = view.getUint32(byteOffset, true);
        byteOffset += sizeOfUint32;

        this.state = Cesium3DTileContentState.PROCESSING;
        this._contentReadyToProcessPromise.resolve(this);

        var contentPromises = [];

        for (var i = 0; i < tilesLength; ++i) {
            var tileType = getMagic(uint8Array, byteOffset);

            // Tile byte length is stored after magic and version
            var tileByteLength = view.getUint32(byteOffset + sizeOfUint32 * 2, true);

            var contentFactory = this._factory[tileType];

            if (defined(contentFactory)) {
                var content = contentFactory(this._tileset, this._tile, this._url);
                content.initialize(arrayBuffer, byteOffset);
                this._contents.push(content);
                contentPromises.push(content.readyPromise);
            } else {
                throw new DeveloperError('Unknown tile content type, ' + tileType + ', inside Composite tile');
            }

            byteOffset += tileByteLength;
        }

        var that = this;

        when.all(contentPromises).then(function() {
            that.state = Cesium3DTileContentState.READY;
            that._readyPromise.resolve(that);
        }).otherwise(function(error) {
            that.state = Cesium3DTileContentState.FAILED;
            that._readyPromise.reject(error);
        });
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.applyDebugSettings = function(enabled, color) {
        var contents = this._contents;
        var length = contents.length;
        for (var i = 0; i < length; ++i) {
            contents[i].applyDebugSettings(enabled, color);
        }
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.update = function(tileset, context, frameState, commandList) {
        var contents = this._contents;
        var length = contents.length;
        for (var i = 0; i < length; ++i) {
            contents[i].update(tileset, context, frameState, commandList);
        }
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.isDestroyed = function() {
        return false;
    };

    /**
     * Part of the {@link Cesium3DTileContent} interface.
     */
    Composite3DTileContent.prototype.destroy = function() {
        var contents = this._contents;
        var length = contents.length;
        for (var i = 0; i < length; ++i) {
            contents[i].destroy();
        }
        return destroyObject(this);
    };

    return Composite3DTileContent;
});
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';

import style from 'PVWStyle/ReactProperties/CheckboxProperty.mcss';

export default class Checkbox extends React.Component {
  constructor(props) {
    super(props);

    // Callback binding
    this.valueChange = this.valueChange.bind(this);
  }

  valueChange(e) {
    if (this.props.onChange) {
      if (this.props.idx >= 0) {
        this.props.onChange(this.props.idx, e.target.checked);
      } else {
        this.props.onChange(null, e.target.checked);
      }
    }
  }

  render() {
    return (

        {this.props.label}
        <input
          className={style.input}
          type="checkbox"
          checked={this.props.value}
          onChange={this.valueChange}
        />

    );
  }
}

Checkbox.propTypes = {
  idx: PropTypes.number.isRequired,
  label: PropTypes.string,
  onChange: PropTypes.func.isRequired,
  value: PropTypes.bool,
};

Checkbox.defaultProps = {
  value: false,
  label: '',
};
<commit_msg>fix(CheckboxProperty): Relax required prop constraint<commit_after>import React from 'react';
import PropTypes from 'prop-types';

import style from 'PVWStyle/ReactProperties/CheckboxProperty.mcss';

export default class Checkbox extends React.Component {
  constructor(props) {
    super(props);

    // Callback binding
    this.valueChange = this.valueChange.bind(this);
  }

  valueChange(e) {
    if (this.props.onChange) {
      if (this.props.idx >= 0) {
        this.props.onChange(this.props.idx, e.target.checked);
      } else {
        this.props.onChange(null, e.target.checked);
      }
    }
  }

  render() {
    return (

        {this.props.label}
        <input
          className={style.input}
          type="checkbox"
          checked={this.props.value}
          onChange={this.valueChange}
        />

    );
  }
}

Checkbox.propTypes = {
  idx: PropTypes.number,
  label: PropTypes.string,
  onChange: PropTypes.func.isRequired,
  value: PropTypes.bool,
};

Checkbox.defaultProps = {
  value: false,
  label: '',
  idx: undefined,
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';

class ReportSelecter extends Component {
  static propTypes = {
    onSubmit: React.PropTypes.func.isRequired,
  };

  codeInput = null;

  constructor() {
    super();
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  componentDidMount() {
    this.codeInput.focus();
  }

  handleSubmit(e) {
    const { onSubmit } = this.props;

    e.preventDefault();

    const code = this.codeInput.value;

    if (!code) {
      alert('Enter the report code.');
      return;
    }

    onSubmit(code.trim());
  }

  render() {
    return (

        <form onSubmit={this.handleSubmit} className="form-inline">

Analyze your Holy Paladin performance

              Use this tool to analyze your performance as a Holy Paladin based on important metrics for the spec.

              You will need a Warcraft Logs report with advanced combat logging enabled to start. Private logs can not be used, if your guild has private logs you will have to
              {' '}upload your own logs or change the existing logs to the
              unlisted privacy option instead.

Analyze report

              Enter your Warcraft Logs report code.

              https://www.warcraftlogs.com/reports/<input type="text" name="code" className="form-control" ref={(elem) => {
              this.codeInput = elem;
            }} style={{ width: 175 }} placeholder="Report code" autoCorrect="off" autoCapitalize="off" spellCheck="false" />/

              <button type="submit" className="btn btn-primary">
                Start
              </button>

Changes

              10-04-2017 - Show an error when parsing crashes (usually caused by not having advanced combat logging on). Renamed Casts Per Minute to Cast Efficiency. Show absolute amount of casts in Cast Efficiency. Added Arcane Torrent to Cast Efficiency (only shown if you cast it at least once).

              09-04-2017 - Added Casts Per Minute table with very basic recommendations.

              08-04-2017 - Added Heals on beacon statistic.

              08-04-2017 - Added Wowhead tooltips and show T19 4 set bonus gain.

              08-04-2017 - Added Beacon of the Lightbringer mastery radius support!

              08-04-2017 - Improve beacon healing tracking accuracy and it now works properly with Beacon of Virtue.

              08-04-2017 - Total healing done count now includes absorbed healing.

              07-04-2017 - New layout with many usability improvements!

              04-04-2017 - Add an Always Be Casting (ABC) module that checks your
              Non healing time and dead GCD time (this is shown in the tooltip).

              29-03-2017 - Fixed a bug where Maraad's healing statistic would show 0% healing after getting only 1 Maraad's charge.

              29-03-2017 - Update healing bonuses to the 7.2 values (DoS & Ilterendi nerfs).

              27-03-2017 - Added Maraad's Dying Breath healing statistic.

              27-03-2017 - Added Prydaz and Obsidian Stone Spaulders healing statistic.

              26-03-2017 - Added Chain of Thrayn healing statistic.

              26-03-2017 - Completely refactor the core, rename to Holy Paladin Analyzer.

              25-03-2017 - Added cast ratios statistic.

            Created by Zerotorescue for the
            #holy Discord. You can usually find helpful people there.

        </form>

    );
  }
}

export default ReportSelecter;
<commit_msg>Update changelog<commit_after>import React, { Component } from 'react';

class ReportSelecter extends Component {
  static propTypes = {
    onSubmit: React.PropTypes.func.isRequired,
  };

  codeInput = null;

  constructor() {
    super();
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  componentDidMount() {
    this.codeInput.focus();
  }

  handleSubmit(e) {
    const { onSubmit } = this.props;

    e.preventDefault();

    const code = this.codeInput.value;

    if (!code) {
      alert('Enter the report code.');
      return;
    }

    onSubmit(code.trim());
  }

  render() {
    return (

        <form onSubmit={this.handleSubmit} className="form-inline">

Analyze your Holy Paladin performance

              Use this tool to analyze your performance as a Holy Paladin based on important metrics for the spec.

              You will need a Warcraft Logs report with advanced combat logging enabled to start. Private logs can not be used, if your guild has private logs you will have to
              {' '}upload your own logs or change the existing logs to the
              unlisted privacy option instead.

Analyze report

              Enter your Warcraft Logs report code.

              https://www.warcraftlogs.com/reports/<input type="text" name="code" className="form-control" ref={(elem) => {
              this.codeInput = elem;
            }} style={{ width: 175 }} placeholder="Report code" autoCorrect="off" autoCapitalize="off" spellCheck="false" />/

              <button type="submit" className="btn btn-primary">
                Start
              </button>

Changes

              11-04-2017 - Added Rule of Law to cast efficiency and grouped spells by category.

              10-04-2017 - Show an error when parsing crashes (usually caused by not having advanced combat logging on). Renamed Casts Per Minute to Cast Efficiency. Show absolute amount of casts in Cast Efficiency. Added Arcane Torrent to Cast Efficiency (only shown if you cast it at least once).

              09-04-2017 - Added Casts Per Minute table with very basic recommendations.

              08-04-2017 - Added Heals on beacon statistic.

              08-04-2017 - Added Wowhead tooltips and show T19 4 set bonus gain.

              08-04-2017 - Added Beacon of the Lightbringer mastery radius support!

              08-04-2017 - Improve beacon healing tracking accuracy and it now works properly with Beacon of Virtue.

              08-04-2017 - Total healing done count now includes absorbed healing.

              07-04-2017 - New layout with many usability improvements!

              04-04-2017 - Add an Always Be Casting (ABC) module that checks your
              Non healing time and dead GCD time (this is shown in the tooltip).

              29-03-2017 - Fixed a bug where Maraad's healing statistic would show 0% healing after getting only 1 Maraad's charge.

              29-03-2017 - Update healing bonuses to the 7.2 values (DoS & Ilterendi nerfs).

              27-03-2017 - Added Maraad's Dying Breath healing statistic.

              27-03-2017 - Added Prydaz and Obsidian Stone Spaulders healing statistic.

              26-03-2017 - Added Chain of Thrayn healing statistic.

              26-03-2017 - Completely refactor the core, rename to Holy Paladin Analyzer.

              25-03-2017 - Added cast ratios statistic.

            Created by Zerotorescue for the
            #holy Discord. You can usually find helpful people there.

        </form>

    );
  }
}

export default ReportSelecter;
<|endoftext|>


<commit_before>window.timeObj = {
  year: 29993,
  month: 12,
  day: 30,
  hour: 23,
  minute: 59,
  second: 55,
};

// time handle
var time = document.getElementById('time');
var front = document.createElement('canvas');
var frontCtx = front.getContext('2d');
var back = document.createElement('canvas');
var backCtx = back.getContext('2d');
var ratio = window.devicePixelRatio || 1;
var color = '#666;';
time.appendChild(back);
time.appendChild(front);
front.width = back.width = time.offsetWidth * ratio;
front.height = back.height = time.offsetHeight * ratio;
frontCtx.strokeStyle = color;
frontCtx.lineCap = 'round';
frontCtx.lineJoin = 'round';

var textWid = 36 * ratio;
var fontSize = 28 * ratio;
var numWidth = 20 * ratio;
var numHeight = 30 * ratio;
var lineWidth = 4 * ratio;
var halfTextWid = textWid / 2;
var halfFontSize = fontSize / 2;
var halfNumWidth = numWidth / 2;
var halfNumHeight = numHeight / 2;
var y = back.height / 2;
backCtx.textAlign = 'center';
backCtx.textBaseline = 'middle';
backCtx.font = fontSize + 'px sans-serif, "黑体"';

var ready = false;
var cache = {};

var ch = ['年', '月', '日', '时', '分', '秒'];
var keys = Object.keys(window.timeObj);
var timeMap = {
  0: '1110111', // |-|_ |_|
  1: '1000100',
  2: '0111110',
  3: '0111011',
  4: '1011001',
  5: '1101011',
  6: '1101111',
  7: '0110001',
  8: '1111111',
  9: '1111011',
};

function formatTime(n) {
  n = String(n);
  return n.length === 1 ? '0' + n : n;
}

// auto increment time
function updateTime() {
  var date = new Date();
  var latestDay = new Date(
    date.getFullYear(),
    date.getMonth() + 1,
    0
  ).getDate();

  // calculate time
  var up = [0, 12, latestDay, 24, 60, 60];
  while (up.length) {
    var index = up.length - 1;
    var upper = up.pop();
    var key = keys[index];
    if (++window.timeObj[key] >= upper && upper) {
      window.timeObj[key] = index >= 3 ? 0 : 1;
    } else {
      break;
    }
  }

  drawText(window.timeObj);
}

function Line(pos1, pos2) {
  this.pos1 = pos1;
  this.pos2 = pos2;
  this.times = 20;
  this.value = '0';
  this.ppos = {
    x: (pos2.x - pos1.x) / this.times,
    y: (pos2.y - pos1.y) / this.times,
  };

  this.start = pos1;
  this.end = pos1;
  this.direction = false;

  this.movingPos = null;
  this.goalPos = null;
  this.addPos = null;
}

var lp = Line.prototype;
lp.update = function() {
  if (this.movingPos && this.goalPos) {
    this.updateToGoal();
  }

  if (
    !this.equal(this.start, this.end) ||
    (this.movingPos && !this.equal(this.movingPos, this.goalPos))
  ) {
    frontCtx.moveTo(this.start.x, this.start.y);
    frontCtx.lineTo(this.end.x, this.end.y);
  }
};

lp.updateToGoal = function() {
  if (this.movingPos.x !== this.goalPos.x) {
    this.movingPos.x += this.addPos.x;
    if (Math.abs(this.movingPos.x - this.goalPos.x) < 0.1) {
      this.movingPos.x = this.goalPos.x;
    }
  }

  if (this.movingPos.y !== this.goalPos.y) {
    this.movingPos.y += this.addPos.y;
    if (Math.abs(this.movingPos.y - this.goalPos.y) < 0.1) {
      this.movingPos.y = this.goalPos.y;
    }
  }
};

lp.equal = function(pos1, pos2) {
  return pos1.x === pos2.x && pos1.y === pos2.y;
};

lp.move = function(type) {
  var newPos1 = { x: this.pos1.x, y: this.pos1.y };
  var newPos2 = { x: this.pos2.x, y: this.pos2.y };
  if (type === 1) {
    this.start = this.pos1;
    this.movingPos = this.end = newPos1;
    this.goalPos = newPos2;
    this.addPos = { x: this.ppos.x, y: this.ppos.y };
  } else if (type === 2) {
    this.start = this.pos1;
    this.movingPos = this.end = newPos2;
    this.goalPos = newPos1;
    this.addPos = { x: -this.ppos.x, y: -this.ppos.y };
  } else if (type === 3) {
    this.end = this.pos2;
    this.movingPos = this.start = newPos2;
    this.goalPos = newPos1;
    this.addPos = { x: -this.ppos.x, y: -this.ppos.y };
  } else {
    this.end = this.pos2;
    this.movingPos = this.start = newPos1;
    this.goalPos = newPos2;
    this.addPos = { x: this.ppos.x, y: this.ppos.y };
  }
};

function readyForDraw(timeObj, startIndex) {
  backCtx.clearRect(0, 0, back.width, back.height);
  backCtx.lineWidth = frontCtx.lineWidth = lineWidth;
  backCtx.fillStyle = color;

  var startX = 0;
  var a = halfTextWid - halfNumWidth;
  var b = halfTextWid + halfNumWidth;
  var c = y - halfNumHeight;
  var d = y + halfNumHeight;

  ch.forEach(function(text, index) {
    if (index < startIndex) {
      return;
    }

    var num = timeObj[keys[index]];
    var numStr = formatTime(num);
    for (var j = 0; j < numStr.length; j++) {
      var val = numStr[j];
      var map = timeMap[+val];
      var e = startX + a;
      var f = startX + b;
      var coors = [
        { x: e, y: y }, // left-mid
        { x: e, y: c }, // left-top
        { x: f, y: c }, // right-top
        { x: f, y: y }, // right-mid
        { x: e, y: y }, // left-mid
        { x: e, y: d }, // left-bottom
        { x: f, y: d }, // right-bottom
        { x: f, y: y }, // right-mid
      ];

      var cc = (cache[text + '_' + j] = []);
      backCtx.beginPath();
      backCtx.moveTo(coors[0].x, coors[0].y);

      for (var k = 1; k < coors.length; k++) {
        backCtx.lineTo(coors[k].x, coors[k].y);
        cc.push(new Line(coors[k - 1], coors[k]));
      }

      backCtx.strokeStyle = '#eee';
      backCtx.stroke();
      startX += textWid;
    }

    backCtx.fillText(text, startX + halfTextWid, y);
    startX += textWid;
  });
}

var latestIndex = 0;
var startIndex = 0;
function drawText(timeObj) {
  for (let i = 0; i < keys.length; i++) {
    if (timeObj[keys[i]]) {
      startIndex = i;
      break;
    }
  }

  if (!ready || startIndex !== latestIndex) {
    readyForDraw(timeObj, startIndex);
    ready = true;
  }

  latestIndex = startIndex;
  ch.forEach(function(text, index) {
    var num = timeObj[keys[index]];
    var numStr = formatTime(num);

    for (var j = 0; j < numStr.length; j++) {
      var cc = cache[text + '_' + j];
      if (!cc) {
        continue;
      }

      var val = numStr[j];
      var map = timeMap[+val];
      for (var k = 0; k < map.length; k++) {
        var val = map[k];
        var line = cc[k];
        if (line.value === val) {
          continue;
        }

        line.value = val;
        if (val === '1') {
          if (cc[k + 1] && cc[k + 1].value === '1') {
            // 1 -> 2
            line.move(3);
          } else {
            // 1 <- 2
            line.move(1);
          }
        } else {
          if (cc[k + 1] && cc[k + 1].value === '1') {
            // 1 -> 2
            line.move(2);
          } else {
            // 1 <- 2
            line.move(4);
          }
        }
      }
    }
  });
}

var time = 0;
function animate() {
  frontCtx.clearRect(0, 0, front.width, front.height);

  frontCtx.beginPath();
  Object.keys(cache).forEach(key => {
    cache[key].forEach(function(line) {
      line.update();
    });
  });
  frontCtx.stroke();

  var newTime = Date.now();
  if (newTime - time >= 1000) {
    updateTime();
    time = newTime;
  }

  RAF(animate);
}

window.RAF = (function() {
  return (
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 1000 / 60);
    }
  );
})();

// start animate
animate();
<commit_msg>feat: update animate<commit_after>window.timeObj = {
  year: 29993,
  month: 12,
  day: 30,
  hour: 23,
  minute: 59,
  second: 55,
};

// time handle
var time = document.getElementById('time');
var front = document.createElement('canvas');
var frontCtx = front.getContext('2d');
var back = document.createElement('canvas');
var backCtx = back.getContext('2d');
var ratio = window.devicePixelRatio || 1;
var color = '#666;';
time.appendChild(back);
time.appendChild(front);
front.width = back.width = time.offsetWidth * ratio;
front.height = back.height = time.offsetHeight * ratio;
frontCtx.strokeStyle = color;
frontCtx.lineCap = 'round';
frontCtx.lineJoin = 'round';

var textWid = 36 * ratio;
var fontSize = 28 * ratio;
var numWidth = 20 * ratio;
var numHeight = 30 * ratio;
var lineWidth = 4 * ratio;
var halfTextWid = textWid / 2;
var halfFontSize = fontSize / 2;
var halfNumWidth = numWidth / 2;
var halfNumHeight = numHeight / 2;
var y = back.height / 2;
backCtx.textAlign = 'center';
backCtx.textBaseline = 'middle';
backCtx.font = fontSize + 'px sans-serif, "黑体"';

var ready = false;
var cache = {};

var ch = ['年', '月', '日', '时', '分', '秒'];
var keys = Object.keys(window.timeObj);
var timeMap = {
  0: '1110111', // |-|_ |_|
  1: '0010001',
  2: '0111110',
  3: '0111011',
  4: '1011001',
  5: '1101011',
  6: '1101111',
  7: '0110001',
  8: '1111111',
  9: '1111011',
};

function formatTime(n) {
  n = String(n);
  return n.length === 1 ? '0' + n : n;
}

// auto increment time
function updateTime() {
  var date = new Date();
  var latestDay = new Date(
    date.getFullYear(),
    date.getMonth() + 1,
    0
  ).getDate();

  // calculate time
  var up = [0, 12, latestDay, 24, 60, 60];
  while (up.length) {
    var index = up.length - 1;
    var upper = up.pop();
    var key = keys[index];
    if (++window.timeObj[key] >= upper && upper) {
      window.timeObj[key] = index >= 3 ? 0 : 1;
    } else {
      break;
    }
  }

  drawText(window.timeObj);
}

function Line(pos1, pos2) {
  this.pos1 = pos1;
  this.pos2 = pos2;
  this.value = '0';

  this.start = pos1;
  this.end = pos1;
  this.direction = false;

  this.movingPos = null;
  this.goalPos = null;
  this.addPos = null;
}

var lp = Line.prototype;
lp.update = function() {
  if (this.movingPos && this.goalPos) {
    this.updateToGoal();
  }

  if (
    !this.equal(this.start, this.end) ||
    (this.movingPos && !this.equal(this.movingPos, this.goalPos))
  ) {
    frontCtx.moveTo(this.start.x, this.start.y);
    frontCtx.lineTo(this.end.x, this.end.y);
  }
};

lp.updateToGoal = function() {
  if (this.movingPos.x !== this.goalPos.x) {
    this.movingPos.x += this.addPos.x;
    if (Math.abs(this.movingPos.x - this.goalPos.x) <= 0.1) {
      this.movingPos.x = this.goalPos.x;
    }
  }

  if (this.movingPos.y !== this.goalPos.y) {
    this.movingPos.y += this.addPos.y;
    if (Math.abs(this.movingPos.y - this.goalPos.y) <= 0.1) {
      this.movingPos.y = this.goalPos.y;
    }
  }
};

lp.equal = function(pos1, pos2) {
  return pos1.x === pos2.x && pos1.y === pos2.y;
};

lp.move = function(type) {
  var newPos1 = { x: this.pos1.x, y: this.pos1.y };
  var newPos2 = { x: this.pos2.x, y: this.pos2.y };
  if (type === 1) {
    this.start = this.pos1;
    this.movingPos = this.end = newPos1;
    this.goalPos = newPos2;
  } else if (type === 2) {
    this.start = this.pos1;
    this.movingPos = this.end = newPos2;
    this.goalPos = newPos1;
  } else if (type === 3) {
    this.end = this.pos2;
    this.movingPos = this.start = newPos2;
    this.goalPos = newPos1;
  } else {
    this.end = this.pos2;
    this.movingPos = this.start = newPos1;
    this.goalPos = newPos2;
  }

  this.addPos = {
    x: (this.goalPos.x - this.movingPos.x) / 26,
    y: (this.goalPos.y - this.movingPos.y) / 26,
  };
};

function readyForDraw(timeObj, startIndex) {
  backCtx.clearRect(0, 0, back.width, back.height);
  backCtx.lineWidth = frontCtx.lineWidth = lineWidth;
  backCtx.fillStyle = color;

  var startX = 0;
  var a = halfTextWid - halfNumWidth;
  var b = halfTextWid + halfNumWidth;
  var c = y - halfNumHeight;
  var d = y + halfNumHeight;

  ch.forEach(function(text, index) {
    if (index < startIndex) {
      return;
    }

    var num = timeObj[keys[index]];
    var numStr = formatTime(num);
    for (var j = 0; j < numStr.length; j++) {
      var val = numStr[j];
      var map = timeMap[+val];
      var e = startX + a;
      var f = startX + b;
      var coors = [
        { x: e, y: y }, // left-mid
        { x: e, y: c }, // left-top
        { x: f, y: c }, // right-top
        { x: f, y: y }, // right-mid
        { x: e, y: y }, // left-mid
        { x: e, y: d }, // left-bottom
        { x: f, y: d }, // right-bottom
        { x: f, y: y }, // right-mid
      ];

      var cc = (cache[text + '_' + j] = []);
      backCtx.beginPath();
      backCtx.moveTo(coors[0].x, coors[0].y);

      for (var k = 1; k < coors.length; k++) {
        backCtx.lineTo(coors[k].x, coors[k].y);
        cc.push(new Line(coors[k - 1], coors[k]));
      }

      backCtx.strokeStyle = '#eee';
      backCtx.stroke();
      startX += textWid;
    }

    backCtx.fillText(text, startX + halfTextWid, y);
    startX += textWid;
  });
}

var latestIndex = 0;
var startIndex = 0;
function drawText(timeObj) {
  for (let i = 0; i < keys.length; i++) {
    if (timeObj[keys[i]]) {
      startIndex = i;
      break;
    }
  }

  if (!ready || startIndex !== latestIndex) {
    readyForDraw(timeObj, startIndex);
    ready = true;
  }

  latestIndex = startIndex;
  ch.forEach(function(text, index) {
    var num = timeObj[keys[index]];
    var numStr = formatTime(num);

    for (var j = 0; j < numStr.length; j++) {
      var cc = cache[text + '_' + j];
      if (!cc) {
        continue;
      }

      var val = numStr[j];
      var map = timeMap[+val];
      for (var k = 0; k < map.length; k++) {
        var val = map[k];
        var line = cc[k];
        if (line.value === val) {
          continue;
        }

        line.value = val;
        if (val === '1') {
          if (cc[k + 1] && cc[k + 1].value === '1') {
            // 1 -> 2
            line.move(3);
          } else {
            // 1 <- 2
            line.move(1);
          }
        } else {
          if (cc[k + 1] && cc[k + 1].value === '1') {
            // 1 -> 2
            line.move(4);
          } else {
            // 1 <- 2
            line.move(2);
          }
        }
      }
    }
  });
}

var time = 0;
function animate() {
  frontCtx.clearRect(0, 0, front.width, front.height);

  frontCtx.beginPath();
  Object.keys(cache).forEach(key => {
    cache[key].forEach(function(line) {
      line.update();
    });
  });
  frontCtx.stroke();

  var newTime = Date.now();
  if (newTime - time >= 1000) {
    updateTime();
    time = newTime;
  }

  RAF(animate);
}

window.RAF = (function() {
  return (
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 1000 / 60);
    }
  );
})();

// start animate
animate();
<|endoftext|>


<commit_before>EZ3.ASTROIDAL_ELLIPSOID = function(xRadius, yRadius, zRadius, stacks, slices) {

  this.slices = slices;
  this.stacks = stacks;
  this.xRadius = xRadius;
  this.yRadius = yRadius;
  this.zRadius = zRadius;

  this.uv = [];
  this.indices = [];
  this.normals = [];
  this.vertices = [];

  this.PI = Math.PI;
  this.HALF_PI = this.PI / 2;
  this.DOUBLE_PI = 2.0 * this.PI;

  this.create();

};

EZ3.ASTROIDAL_ELLIPSOID.prototype.create = function() {

  var s, t, cosS, cosT, sinS, sinT, phi, rho, u, v, normal, vertex, S, T;

  vertex = vec3.create();
  normal = vec3.create();

  S = 1.0 / (this.slices - 1);
  T = 1.0 / (this.stacks - 1);

  for(s = 0; s < this.slices; ++s) {
    for(t = 0; t < this.stacks; ++t) {

      u = s * S;
      v = t * T;

      phi = this.DOUBLE_PI * u - this.PI;
      rho = this.PI * v - this.HALF_PI;

      cosS = Math.pow(Math.cos(phi), 3.0);
      cosT = Math.pow(Math.cos(rho), 3.0);
      sinS = Math.pow(Math.sin(phi), 3.0);
      sinT = Math.pow(Math.sin(rho), 3.0);

      vertex[0] = (this.xRadius * cosT * cosS);
      vertex[1] = (this.yRadius * sinT);
      vertex[2] = (this.zRadius * cosT * sinS);

      normal[0] = vertex[0] / this.xRadius;
      normal[1] = vertex[1] / this.yRadius;
      normal[2] = vertex[2] / this.zRadius;

      vec3.normalize(normal, normal);

      this.uv.push(u);
      this.uv.push(v);

      this.normals.push(normal[0]);
      this.normals.push(normal[1]);
      this.normals.push(normal[2]);

      this.vertices.push(vertex[0]);
      this.vertices.push(vertex[1]);
      this.vertices.push(vertex[2]);

    }
  }

  for(s = 0; s < this.slices - 1; ++s) {
    for(t = 0; t < this.stacks - 1; ++t) {

      this.indices.push((s + 0) * this.stacks + (t + 0));
      this.indices.push((s + 0) * this.stacks + (t + 1));
      this.indices.push((s + 1) * this.stacks + (t + 1));

      this.indices.push((s + 0) * this.stacks + (t + 0));
      this.indices.push((s + 1) * this.stacks + (t + 1));
      this.indices.push((s + 1) * this.stacks + (t + 0));

    }
  }

};
<commit_msg>Updated astroidal-ellipsoid.js<commit_after>EZ3.ASTROIDAL_ELLIPSOID = function(radiusx, radiusy, radiusz, stacks, slices) {

  this._slices = slices;
  this._stacks = stacks;
  this._radiusx = radiusx;
  this._radiusy = radiusy;
  this._radiusz = radiusz;

  this.uv = [];
  this.indices = [];
  this.normals = [];
  this.vertices = [];

  this.PI = Math.PI;
  this.HALF_PI = this.PI / 2;
  this.DOUBLE_PI = 2.0 * this.PI;

  this.create();

};

EZ3.ASTROIDAL_ELLIPSOID.prototype.create = function() {

  var s, t, cosS, cosT, sinS, sinT, phi, rho, u, v, normal, vertex, S, T;

  vertex = vec3.create();
  normal = vec3.create();

  S = 1.0 / (this._slices - 1);
  T = 1.0 / (this._stacks - 1);

  for(s = 0; s < this._slices; ++s) {
    for(t = 0; t < this._stacks; ++t) {

      u = s * S;
      v = t * T;

      phi = this.DOUBLE_PI * u - this.PI;
      rho = this.PI * v - this.HALF_PI;

      cosS = Math.pow(Math.cos(phi), 3.0);
      cosT = Math.pow(Math.cos(rho), 3.0);
      sinS = Math.pow(Math.sin(phi), 3.0);
      sinT = Math.pow(Math.sin(rho), 3.0);

      vertex[0] = (this._radiusx * cosT * cosS);
      vertex[1] = (this._radiusy * sinT);
      vertex[2] = (this._radiusz * cosT * sinS);

      normal[0] = vertex[0] / this._xradius;
      normal[1] = vertex[1] / this._yradius;
      normal[2] = vertex[2] / this._zradius;

      vec3.normalize(normal, normal);

      this.uv.push(u);
      this.uv.push(v);

      this.normals.push(normal[0]);
      this.normals.push(normal[1]);
      this.normals.push(normal[2]);

      this.vertices.push(vertex[0]);
      this.vertices.push(vertex[1]);
      this.vertices.push(vertex[2]);

    }
  }

  for(s = 0; s < this._slices - 1; ++s) {
    for(t = 0; t < this._stacks - 1; ++t) {

      this.indices.push((s + 0) * this._stacks + (t + 0));
      this.indices.push((s + 0) * this._stacks + (t + 1));
      this.indices.push((s + 1) * this._stacks + (t + 1));

      this.indices.push((s + 0) * this._stacks + (t + 0));
      this.indices.push((s + 1) * this._stacks + (t + 1));
      this.indices.push((s + 1) * this._stacks + (t + 0));

    }
  }
};
<|endoftext|>


<commit_before><commit_msg>updated html5 symlink<commit_after><|endoftext|>


<commit_before>(function() {
  var colors = {
    'ORANGE': {
      colour: 'rgb(255,144,47)',
      secondary_colour: ['LIGHT BLUE', 'DARK BLUE'],
      index: 8
    },
    'LIGHT BLUE': {
      colour: 'rgb(51,151,197)',
      secondary_colour: ['YELLOW', 'RED'],
      index: 4
    },
    'DARK BLUE': {
      colour: 'rgb(59,54,182)',
      secondary_colour: ['ORANGE', 'YELLOW'],
      index: 3
    },
    'GREEN': {
      colour: 'rgb(83,119,48)',
      secondary_colour: ['PINK', 'PURPLE'],
      index: 5
    },
    'YELLOW': {
      colour: 'rgb(219,217,37)',
      secondary_colour: ['LIGHT BLUE', 'PURPLE'],
      index: 6
    },
    'BLACK': {
      colour: 'rgb(25,25,25)',
      secondary_colour: ['ORANGE', 'PINK', 'LIGHT BLUE', 'GREEN', 'RED'],
      index: 10
    },
    'PINK': {
      colour: 'rgb(206,51,122)',
      secondary_colour: ['LIGHT BLUE', 'ORANGE'],
      index: 1
    },
    'WHITE': {
      colour: 'rgb(200,200,200)',
      secondary_colour: ['PINK', 'LIGHT BLUE', 'ORANGE', 'RED', 'GREEN'],
      index: 9
    },
    'BROWN': {
      colour: 'rgb(142,107,68)',
      secondary_colour: ['DARK BLUE', 'PINK'],
      index: 7
    },
    'PURPLE': {
      colour: 'rgb(113,52,165)',
      secondary_colour: ['YELLOW', 'GREEN'],
      index: 2
    },
    'RED': {
      colour: 'rgb(210,50,44)',
      secondary_colour: ['GREEN', 'LIGHT BLUE'],
      index: 0
    }
  };
  var colorNames = Object.keys(colors)

  var parseRgb = function(string) {
    return string.replace('rgb(', '').replace(')', '').split(',').map(function(s) {return parseInt(s, 10)})
  }

  var componentFromHue = function(m1, m2, h) {
    h = ((h % 1) + 1) % 1;
    if (h*6 < 1) {
      return m1 + (m2-m1) * h*6;
    }
    if (h*2 < 1) {
      return m2;
    }
    if (h*3 < 2) {
      return m1 + (m2-m1) * (2/3 - h) * 6;
    }
    return m1;
  }

  var rgbFromHsl = function(h, s, l) {
    var m2;
    if (l < 0.5) {
      m2 = l * (s+1);
    } else {
      m2 = l + s - l*s;
    }
    var m1 = l*2 - m2;
    return {
      r: componentFromHue(m1, m2, h + 1/3),
      g: componentFromHue(m1, m2, h),
      b: componentFromHue(m1, m2, h - 1/3)
    };
  }

  var hslFromRgb = function(r, g, b) {
    var m = Math.min(r, g, b)
    var M = Math.max(r, g, b)
    var l = (M+m)/2
    var c = M - m
    var s
    if (l <= 0.0) {
      s = 0
    } else if (l <= 0.5) {
      s = c/(2*l)
    } else {
      s = c/(2 - 2*l)
    }
    var h = 0
    if (c == 0) {
      h = 0
    } else if (M == r) {
      h = ((g - b) / c)
    } else if (M == g) {
      h = ((b - r) / c) + 2
    } else if (M == b) {
      h = ((r - g) / c) + 4
    }
    h = ((h/6) + 1) % 1;

    return {
      h: h,
      s: s,
      l: l
    }
  }

  function hueReplace(el, primary, secondary) {
    primary = hslFromRgb(primary[0]/255, primary[1]/255, primary[2]/255)
    secondary = hslFromRgb(secondary[0]/255, secondary[1]/255, secondary[2]/255)
    var canvas = document.createElement("canvas");
    //canvas.width = el.naturalWidth
    //canvas.height = el.naturalHeight
    canvas.width = el.offsetWidth
    canvas.height = el.offsetHeight

    var ctx = canvas.getContext("2d");
    ctx.drawImage(el, 0, 0, canvas.width, canvas.height);

    var map = ctx.getImageData(0, 0, canvas.width, canvas.height)
    var data = map.data;

    var r, g, b
    var hsl, rgb
    var hues = {}
    for(var i = 0, len = data.length;i < len;i += 4) {
      r = data[i]/255
      g = data[i+1]/255
      b = data[i+2]/255
      // alpha channel (p+3) is ignored

      hsl = hslFromRgb(r, g, b)
      if (hsl.h > 0.50 && hsl.h < 0.70) {
        hues[hsl.h] = (hues[hsl.h] || 0) + 1
        if (i % 1000 == 0) {
          console.log('primary', r*255, g*255, b*255, hsl)
        }
        hsl.h = primary.h
        if (hsl.s > 0.1) {
          hsl.s = primary.s
        }
      } else if (hsl.h > 0.05 && hsl.h < 0.18) {
        hues[hsl.h] = (hues[hsl.h] || 0) + 1
        if (i % 1000 == 0) {
          console.log('secondary', r*255, g*255, b*255, hsl)
        }
        hsl.h = secondary.h
        if (hsl.s > 0.1) {
          hsl.s = secondary.s
        }
      }
      rgb = rgbFromHsl(hsl.h, hsl.s, hsl.l)
      if (i % 1000 == 0) {
        //console.log(r, g, b, hsl, rgb)
      }

      data[i] = rgb.r*255
      data[i+1] = rgb.g*255
      data[i+2] = rgb.b*255
      //data[i] = hsl.l*255
      //data[i+1] = hsl.l*255
      //data[i+2] = hsl.l*255
    }

    ctx.putImageData(map,0,0);

    el.src = canvas.toDataURL();
    console.log(hues)
  }

  var baseBlue = [58, 119, 174]
  var baseYellow = [255, 200, 2]

  var $commander = $('[data-bind="visible: true, attr: {src: commanderImg}"]')
  var colorize = function() {
    var main = colors[colorNames[Math.floor(Math.random() * 11)]]
    var primary = parseRgb(main.colour)
    var choices = main.secondary_colour
    var secondary = parseRgb(colors[choices[Math.floor(Math.random() * choices.length)]].colour)

    $commander.off('load', colorize)
    hueReplace(
      $commander[0],
      primary
      ,
      secondary
    );
    //setTimeout(colorize, 1000)
  }
  $commander.on('load', colorize)

  window.rgbFromHsl = rgbFromHsl
  window.hslFromRgb = hslFromRgb
})()
<commit_msg>ability to cycle colors<commit_after>(function() {
  var colors = {
    'ORANGE': {
      colour: 'rgb(255,144,47)',
      secondary_colour: ['LIGHT BLUE', 'DARK BLUE'],
      index: 8
    },
    'LIGHT BLUE': {
      colour: 'rgb(51,151,197)',
      secondary_colour: ['YELLOW', 'RED'],
      index: 4
    },
    'DARK BLUE': {
      colour: 'rgb(59,54,182)',
      secondary_colour: ['ORANGE', 'YELLOW'],
      index: 3
    },
    'GREEN': {
      colour: 'rgb(83,119,48)',
      secondary_colour: ['PINK', 'PURPLE'],
      index: 5
    },
    'YELLOW': {
      colour: 'rgb(219,217,37)',
      secondary_colour: ['LIGHT BLUE', 'PURPLE'],
      index: 6
    },
    'BLACK': {
      colour: 'rgb(25,25,25)',
      secondary_colour: ['ORANGE', 'PINK', 'LIGHT BLUE', 'GREEN', 'RED'],
      index: 10
    },
    'PINK': {
      colour: 'rgb(206,51,122)',
      secondary_colour: ['LIGHT BLUE', 'ORANGE'],
      index: 1
    },
    'WHITE': {
      colour: 'rgb(200,200,200)',
      secondary_colour: ['PINK', 'LIGHT BLUE', 'ORANGE', 'RED', 'GREEN'],
      index: 9
    },
    'BROWN': {
      colour: 'rgb(142,107,68)',
      secondary_colour: ['DARK BLUE', 'PINK'],
      index: 7
    },
    'PURPLE': {
      colour: 'rgb(113,52,165)',
      secondary_colour: ['YELLOW', 'GREEN'],
      index: 2
    },
    'RED': {
      colour: 'rgb(210,50,44)',
      secondary_colour: ['GREEN', 'LIGHT BLUE'],
      index: 0
    }
  };
  var colorNames = Object.keys(colors)

  var parseRgb = function(string) {
    return string.replace('rgb(', '').replace(')', '').split(',').map(function(s) {return parseInt(s, 10)})
  }

  var componentFromHue = function(m1, m2, h) {
    h = ((h % 1) + 1) % 1;
    if (h*6 < 1) {
      return m1 + (m2-m1) * h*6;
    }
    if (h*2 < 1) {
      return m2;
    }
    if (h*3 < 2) {
      return m1 + (m2-m1) * (2/3 - h) * 6;
    }
    return m1;
  }

  var rgbFromHsl = function(h, s, l) {
    var m2;
    if (l < 0.5) {
      m2 = l * (s+1);
    } else {
      m2 = l + s - l*s;
    }
    var m1 = l*2 - m2;
    return {
      r: componentFromHue(m1, m2, h + 1/3),
      g: componentFromHue(m1, m2, h),
      b: componentFromHue(m1, m2, h - 1/3)
    };
  }

  var hslFromRgb = function(r, g, b) {
    var m = Math.min(r, g, b)
    var M = Math.max(r, g, b)
    var l = (M+m)/2
    var c = M - m
    var s
    if (l <= 0.0) {
      s = 0
    } else if (l <= 0.5) {
      s = c/(2*l)
    } else {
      s = c/(2 - 2*l)
    }
    var h = 0
    if (c == 0) {
      h = 0
    } else if (M == r) {
      h = ((g - b) / c)
    } else if (M == g) {
      h = ((b - r) / c) + 2
    } else if (M == b) {
      h = ((r - g) / c) + 4
    }
    h = ((h/6) + 1) % 1;

    return {
      h: h,
      s: s,
      l: l
    }
  }

  function hueReplace(from, to, primary, secondary) {
    primary = hslFromRgb(primary[0]/255, primary[1]/255, primary[2]/255)
    secondary = hslFromRgb(secondary[0]/255, secondary[1]/255, secondary[2]/255)
    var canvas = document.createElement("canvas");
    //canvas.width = from.naturalWidth
    //canvas.height = from.naturalHeight
    canvas.width = from.offsetWidth
    canvas.height = from.offsetHeight

    var ctx = canvas.getContext("2d");
    ctx.drawImage(from, 0, 0, canvas.width, canvas.height);

    var map = ctx.getImageData(0, 0, canvas.width, canvas.height)
    var data = map.data;

    var r, g, b
    var hsl, rgb
    var hues = {}
    for(var i = 0, len = data.length;i < len;i += 4) {
      r = data[i]/255
      g = data[i+1]/255
      b = data[i+2]/255
      // alpha channel (p+3) is ignored

      hsl = hslFromRgb(r, g, b)
      if (hsl.h > 0.50 && hsl.h < 0.70) {
        hues[hsl.h] = (hues[hsl.h] || 0) + 1
        if (i % 1000 == 0) {
          console.log('primary', r*255, g*255, b*255, hsl)
        }
        hsl.h = primary.h
        if (hsl.s > 0.1) {
          hsl.s = primary.s
        }
      } else if (hsl.h > 0.05 && hsl.h < 0.18) {
        hues[hsl.h] = (hues[hsl.h] || 0) + 1
        if (i % 1000 == 0) {
          console.log('secondary', r*255, g*255, b*255, hsl)
        }
        hsl.h = secondary.h
        if (hsl.s > 0.1) {
          hsl.s = secondary.s
        }
      }
      rgb = rgbFromHsl(hsl.h, hsl.s, hsl.l)
      if (i % 1000 == 0) {
        //console.log(r, g, b, hsl, rgb)
      }

      data[i] = rgb.r*255
      data[i+1] = rgb.g*255
      data[i+2] = rgb.b*255
      //data[i] = hsl.l*255
      //data[i+1] = hsl.l*255
      //data[i+2] = hsl.l*255
    }

    ctx.putImageData(map,0,0);

    to.src = canvas.toDataURL();
    console.log(hues)
  }

  var baseBlue = [58, 119, 174]
  var baseYellow = [255, 200, 2]

  var $commander = $('[data-bind="visible: true, attr: {src: commanderImg}"]')
  var $clone = $commander.clone()
  $commander.hide()
  $commander.after($clone)
  var colorize = function() {
    var main = colors[colorNames[Math.floor(Math.random() * 11)]]
    var primary = parseRgb(main.colour)
    var choices = main.secondary_colour
    var secondary = parseRgb(colors[choices[Math.floor(Math.random() * choices.length)]].colour)

    $commander.off('load', colorize)
    var canvas = hueReplace(
      $commander[0],
      $clone[0],
      primary
      ,
      secondary
    );
    //setTimeout(colorize, 1000)
  }
  $commander.on('load', colorize)

  window.rgbFromHsl = rgbFromHsl
  window.hslFromRgb = hslFromRgb
})()
<|endoftext|>


<commit_before>import h from 'react-hyperscript'
import PropTypes from 'prop-types'
import { compose } from 'recompose'
import { connect as connectStyles } from 'react-fela'
import { isNil, not, and, either, isEmpty } from 'ramda'
import MuiAvatar from 'material-ui/Avatar'
import FontIcon from 'material-ui/FontIcon'

import styles from '../styles/ProfileIcon'

// (mw) these values are _arbitrary_!
// TODO make them more legit
const sizeInPx = {
  small: 40,
  medium: 60,
  large: 80
}

export default compose(
  connectStyles(styles)
)(Avatar)

function Avatar (props) {
  const {
    styles,
    agent,
    size,
    icon,
    dirtyAvatar = ''
  } = props

  const hasDirtyAvatar = not(isEmpty(dirtyAvatar))

  const hasIcon = not(isNil(icon))

  if (isNil(agent)) return null

  const { profile } = agent

  if (isNil(profile)) return null

  const { name, avatar } = profile

  const hasName = not(isNil(name))
  const hasAvatar = not(isNil(avatar))

  const shouldDisplayIcon = and(not(hasAvatar), not(hasDirtyAvatar), not(hasName), hasIcon)

  const src = hasDirtyAvatar ? dirtyAvatar : hasAvatar ? avatar : null

  return (
    h('div', {
      className: styles.container
    }, [
      h(MuiAvatar, {
        className: styles.avatar,
        size: sizeInPx[size],
        icon: (
          shouldDisplayIcon
            ? h(FontIcon, {
                className: `fa fa-${icon}`
              })
            : null
        ),
        src: src
      }, [
        and(not(hasAvatar), hasName)
          ? name.substring(0, 1)
          : null
      ])
    ])
  )
}

Avatar.propTypes = {
  avatar: PropTypes.string,
  size: PropTypes.oneOf(['small', 'medium', 'large'])
}

Avatar.defaultProps = {
  size: 'small'
}
<commit_msg>bugfix(avatar): fixed conditions governing display of icon and of initial<commit_after>import h from 'react-hyperscript'
import PropTypes from 'prop-types'
import { compose } from 'recompose'
import { connect as connectStyles } from 'react-fela'
import { isNil, not, and, either, isEmpty, all } from 'ramda'
import MuiAvatar from 'material-ui/Avatar'
import FontIcon from 'material-ui/FontIcon'

import styles from '../styles/ProfileIcon'

// (mw) these values are _arbitrary_!
// TODO make them more legit
const sizeInPx = {
  small: 40,
  medium: 60,
  large: 80
}

export default compose(
  connectStyles(styles)
)(Avatar)

function Avatar (props) {
  const {
    styles,
    agent,
    size,
    icon,
    dirtyAvatar = ''
  } = props

  const hasDirtyAvatar = not(isEmpty(dirtyAvatar))

  const hasIcon = not(isNil(icon))

  if (isNil(agent)) return null

  const { profile } = agent

  if (isNil(profile)) return null

  const { name, avatar } = profile

  const hasName = not(isNil(name))
  const hasAvatar = not(isNil(avatar))

  const shouldDisplayIcon = and(and(not(hasAvatar), not(hasDirtyAvatar)), and(not(hasName), hasIcon))

  const src = hasDirtyAvatar ? dirtyAvatar : hasAvatar ? avatar : null

  return (
    h('div', {
      className: styles.container
    }, [
      h(MuiAvatar, {
        className: styles.avatar,
        size: sizeInPx[size],
        icon: (
          shouldDisplayIcon
            ? h(FontIcon, {
                className: `fa fa-${icon}`
              })
            : null
        ),
        src: src
      }, [
        and(and(not(hasAvatar), not(hasDirtyAvatar)), hasName)
          ? name.substring(0, 1)
          : null
      ])
    ])
  )
}

Avatar.propTypes = {
  avatar: PropTypes.string,
  size: PropTypes.oneOf(['small', 'medium', 'large'])
}

Avatar.defaultProps = {
  size: 'small'
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';

const DEFAULT_LENGTH = 50;
const DEFAULT_SUFFIX = '…';

export const truncate = (text, length = DEFAULT_LENGTH, suffix = DEFAULT_SUFFIX) =>
  text.substr(0, length - 1) + (text.length > length ? suffix : '');

const Truncate = ({
  children, length, suffix, ...rest
}) => (
  <span {...rest}>
    {truncate(children, length, suffix)}
  </span>
);

Truncate.propTypes = {
  children: PropTypes.node.isRequired,
  length: PropTypes.number,
  suffix: PropTypes.string,
};

Truncate.defaultProps = {
  length: DEFAULT_LENGTH,
  suffix: DEFAULT_SUFFIX,
};

export default Truncate;
<commit_msg>Defensive Truncate<commit_after>import React from 'react';
import PropTypes from 'prop-types';

const DEFAULT_LENGTH = 50;
const DEFAULT_SUFFIX = '…';

export const truncate = (text, length = DEFAULT_LENGTH, suffix = DEFAULT_SUFFIX) =>
  text && text.substr(0, length - 1) + (text.length > length ? suffix : '');

const Truncate = ({
  children, length, suffix, ...rest
}) => (
  <span {...rest}>
    {truncate(children, length, suffix)}
  </span>
);

Truncate.propTypes = {
  children: PropTypes.node.isRequired,
  length: PropTypes.number,
  suffix: PropTypes.string,
};

Truncate.defaultProps = {
  length: DEFAULT_LENGTH,
  suffix: DEFAULT_SUFFIX,
};

export default Truncate;
<|endoftext|>