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

  angular.module('app.components')
    .controller('MyProfileController', MyProfileController);

    MyProfileController.$inject = ['$scope', '$location', 'userData', 'kitsData', 'AuthUser', 'user', 'auth', 'utils', 'alert', 'COUNTRY_CODES', '$timeout', 'file', 'PROFILE_TOOLS', 'animation', 'DROPDOWN_OPTIONS_KIT', '$mdDialog'];
    function MyProfileController($scope, $location, userData, kitsData, AuthUser, user, auth, utils, alert, COUNTRY_CODES, $timeout, file, PROFILE_TOOLS, animation, DROPDOWN_OPTIONS_KIT, $mdDialog) {
      var vm = this;

      vm.highlightIcon = highlightIcon;
      vm.unhighlightIcon = unhighlightIcon;

      //PROFILE TAB
      vm.formUser = {};
      vm.getCountries = getCountries;

      vm.user = userData;
      copyUserToForm(vm.formUser, vm.user);
      vm.searchText = vm.formUser.country;

      vm.updateUser = updateUser;
      vm.removeUser = removeUser;
      vm.uploadAvatar = uploadAvatar;

      //KITS TAB
      vm.kits = kitsData;
      vm.kitStatus = undefined;
      vm.filteredKits = [];

      vm.dropdownSelected = undefined;
      vm.dropdownOptions = DROPDOWN_OPTIONS_KIT;

      //TOOLS TAB
      vm.tools = PROFILE_TOOLS;
      vm.toolType = undefined;
      vm.filteredTools = [];

      //SIDEBAR
      vm.filterKits = filterKits;
      vm.filterTools = filterTools;

      $scope.$on('loggedOut', function() {
        $location.path('/');
      });

      initialize();

      //////////////////

      function initialize() {
        $timeout(function() {
          highlightIcon(0);
          setSidebarMinHeight();
          animation.viewLoaded();
        }, 500);
      }

      function filterKits(status) {
        if(status === 'all') {
          status = undefined;
        }
        vm.kitStatus = status;
      }

      function filterTools(type) {
        if(type === 'all') {
          type = undefined;
        }
        vm.toolType = type;
      }

      function updateUser(userData) {
        if(userData.country) {
          _.each(COUNTRY_CODES, function(value, key) {
            if(value === userData.country) {
              /*jshint camelcase: false */
              userData.country_code = key;
              return;
            }
          });
        }

        user.updateUser(userData)
          .then(function(data) {
            var user = new AuthUser(data);
            _.extend(vm.user, user);
            vm.errors = {};
            alert.success('User updated');
          })
          .catch(function(err) {
            alert.error('User could not be updated ');
            vm.errors = err.data.errors;
          });
      }

      function removeUser() {
        var alert = $mdDialog.alert()
          .title('Delete your account?')
          .content('If you wish to remove you account completely, please contact our support team at support@smartcitizen.me')
          .ariaLabel('')
          .ok('OK!')
          .theme('primary')
          .clickOutsideToClose(true);

        $mdDialog.show(alert);
      }

      function highlightIcon(iconIndex) {
        var icons = angular.element('.myProfile_tab_icon');

        _.each(icons, function(icon) {
          unhighlightIcon(icon);
        });

        var icon = icons[iconIndex];

        angular.element(icon).find('.stroke_container').css({'stroke': 'white', 'stroke-width': '0.01px'});
        angular.element(icon).find('.fill_container').css('fill', 'white');

      }

      function unhighlightIcon(icon) {
        icon = angular.element(icon);

        icon.find('.stroke_container').css({'stroke': 'none'});
        icon.find('.fill_container').css('fill', '#82A7B0');
      }

      function setSidebarMinHeight() {
        var height = document.body.clientHeight / 4 * 3;
        angular.element('.profile_content').css('min-height', height + 'px');
      }

      function getCountries(searchText) {
        return _.filter(COUNTRY_CODES, createFilter(searchText));
      }

      function createFilter(searchText) {
        searchText = searchText.toLowerCase();
        return function(country) {
          country = country.toLowerCase();
          return country.indexOf(searchText) !== -1;
        };
      }

      function uploadAvatar(fileData) {
        if(fileData && fileData.length) {
          file.getCredentials(fileData[0].name)
            .then(function(res) {
              file.uploadFile(fileData[0], res.key, res.policy, res.signature)
                .success(function() {
                  vm.user.avatar = file.getImageURL(res.key);
                });
              });
        }
      }

      function copyUserToForm(formData, userData) {
        var props = {username: true, email: true, city: true, country: true, country_code: true, website: true, constructor: false};

        for(var key in userData) {
          if(props[key]) {
            formData[key] = userData[key];
          }
        }
      }
    }
})();
<commit_msg>feat: added polling on profile kit list<commit_after>(function() {
  'use strict';

  angular.module('app.components')
    .controller('MyProfileController', MyProfileController);

    MyProfileController.$inject = ['$scope', '$location', '$q', '$interval', 'userData', 'kitsData', 'AuthUser', 'user', 'auth', 'utils', 'alert', 'COUNTRY_CODES', '$timeout', 'file', 'PROFILE_TOOLS', 'animation', 'DROPDOWN_OPTIONS_KIT', '$mdDialog', 'PreviewKit', 'device'];
    function MyProfileController($scope, $location, $q, $interval, userData, kitsData, AuthUser, user, auth, utils, alert, COUNTRY_CODES, $timeout, file, PROFILE_TOOLS, animation, DROPDOWN_OPTIONS_KIT, $mdDialog, PreviewKit, device) {
      var vm = this;

      vm.highlightIcon = highlightIcon;
      vm.unhighlightIcon = unhighlightIcon;

      //PROFILE TAB
      vm.formUser = {};
      vm.getCountries = getCountries;

      vm.user = userData;
      copyUserToForm(vm.formUser, vm.user);
      vm.searchText = vm.formUser.country;

      vm.updateUser = updateUser;
      vm.removeUser = removeUser;
      vm.uploadAvatar = uploadAvatar;

      //KITS TAB
      vm.kits = kitsData;
      vm.kitStatus = undefined;
      vm.filteredKits = [];

      vm.dropdownSelected = undefined;
      vm.dropdownOptions = DROPDOWN_OPTIONS_KIT;

      //TOOLS TAB
      vm.tools = PROFILE_TOOLS;
      vm.toolType = undefined;
      vm.filteredTools = [];

      //SIDEBAR
      vm.filterKits = filterKits;
      vm.filterTools = filterTools;

      var updateKitsTimer = undefined;

      $scope.$on('loggedOut', function() {
        $location.path('/');
      });
      $scope.$on("$destroy", function() {
        if (updateKitsTimer) {
            $interval.cancel(updateKitsTimer);
        }
    });

      initialize();

      //////////////////

      function initialize() {
        $timeout(function() {
          highlightIcon(0);
          setSidebarMinHeight();
          animation.viewLoaded();
        }, 500);

        updateKitsTimer = $interval(updateKits, 4000);
      }

      function filterKits(status) {
        if(status === 'all') {
          status = undefined;
        }
        vm.kitStatus = status;
      }

      function filterTools(type) {
        if(type === 'all') {
          type = undefined;
        }
        vm.toolType = type;
      }

      function updateUser(userData) {
        if(userData.country) {
          _.each(COUNTRY_CODES, function(value, key) {
            if(value === userData.country) {
              /*jshint camelcase: false */
              userData.country_code = key;
              return;
            }
          });
        }

        user.updateUser(userData)
          .then(function(data) {
            var user = new AuthUser(data);
            _.extend(vm.user, user);
            vm.errors = {};
            alert.success('User updated');
          })
          .catch(function(err) {
            alert.error('User could not be updated ');
            vm.errors = err.data.errors;
          });
      }

      function removeUser() {
        var alert = $mdDialog.alert()
          .title('Delete your account?')
          .content('If you wish to remove you account completely, please contact our support team at support@smartcitizen.me')
          .ariaLabel('')
          .ok('OK!')
          .theme('primary')
          .clickOutsideToClose(true);

        $mdDialog.show(alert);
      }

      function highlightIcon(iconIndex) {
        var icons = angular.element('.myProfile_tab_icon');

        _.each(icons, function(icon) {
          unhighlightIcon(icon);
        });

        var icon = icons[iconIndex];

        angular.element(icon).find('.stroke_container').css({'stroke': 'white', 'stroke-width': '0.01px'});
        angular.element(icon).find('.fill_container').css('fill', 'white');

      }

      function unhighlightIcon(icon) {
        icon = angular.element(icon);

        icon.find('.stroke_container').css({'stroke': 'none'});
        icon.find('.fill_container').css('fill', '#82A7B0');
      }

      function setSidebarMinHeight() {
        var height = document.body.clientHeight / 4 * 3;
        angular.element('.profile_content').css('min-height', height + 'px');
      }

      function getCountries(searchText) {
        return _.filter(COUNTRY_CODES, createFilter(searchText));
      }

      function createFilter(searchText) {
        searchText = searchText.toLowerCase();
        return function(country) {
          country = country.toLowerCase();
          return country.indexOf(searchText) !== -1;
        };
      }

      function uploadAvatar(fileData) {
        if(fileData && fileData.length) {
          file.getCredentials(fileData[0].name)
            .then(function(res) {
              file.uploadFile(fileData[0], res.key, res.policy, res.signature)
                .success(function() {
                  vm.user.avatar = file.getImageURL(res.key);
                });
              });
        }
      }

      function copyUserToForm(formData, userData) {
        var props = {username: true, email: true, city: true, country: true, country_code: true, website: true, constructor: false};

        for(var key in userData) {
          if(props[key]) {
            formData[key] = userData[key];
          }
        }
      }

      function updateKits() {
        var kitIDs = _.pluck(vm.user.kits, 'id');
        if(!kitIDs.length) {
          return [];
        }

        $q.all(
          kitIDs.map(function(id) {
            return device.getDevice(id)
              .then(function(data) {
                return new PreviewKit(data);
              });
          })
        )
        .then(function(data){
          vm.kits = data;
        });
      }
    }
})();
<|endoftext|>


<commit_before>var URL = require("url"),
	http = require("http"),
	https = require("https"),
	fs = require("fs"),
	cp = require("child_process"),
	fc = require("./fetcher.common.js"),
	harel = require("./fetcher.harel.js");

var cUrl = 6,
	cNum = 4,
	cBody = 3;

var bodys = {
	"אחר": "other",
	"מגדל": "migdal",
	"מנורה": "menora",
	"פניקס": "fenix",
	"כלל": "clal",
	"דש איפקס": "dash",
	"הראל": "harel",
	"אנליסט": "analyst",
	"אלטשולר": "altshuler",
	"איילון": "ayalon",
	"אי.בי.אי": "IBI",
	"אקסלנס": "xnes",
	"אינפיניטי": "infinity",
	"הלמן": "helman",
	"ארגון המורים העל יסודיים": "highschools_teachers",
	"הסתדרות המורים בישראל": "teachers",
	"דיסקונט": "discount",
	"אקדמאים במדעי החברה": "havera_acdemics",
	"ביוכימאים": "biochemists" ,
	"הסוכנות היהודית": "hasochnut"
};

var parseBody = function(body) {
	for (var k in bodys) {
		if (body.indexOf(k) != -1) {
			return bodys[k];
		}
	}

	return null;
};

/* Read & parse files_data.csv file */
var readFundsFile = function() {

	var parsedLines = require('fs').readFileSync('files_data.csv').toString().split("\n");

	var funds = [];

	var columnsCount = parsedLines[0].split(',').length;

	for (var i = 1; i < parsedLines.length; ++i) {
		var splt = parsedLines[i].split(',');

		if (splt.length != columnsCount) {
			continue;
		}

		var url = splt[cUrl].trim();
		if (url !== '') {
			var body = splt[cBody];

			var englishBody = parseBody(body);

			if (englishBody === null) {
				console.log("Unknwon body: ", body);
			} else {
				funds.push({
					body: englishBody,
					number: splt[cNum],
					url: url
				});
			}
		}
	}

	return funds;
};

var doFetch = function(step, funds, seed) {
	if (seed < funds.length) {
		var fund = funds[seed];
		var next = doFetch.bind(this, step, funds, seed+step);
		switch (fund.body) {
			case "harel":
				harel.fetchOne(fund, next);
			break;
			default:
				fc.fetchFund(fund, next);
		}
	}
};

/* Fetch all funds */
exports.fetchAll = function(funds) {
	if (funds === undefined) {
		funds = readFundsFile();
	}

	var step = 5;
	for(var i = 0; i < Math.min(funds.length, step); ++i) {
		doFetch(step, funds, i);
	}
};

exports.fetchHarel = function() {
	var allFunds = readFundsFile();

	var funds = [];

	for(var i = 0; i < allFunds.length; ++i) {
		var fund = allFunds[i];
		if (fund.body == "harel") {
			funds.push(fund);
		}
	}

	exports.fetchAll(funds);
	// var outFile = fs.createWriteStream("test.csv");

	// var count = funds.length;
	// var handleDone = function(fund, fundFiles) {
	// 	console.log("Writing fund", fund.number, "files");
	// 	for (var i = 0; i < fundFiles.length; ++i) {
	// 		var file = fundFiles[i];
	// 		outFile.write([fund.number, file.year, file. q, file.url].join(',') + "\n");
	// 	}

	// 	if (--count === 0) {
	// 		console.log("All funds fetched.");
	// 		outFile.end();
	// 	}
	// };

	// for (i = 0; i < funds.length; ++i) {
	// 	harel.fetchOne(funds[i], handleDone);
	// }
};
<commit_msg>Fetcher: increase step to 8 from 5(i.e. the number of fetches to run in parallel).<commit_after>var URL = require("url"),
	http = require("http"),
	https = require("https"),
	fs = require("fs"),
	cp = require("child_process"),
	fc = require("./fetcher.common.js"),
	harel = require("./fetcher.harel.js");

var cUrl = 6,
	cNum = 4,
	cBody = 3;

var bodys = {
	"אחר": "other",
	"מגדל": "migdal",
	"מנורה": "menora",
	"פניקס": "fenix",
	"כלל": "clal",
	"דש איפקס": "dash",
	"הראל": "harel",
	"אנליסט": "analyst",
	"אלטשולר": "altshuler",
	"איילון": "ayalon",
	"אי.בי.אי": "IBI",
	"אקסלנס": "xnes",
	"אינפיניטי": "infinity",
	"הלמן": "helman",
	"ארגון המורים העל יסודיים": "highschools_teachers",
	"הסתדרות המורים בישראל": "teachers",
	"דיסקונט": "discount",
	"אקדמאים במדעי החברה": "havera_acdemics",
	"ביוכימאים": "biochemists" ,
	"הסוכנות היהודית": "hasochnut"
};

var parseBody = function(body) {
	for (var k in bodys) {
		if (body.indexOf(k) != -1) {
			return bodys[k];
		}
	}

	return null;
};

/* Read & parse files_data.csv file */
var readFundsFile = function() {

	var parsedLines = require('fs').readFileSync('files_data.csv').toString().split("\n");

	var funds = [];

	var columnsCount = parsedLines[0].split(',').length;

	for (var i = 1; i < parsedLines.length; ++i) {
		var splt = parsedLines[i].split(',');

		if (splt.length != columnsCount) {
			continue;
		}

		var url = splt[cUrl].trim();
		if (url !== '') {
			var body = splt[cBody];

			var englishBody = parseBody(body);

			if (englishBody === null) {
				console.log("Unknwon body: ", body);
			} else {
				funds.push({
					body: englishBody,
					number: splt[cNum],
					url: url
				});
			}
		}
	}

	return funds;
};

var doFetch = function(step, funds, seed) {
	if (seed < funds.length) {
		var fund = funds[seed];
		var next = doFetch.bind(this, step, funds, seed+step);
		switch (fund.body) {
			case "harel":
				harel.fetchOne(fund, next);
			break;
			default:
				fc.fetchFund(fund, next);
		}
	}
};

/* Fetch all funds */
exports.fetchAll = function(funds) {
	if (funds === undefined) {
		funds = readFundsFile();
	}

	var step = 8;
	for(var i = 0; i < Math.min(funds.length, step); ++i) {
		doFetch(step, funds, i);
	}
};

exports.fetchHarel = function() {
	var allFunds = readFundsFile();

	var funds = [];

	for(var i = 0; i < allFunds.length; ++i) {
		var fund = allFunds[i];
		if (fund.body == "harel") {
			funds.push(fund);
		}
	}

	exports.fetchAll(funds);
	// var outFile = fs.createWriteStream("test.csv");

	// var count = funds.length;
	// var handleDone = function(fund, fundFiles) {
	// 	console.log("Writing fund", fund.number, "files");
	// 	for (var i = 0; i < fundFiles.length; ++i) {
	// 		var file = fundFiles[i];
	// 		outFile.write([fund.number, file.year, file. q, file.url].join(',') + "\n");
	// 	}

	// 	if (--count === 0) {
	// 		console.log("All funds fetched.");
	// 		outFile.end();
	// 	}
	// };

	// for (i = 0; i < funds.length; ++i) {
	// 	harel.fetchOne(funds[i], handleDone);
	// }
};
<|endoftext|>


<commit_before>/*
* BrainBrowser: Web-based Neurological Visualization Tools
* (https://brainbrowser.cbrain.mcgill.ca)
*
* Copyright (C) 2011-2014
* The Royal Institution for the Advancement of Learning
* McGill University
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
* Author: Robert D. Vincent <robert.d.vincent@mcgill.ca>
*
* Loads MGH (FreeSurfer) files for volume viewer. For details on the MGH
* format, see https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat
*
* Here are some of the salient features of the format:
* 1. A fixed-size binary header similar to NIfTI-1.
* 2. Generally stored big-endian, even on little-endian systems.
* 3. At most 4 dimensions, of which three are spatial.
* 4. MGZ files are just MGH files that have been run through GZIP/ZLIB.
* 5. Encodes a single transform, but uses a confusing dual notion of what
* the origin of the world axis is. In some cases, the centre of the voxel
* grid is used as the world origin, in others an offset is
* applied to each of the spatial dimensions.
* 6. There is no scaling information in the header. Voxel values are not
* transformed in any way.
*/

(function() {
  "use strict";

  var VolumeViewer = BrainBrowser.VolumeViewer;
  var debug = false;

  VolumeViewer.volume_loaders.mgh = function(description, callback) {
    var error_message;
    if (description.url) {
      BrainBrowser.loader.loadFromURL(description.url, function(data) {
        parseMGHHeader(data, function(header) {
          createMGHVolume(header, data, callback);
        });
      }, {result_type: "arraybuffer" });

    } else if (description.file) {
      BrainBrowser.loader.loadFromFile(description.file, function(data) {
        parseMGHHeader(data, function(header) {
          createMGHVolume(header, data, callback);
        });
      }, {result_type: "arraybuffer" });
    } else {
      error_message = "invalid volume description.\n" +
        "Description must contain the property 'url' or 'file'.";

      BrainBrowser.events.triggerEvent("error", { message: error_message });
      throw new Error(error_message);
    }

  };

  /* Function to parse the basic MGH header. This is a 284-byte binary
   * object that begins at offset zero in the file.
   * The resulting header object will contain the following fields:
   *
   * header.order[] - An array of strings that gives the order of the
   * spatial dimensions.
   * header.xspace - Description of the X axis (patient left to right)
   * header.yspace - Description of the Y axis (patient posterior to anterior)
   * header.zspace - Description of the Z axis (patient inferior to superior)
   * header.time - Description of time axis, if any.

   * Non-standard fields used internally only:
   *
   * header.nvoxels - Total number of voxels in the image.
   * header.datatype - MGH data type of image.
   * header.little_endian - True if data is little endian (should be false!)
   */
  function parseMGHHeader(raw_data, callback) {
    var header = {
      order: ["xspace", "yspace", "zspace"],
      xspace: {},
      yspace: {},
      zspace: {}
    };
    var error_message;
    var dview = new DataView(raw_data, 0, 284);
    var little_endian = true;

    /* Read the header version, which should always have the value
     * 0x00000001. We use this to test the endian-ness of the data,
     * but it should always be big-endian.
     */
    var hdr_version = dview.getUint32(0, true);
    if (hdr_version === 0x00000001) {
      little_endian = true;
    } else if (hdr_version === 0x01000000) {
      little_endian = false;    // Generally files are big-endian.
    }
    else {
      error_message = "This does not look like an MGH file.";
    }

    /* Now read the dimension lengths. There are at most 4 dimensions
     * in the file. The lengths fields are always present, but they
     * unused dimensions may have the value 0 or 1.
     */
    var ndims = 0;
    var sizes = [0, 0, 0, 0];
    var header_offset = 4;
    var nvoxels = 1;
    for (ndims = 0; ndims < 4; ndims++) {
      sizes[ndims] = dview.getUint32(header_offset, little_endian);
      if (sizes[ndims] <= 1) {
        break;
      }
      nvoxels *= sizes[ndims];
      header_offset += 4;
    }

    if (ndims < 3 || ndims > 4) {
      error_message = "Cannot handle " + ndims + "-dimensional images yet.";
    }

    var datatype = dview.getUint32(20, little_endian);
    // IGNORED var dof = dview.getUint32(24, little_endian);
    var good_transform_flag = dview.getUint16(28, little_endian);
    var spacing = [1.0, 1.0, 1.0];
    var i, j;
    var dircos = [
      [-1.0,  0.0,  0.0],
      [ 0.0,  0.0, -1.0],
      [ 0.0,  1.0,  0.0],
      [ 0.0,  0.0,  0.0]
    ];
    if (good_transform_flag) {
      header_offset = 30;
      for (i = 0; i < 3; i++) {
        spacing[i] = dview.getFloat32(header_offset, little_endian);
        header_offset += 4;
      }
      for (i = 0; i < 4; i++) {
        for (j = 0; j < 3; j++) {
          dircos[i][j] = dview.getFloat32(header_offset, little_endian);
          header_offset += 4;
        }
      }
    }

    if (debug) {
      // Prints out the transform in a format similar to the output
      // of FreeSurfer's mri_info tool.
      //
      for (i = 0; i < 3; i++) {
        var s1 = "";
        for (j = 0; j < 4; j++) {
          s1 += "xyzc"[j] + "_" + "ras"[i] + " " + dircos[j][i] + " ";
        }
        console.log(s1);
      }
    }

    var axis_index_from_file = [0, 1, 2];

    for ( var axis = 0; axis < 3; axis++) {
      var spatial_axis = 0;
      var c_x = Math.abs(dircos[axis][0]);
      var c_y = Math.abs(dircos[axis][1]);
      var c_z = Math.abs(dircos[axis][2]);

      header.order[axis] = "xspace";
      if (c_y > c_x && c_y > c_z) {
        spatial_axis = 1;
        header.order[axis] = "yspace";
      }
      if (c_z > c_x && c_z > c_y) {
        spatial_axis = 2;
        header.order[axis] = "zspace";
      }
      axis_index_from_file[axis] = spatial_axis;
    }

    /* If there are four dimensions, assume the last is the time
     * dimension. I use default values for step and start because as
     * far as I know MGH files do not carry any descriptive
     * information about the 4th dimension.
     */
    if (ndims === 4) {
      if (debug) {
        console.log("Creating time dimension: " + sizes[3]);
      }
      header.time = {
        space_length: sizes[3],
        step: 1,
        start: 0,
        name: "time"
      };
      header.order.push("time");
    }

    /** This is here because there are two different ways of interpreting
      * the origin of an MGH file. One can ignore the offsets in the
      * transform, using the centre of the voxel grid. Or you can correct
      * these naive grid centres using the values stored in the transform.
      * The first approach is what is used by surface files, so to get them
      * to register nicely, we want ignore_offsets to be true. However,
      * getting volumetric files to register correctly implies setting
      * ignore_offsets to false.
      */
    var ignore_offsets = false;
    var mgh_xform = [
      [0, 0, 0, 0],
      [0, 0, 0, 0],
      [0, 0, 0, 0]
    ];
    for (i = 0; i < 3; i++) {
      for (j = 0; j < 3; j++) {
        mgh_xform[i][j] = dircos[j][i] * spacing[i];
      }
    }

    for (i = 0; i < 3; i++) {
      var temp = 0.0;
      for (j = 0; j < 3; j++) {
        temp += mgh_xform[i][j] * (sizes[j] / 2.0);
      }

      if (ignore_offsets) {
        mgh_xform[i][4 - 1] = -temp;
      }
      else {
        mgh_xform[i][4 - 1] = dircos[4 - 1][i] - temp;
      }
    }

    var transform = [
      [0, 0, 0, 0],
      [0, 0, 0, 0],
      [0, 0, 0, 0],
      [0, 0, 0, 0]
    ];

    for (i = 0; i < 3; i++) {
      for (j = 0; j < 4; j++) {
        var volume_axis = j;
        if (j < 3) {
          volume_axis = axis_index_from_file[j];
        }
        transform[i][volume_axis] = mgh_xform[i][j];
      }
    }

    // Now that we have the transform, need to convert it to MINC-like
    // steps and direction_cosines.

    VolumeViewer.utils.transformToMinc(transform, header);

    if (error_message !== undefined) {
      BrainBrowser.events.triggerEvent("error", { message: error_message });
      throw new Error(error_message);
    }

    // Save the datatype so that we can refer to it later.
    header.datatype = datatype;
    header.little_endian = little_endian;
    header.nvoxels = nvoxels;

    // Save the voxel dimension lengths.
    for (i = 0; i < 3; i++) {
      header[header.order[i]].space_length = sizes[i];
    }

    if (BrainBrowser.utils.isFunction(callback)) {
      callback(header);
    }
  }

  function createMGHVolume(header, raw_data, callback) {
    var volume = VolumeViewer.createVolume(header,
                                           createMGHData(header, raw_data));
    volume.type = "mgh";
    volume.saveOriginAndTransform(header);
    if (BrainBrowser.utils.isFunction(callback)) {
      callback(volume);
    }
  }

  function createMGHData(header, raw_data) {
    var byte_data = null;
    var native_data = null;
    var n_min, n_max;
    var bytes_per_voxel = 1;

    switch (header.datatype) {
    case 0:                     // Unsigned characters.
      bytes_per_voxel = 1;
      break;
    case 1:                     // 4-byte signed integers.
    case 3:                     // 4-byte float.
      bytes_per_voxel = 4;
      break;
    case 4:                     // 2-byte signed integers.
      bytes_per_voxel = 2;
      break;
    default:
      var error_message = "Unsupported data type: " + header.datatype;
      BrainBrowser.events.triggerEvent("error", { message: error_message });
      throw new Error(error_message);
    }

    var nbytes = header.nvoxels * bytes_per_voxel;

    if (bytes_per_voxel > 1 && !header.little_endian) {
      VolumeViewer.utils.swapn(new Uint8Array(raw_data, 284, nbytes),
                               bytes_per_voxel);
    }

    switch (header.datatype) {
    case 0:                     // unsigned char
      native_data = new Uint8Array(raw_data, 284, header.nvoxels);
      break;
    case 1:                     // signed int
      native_data = new Int32Array(raw_data, 284, header.nvoxels);
      break;
    case 3:
      native_data = new Float32Array(raw_data, 284, header.nvoxels);
      break;
    case 4:                     // signed short
      native_data = new Int16Array(raw_data, 284, header.nvoxels);
      break;
    }

    var d = 0;                  // Generic loop counter.

    // Convert raw data to bytes.
    byte_data = new Uint8Array(native_data.length);
    n_min = native_data[0];
    n_max = native_data[0];

    for (d = 1; d < native_data.length; d++) {
      if (native_data[d] > n_max)
        n_max = native_data[d];
      if (native_data[d] < n_min)
        n_min = native_data[d];
    }
    for (d = 0; d < native_data.length; d++) {
      byte_data[d] = ((native_data[d] + n_min) * 255) / (n_max - n_min);
    }

    // Incrementation offsets for each dimension of the volume. MGH
    // files store the fastest-varying dimension _first_, so the
    // "first" dimension actually has the smallest offset. That is
    // why this calculation is different from that for NIfTI-1.
    //
    var offset = 1;
    for (d = 0; d < header.order.length; d++) {
      header[header.order[d]].offset = offset;
      offset *= header[header.order[d]].space_length;
    }
    return byte_data;
  }

}());
<commit_msg>Fix a few minor issues to bring the MGH reader up to date with the master branch.<commit_after>/*
* BrainBrowser: Web-based Neurological Visualization Tools
* (https://brainbrowser.cbrain.mcgill.ca)
*
* Copyright (C) 2011-2014
* The Royal Institution for the Advancement of Learning
* McGill University
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
* Author: Robert D. Vincent <robert.d.vincent@mcgill.ca>
*
* Loads MGH (FreeSurfer) files for volume viewer. For details on the MGH
* format, see https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat
*
* Here are some of the salient features of the format:
* 1. A fixed-size binary header similar to NIfTI-1.
* 2. Generally stored big-endian, even on little-endian systems.
* 3. At most 4 dimensions, of which three are spatial.
* 4. MGZ files are just MGH files that have been run through GZIP/ZLIB.
* 5. Encodes a single transform, but uses a confusing dual notion of what
* the origin of the world axis is. In some cases, the centre of the voxel
* grid is used as the world origin, in others an offset is
* applied to each of the spatial dimensions.
* 6. There is no scaling information in the header. Voxel values are not
* transformed in any way.
*/

(function() {
  "use strict";

  var VolumeViewer = BrainBrowser.VolumeViewer;
  var debug = false;

  VolumeViewer.volume_loaders.mgh = function(description, callback) {
    var error_message;
    if (description.url) {
      BrainBrowser.loader.loadFromURL(description.url, function(data) {
        parseMGHHeader(data, function(header) {
          createMGHVolume(header, data, callback);
        });
      }, {result_type: "arraybuffer" });

    } else if (description.file) {
      BrainBrowser.loader.loadFromFile(description.file, function(data) {
        parseMGHHeader(data, function(header) {
          createMGHVolume(header, data, callback);
        });
      }, {result_type: "arraybuffer" });
    } else {
      error_message = "invalid volume description.\n" +
        "Description must contain the property 'url' or 'file'.";

      BrainBrowser.events.triggerEvent("error", { message: error_message });
      throw new Error(error_message);
    }

  };

  /* Function to parse the basic MGH header. This is a 284-byte binary
   * object that begins at offset zero in the file.
   * The resulting header object will contain the following fields:
   *
   * header.order[] - An array of strings that gives the order of the
   * spatial dimensions.
   * header.xspace - Description of the X axis (patient left to right)
   * header.yspace - Description of the Y axis (patient posterior to anterior)
   * header.zspace - Description of the Z axis (patient inferior to superior)
   * header.time - Description of time axis, if any.

   * Non-standard fields used internally only:
   *
   * header.nvoxels - Total number of voxels in the image.
   * header.datatype - MGH data type of image.
   * header.little_endian - True if data is little endian (should be false!)
   */
  function parseMGHHeader(raw_data, callback) {
    var header = {
      order: ["xspace", "yspace", "zspace"],
      xspace: {},
      yspace: {},
      zspace: {}
    };
    var error_message;
    var dview = new DataView(raw_data, 0, 284);
    var little_endian = true;

    /* Read the header version, which should always have the value
     * 0x00000001. We use this to test the endian-ness of the data,
     * but it should always be big-endian.
     */
    var hdr_version = dview.getUint32(0, true);
    if (hdr_version === 0x00000001) {
      little_endian = true;
    } else if (hdr_version === 0x01000000) {
      little_endian = false;    // Generally files are big-endian.
    }
    else {
      error_message = "This does not look like an MGH file.";
    }

    /* Now read the dimension lengths. There are at most 4 dimensions
     * in the file. The lengths fields are always present, but they
     * unused dimensions may have the value 0 or 1.
     */
    var ndims = 0;
    var sizes = [0, 0, 0, 0];
    var header_offset = 4;
    var nvoxels = 1;
    for (ndims = 0; ndims < 4; ndims++) {
      sizes[ndims] = dview.getUint32(header_offset, little_endian);
      if (sizes[ndims] <= 1) {
        break;
      }
      nvoxels *= sizes[ndims];
      header_offset += 4;
    }

    if (ndims < 3 || ndims > 4) {
      error_message = "Cannot handle " + ndims + "-dimensional images yet.";
    }

    var datatype = dview.getUint32(20, little_endian);
    // IGNORED var dof = dview.getUint32(24, little_endian);
    var good_transform_flag = dview.getUint16(28, little_endian);
    var spacing = [1.0, 1.0, 1.0];
    var i, j;
    var dircos = [
      [-1.0,  0.0,  0.0],
      [ 0.0,  0.0, -1.0],
      [ 0.0,  1.0,  0.0],
      [ 0.0,  0.0,  0.0]
    ];
    if (good_transform_flag) {
      header_offset = 30;
      for (i = 0; i < 3; i++) {
        spacing[i] = dview.getFloat32(header_offset, little_endian);
        header_offset += 4;
      }
      for (i = 0; i < 4; i++) {
        for (j = 0; j < 3; j++) {
          dircos[i][j] = dview.getFloat32(header_offset, little_endian);
          header_offset += 4;
        }
      }
    }

    if (debug) {
      // Prints out the transform in a format similar to the output
      // of FreeSurfer's mri_info tool.
      //
      for (i = 0; i < 3; i++) {
        var s1 = "";
        for (j = 0; j < 4; j++) {
          s1 += "xyzc"[j] + "_" + "ras"[i] + " " + dircos[j][i] + " ";
        }
        console.log(s1);
      }
    }

    var axis_index_from_file = [0, 1, 2];

    for ( var axis = 0; axis < 3; axis++) {
      var spatial_axis = 0;
      var c_x = Math.abs(dircos[axis][0]);
      var c_y = Math.abs(dircos[axis][1]);
      var c_z = Math.abs(dircos[axis][2]);

      header.order[axis] = "xspace";
      if (c_y > c_x && c_y > c_z) {
        spatial_axis = 1;
        header.order[axis] = "yspace";
      }
      if (c_z > c_x && c_z > c_y) {
        spatial_axis = 2;
        header.order[axis] = "zspace";
      }
      axis_index_from_file[axis] = spatial_axis;
    }

    /* If there are four dimensions, assume the last is the time
     * dimension. I use default values for step and start because as
     * far as I know MGH files do not carry any descriptive
     * information about the 4th dimension.
     */
    if (ndims === 4) {
      if (debug) {
        console.log("Creating time dimension: " + sizes[3]);
      }
      header.time = {
        space_length: sizes[3],
        step: 1,
        start: 0,
        name: "time"
      };
      header.order.push("time");
    }

    /** This is here because there are two different ways of interpreting
      * the origin of an MGH file. One can ignore the offsets in the
      * transform, using the centre of the voxel grid. Or you can correct
      * these naive grid centres using the values stored in the transform.
      * The first approach is what is used by surface files, so to get them
      * to register nicely, we want ignore_offsets to be true. However,
      * getting volumetric files to register correctly implies setting
      * ignore_offsets to false.
      */
    var ignore_offsets = false;
    var mgh_xform = [
      [0, 0, 0, 0],
      [0, 0, 0, 0],
      [0, 0, 0, 0]
    ];
    for (i = 0; i < 3; i++) {
      for (j = 0; j < 3; j++) {
        mgh_xform[i][j] = dircos[j][i] * spacing[i];
      }
    }

    for (i = 0; i < 3; i++) {
      var temp = 0.0;
      for (j = 0; j < 3; j++) {
        temp += mgh_xform[i][j] * (sizes[j] / 2.0);
      }

      if (ignore_offsets) {
        mgh_xform[i][4 - 1] = -temp;
      }
      else {
        mgh_xform[i][4 - 1] = dircos[4 - 1][i] - temp;
      }
    }

    var transform = [
      [0, 0, 0, 0],
      [0, 0, 0, 0],
      [0, 0, 0, 0],
      [0, 0, 0, 0]
    ];

    for (i = 0; i < 3; i++) {
      for (j = 0; j < 4; j++) {
        var volume_axis = j;
        if (j < 3) {
          volume_axis = axis_index_from_file[j];
        }
        transform[i][volume_axis] = mgh_xform[i][j];
      }
    }

    // Now that we have the transform, need to convert it to MINC-like
    // steps and direction_cosines.

    VolumeViewer.utils.transformToMinc(transform, header);

    if (error_message !== undefined) {
      BrainBrowser.events.triggerEvent("error", { message: error_message });
      throw new Error(error_message);
    }

    // Save the datatype so that we can refer to it later.
    header.datatype = datatype;
    header.little_endian = little_endian;
    header.nvoxels = nvoxels;

    // Save the voxel dimension lengths.
    for (i = 0; i < 3; i++) {
      header[header.order[i]].space_length = sizes[i];
    }

    if (BrainBrowser.utils.isFunction(callback)) {
      callback(header);
    }
  }

  function createMGHVolume(header, raw_data, callback) {
    var volume = VolumeViewer.createVolume(header,
                                           createMGHData(header, raw_data));
    volume.type = "mgh";
    volume.intensity_min = header.voxel_min;
    volume.intensity_max = header.voxel_max;
    volume.saveOriginAndTransform(header);
    if (BrainBrowser.utils.isFunction(callback)) {
      callback(volume);
    }
  }

  function createMGHData(header, raw_data) {
    var native_data = null;
    var bytes_per_voxel = 1;

    switch (header.datatype) {
    case 0:                     // Unsigned characters.
      bytes_per_voxel = 1;
      break;
    case 1:                     // 4-byte signed integers.
    case 3:                     // 4-byte float.
      bytes_per_voxel = 4;
      break;
    case 4:                     // 2-byte signed integers.
      bytes_per_voxel = 2;
      break;
    default:
      var error_message = "Unsupported data type: " + header.datatype;
      BrainBrowser.events.triggerEvent("error", { message: error_message });
      throw new Error(error_message);
    }

    var nbytes = header.nvoxels * bytes_per_voxel;

    if (bytes_per_voxel > 1 && !header.little_endian) {
      VolumeViewer.utils.swapn(new Uint8Array(raw_data, 284, nbytes),
                               bytes_per_voxel);
    }

    switch (header.datatype) {
    case 0:                     // unsigned char
      native_data = new Uint8Array(raw_data, 284, header.nvoxels);
      break;
    case 1:                     // signed int
      native_data = new Int32Array(raw_data, 284, header.nvoxels);
      break;
    case 3:
      native_data = new Float32Array(raw_data, 284, header.nvoxels);
      break;
    case 4:                     // signed short
      native_data = new Int16Array(raw_data, 284, header.nvoxels);
      break;
    }

    var d = 0;                  // Generic loop counter.
    var n_min = +Infinity;
    var n_max = -Infinity;

    for (d = 0; d < native_data.length; d++) {
      if (native_data[d] > n_max)
        n_max = native_data[d];
      if (native_data[d] < n_min)
        n_min = native_data[d];
    }

    header.voxel_min = n_min;
    header.voxel_max = n_max;

    // Incrementation offsets for each dimension of the volume. MGH
    // files store the fastest-varying dimension _first_, so the
    // "first" dimension actually has the smallest offset. That is
    // why this calculation is different from that for NIfTI-1.
    //
    var offset = 1;
    for (d = 0; d < header.order.length; d++) {
      header[header.order[d]].offset = offset;
      offset *= header[header.order[d]].space_length;
    }
    return native_data;
  }

}());
<|endoftext|>


<commit_before>import Emitter from 'helpers/Emitter';
import SoundManager from 'helpers/SoundManager';
import FishGroup from '../FishGroup';

import points from '../Path/paths/path_1.dae';
import createSpline from 'utils/create-spline';
import { loopIndex, degreeToRadian, randomFloat } from 'utils';

import {
  EXP_INTRO_ENDED,
  EXP_RAYCAST_TOGGLE,
  EXP_INTERSECTING_FISH,
  EXP_NOT_INTERSECTING_FISH,
  EXP_SHOW_FISH_NAME,
  EXP_LUX_VALUE_UPDATE,
  EXP_FLASH_MSG
} from 'config/messages';

/**
 * Level class
 */
class Level extends THREE.Object3D {

  /**
   * Constructor function
   * @param {Terrain} Terrain           Terrain instance
   * @param {Camera}  Camera            Camera instance
   * @param {Player}  Player            Player instance
   * @param {Object}  boundingBoxConfig Bounding box configuration
   * @param {Object}  fishGroupConfig   Fish group configuration
   * @param {Object}  resources         Resources
   */
  constructor( Terrain, Camera, Player, boundingBoxConfig, fishGroupConfig, resources ) {

    super();

    this.terrain = Terrain;
    this.camera = Camera;
    this.player = Player;
    this.resources = resources;
    this.fishGroups = [];
    this.fishModels = [];
    this.intersects = [];

    this.curve = createSpline( points );
    this.points = this.curve.getSpacedPoints( 100 );

    this.raycastEnabled = false;
    this.wasIntersecting = false;
    this.isIntersecting = false;

    this.intersectingTimeout = null;
    this.intersectingDebounce = false;

    this.raycaster = new THREE.Raycaster();
    this.mouse = new THREE.Vector2();

    fishGroupConfig.map( config => {
      const fishGroup = new FishGroup( config, this.resources, this.curve );
      this.fishGroups.push( fishGroup );

      const geometry = new THREE.Geometry();
      geometry.vertices = this.points;

      const material = new THREE.LineBasicMaterial({ color: false, transparent: true, opacity: 0 });
      const path = new THREE.Line( geometry, material );
      path.position.copy( config.position );
      path.rotation.y = degreeToRadian( 90 );

      for ( let i = 0; i < fishGroup.fishes.length; i++ ) {
        this.fishModels.push( fishGroup.fishes[ i ].modelObject );
      }

      this.add( path );
      path.add( fishGroup );
    });

    this.add( this.terrain );
    this.add( this.player );

    this.norm = 0;

    this.bind();

    Emitter.once( EXP_INTRO_ENDED , this.onIntroEnded );
    Emitter.once( EXP_RAYCAST_TOGGLE , this.toggleRaycast );

  }

  bind() {

    [ 'update', 'onIntroEnded', 'onClick', 'onMouseMove', 'raycast', 'toggleRaycast' ]
        .forEach( ( fn ) => this[ fn ] = this[ fn ].bind( this ) );
  }

  addEventListeners() {

    document.addEventListener( 'click', this.onClick, false );
    document.addEventListener( 'mousemove', this.onMouseMove, false );
  }

  removeEventListeners() {

    document.removeEventListener( 'click', this.onClick, false );
    document.removeEventListener( 'mousemove', this.onMouseMove, false );
  }

  onIntroEnded() {

    this.raycastEnabled = true;

    this.addEventListeners();
  }

  toggleRaycast( toggle ) {
    this.raycastEnabled = toggle;
  }

  onMouseMove( ev ) {

    this.mouse.x = ( ev.clientX / window.innerWidth ) * 2 - 1;
    this.mouse.y = - ( ev.clientY / window.innerHeight ) * 2 + 1;

  }

  onClick() {

    if( this.intersects.length <= 0 ) return;

    const model = this.intersects[ 0 ].object;
    const fish = model.parent.parent;

    const luxGain = randomFloat( 0.05, 0.1 );

    TweenMax.to( model.scale, 1, { x: 0.001, y: 0.001, z: 0.001, ease: Expo.easeOut, onComplete: () => {

      Emitter.emit( EXP_LUX_VALUE_UPDATE, luxGain );

      Emitter.emit( EXP_FLASH_MSG, 'good', `You win + ${luxGain} lux` );

      model.removeFish( fish );
    } });
  }

  updateWindowCursor() {

    if( this.isIntersecting ) {

      document.body.classList.add( 'is-intersecting' );
    } else {

      document.body.classList.remove( 'is-intersecting' );
    }

  }

  raycast() {

    if( this.raycastEnabled ) {

      this.raycaster.setFromCamera( this.mouse, this.camera );

      // calculate objects intersecting the picking ray
      this.intersects = this.raycaster.intersectObjects( this.fishModels );

      this.wasIntersecting = this.isIntersecting;

      if( this.intersects.length > 0 ) {

        // Check distance
        if( this.intersects[ 0 ].distance < 2000 ) {

          this.isIntersecting = true;

          if( this.wasIntersecting !== this.isIntersecting ) {

            // Debounce later system
            clearTimeout( this.intersectingTimeout );

            this.intersectingTimeout = setTimeout( ()=> {
              this.intersectingDebounce = false;
            }, 300 );

            // Debounce trigger only once per 300ms
            if( !this.intersectingDebounce ) {

              this.intersectingDebounce = true;

              Emitter.emit( EXP_INTERSECTING_FISH, this.intersects[ 0 ] );
              Emitter.emit( EXP_SHOW_FISH_NAME, this.intersects[ 0 ].object.name );

              // Play sound
              SoundManager.play( 'fish-hover' );
            }

          }

        }

      } else {

        this.isIntersecting = false;

        if( this.wasIntersecting !== this.isIntersecting ) {

          Emitter.emit( EXP_NOT_INTERSECTING_FISH );
        }
      }

      this.updateWindowCursor();

    }
  }

  update( time ) {

    this.raycast();

    this.norm = loopIndex( this.norm + 0.001, 1 );

    this.fishGroups.map( group => {
      group.update( time );
    });
  }
}

export default Level;
<commit_msg>Experience - Start fishgoal feature<commit_after>import Emitter from 'helpers/Emitter';
import SoundManager from 'helpers/SoundManager';
import FishGroup from '../FishGroup';

import points from '../Path/paths/path_1.dae';
import createSpline from 'utils/create-spline';
import { loopIndex, degreeToRadian, randomFloat } from 'utils';

import {
  EXP_INTRO_ENDED,
  EXP_RAYCAST_TOGGLE,
  EXP_INTERSECTING_FISH,
  EXP_NOT_INTERSECTING_FISH,
  EXP_SHOW_FISH_NAME,
  EXP_LUX_VALUE_UPDATE,
  EXP_FLASH_MSG
} from 'config/messages';

/**
 * Level class
 */
class Level extends THREE.Object3D {

  /**
   * Constructor function
   * @param {Terrain} Terrain           Terrain instance
   * @param {Camera}  Camera            Camera instance
   * @param {Player}  Player            Player instance
   * @param {Object}  boundingBoxConfig Bounding box configuration
   * @param {Object}  fishGroupConfig   Fish group configuration
   * @param {Object}  resources         Resources
   */
  constructor( Terrain, Camera, Player, boundingBoxConfig, fishGroupConfig, resources ) {

    super();

    this.terrain = Terrain;
    this.camera = Camera;
    this.player = Player;
    this.resources = resources;
    this.fishGroups = [];
    this.fishModels = [];
    this.intersects = [];

    this.fishGoal = 8;

    this.curve = createSpline( points );
    this.points = this.curve.getSpacedPoints( 100 );

    this.raycastEnabled = false;
    this.wasIntersecting = false;
    this.isIntersecting = false;

    this.intersectingTimeout = null;
    this.intersectingDebounce = false;

    this.raycaster = new THREE.Raycaster();
    this.mouse = new THREE.Vector2();

    fishGroupConfig.map( config => {
      const fishGroup = new FishGroup( config, this.resources, this.curve );
      this.fishGroups.push( fishGroup );

      const geometry = new THREE.Geometry();
      geometry.vertices = this.points;

      const material = new THREE.LineBasicMaterial({ color: false, transparent: true, opacity: 0 });
      const path = new THREE.Line( geometry, material );
      path.position.copy( config.position );
      path.rotation.y = degreeToRadian( 90 );

      for ( let i = 0; i < fishGroup.fishes.length; i++ ) {
        this.fishModels.push( fishGroup.fishes[ i ].modelObject );
      }

      this.add( path );
      path.add( fishGroup );
    });

    this.add( this.terrain );
    this.add( this.player );

    this.norm = 0;

    this.bind();

    Emitter.once( EXP_INTRO_ENDED , this.onIntroEnded );
    Emitter.once( EXP_RAYCAST_TOGGLE , this.toggleRaycast );

  }

  bind() {

    [ 'update', 'onIntroEnded', 'onClick', 'onMouseMove', 'raycast', 'toggleRaycast' ]
        .forEach( ( fn ) => this[ fn ] = this[ fn ].bind( this ) );
  }

  addEventListeners() {

    document.addEventListener( 'click', this.onClick, false );
    document.addEventListener( 'mousemove', this.onMouseMove, false );
  }

  removeEventListeners() {

    document.removeEventListener( 'click', this.onClick, false );
    document.removeEventListener( 'mousemove', this.onMouseMove, false );
  }

  onIntroEnded() {

    this.raycastEnabled = true;

    this.addEventListeners();
  }

  toggleRaycast( toggle ) {
    this.raycastEnabled = toggle;
  }

  onMouseMove( ev ) {

    this.mouse.x = ( ev.clientX / window.innerWidth ) * 2 - 1;
    this.mouse.y = - ( ev.clientY / window.innerHeight ) * 2 + 1;

  }

  onClick() {

    if( this.intersects.length <= 0 ) return;

    const model = this.intersects[ 0 ].object;
    const fish = model.parent.parent;

    const luxGain = randomFloat( 0.05, 0.1 );

    TweenMax.to( model.scale, 1, { x: 0.001, y: 0.001, z: 0.001, ease: Expo.easeOut, onComplete: () => {

      Emitter.emit( EXP_LUX_VALUE_UPDATE, luxGain );

      Emitter.emit( EXP_FLASH_MSG, 'good', `You win + ${luxGain} lux` );

      model.removeFish( fish );
    } });
  }

  updateWindowCursorPointer() {

    if( this.isIntersecting ) {

      document.body.classList.add( 'is-intersecting' );
    } else {

      document.body.classList.remove( 'is-intersecting' );
    }

  }

  raycast() {

    if( this.raycastEnabled ) {

      this.raycaster.setFromCamera( this.mouse, this.camera );

      // calculate objects intersecting the picking ray
      this.intersects = this.raycaster.intersectObjects( this.fishModels );

      this.wasIntersecting = this.isIntersecting;

      if( this.intersects.length > 0 ) {

        // Check distance
        if( this.intersects[ 0 ].distance < 2000 ) {

          this.isIntersecting = true;

          if( this.wasIntersecting !== this.isIntersecting ) {

            // Debounce later system
            clearTimeout( this.intersectingTimeout );

            this.intersectingTimeout = setTimeout( ()=> {
              this.intersectingDebounce = false;
            }, 300 );

            // Debounce trigger only once per 300ms
            if( !this.intersectingDebounce ) {

              this.intersectingDebounce = true;

              Emitter.emit( EXP_INTERSECTING_FISH, this.intersects[ 0 ] );
              Emitter.emit( EXP_SHOW_FISH_NAME, this.intersects[ 0 ].object.name );

              // Play sound
              SoundManager.play( 'fish-hover' );
            }

          }

        }

      } else {

        this.isIntersecting = false;

        if( this.wasIntersecting !== this.isIntersecting ) {

          Emitter.emit( EXP_NOT_INTERSECTING_FISH );
        }
      }

      this.updateWindowCursorPointer();

    }
  }

  update( time ) {

    this.raycast();

    this.norm = loopIndex( this.norm + 0.001, 1 );

    this.fishGroups.map( group => {
      group.update( time );
    });
  }
}

export default Level;
<|endoftext|>


<commit_before>import ButtonBackToTop from '../';
const {renderIntoDocument, scryRenderedDOMComponentsWithTag, Simulate} = TestUtils;

describe.only('Select ButtonBackToTop Component', () => {
    describe('Rendering', () => {
        describe('When a default button-back-to-top is rendered', () => {
            let renderedButtonBackToTop, arr;
            before(() => {
                renderedButtonBackToTop = renderIntoDocument(<ButtonBackToTop />);
                renderedButtonBackToTop.setState({isVisible: true})
                arr = scryRenderedDOMComponentsWithTag(renderedButtonBackToTop, 'button');
            });
            it('should have the material button className', () => {
                expect(arr[0].className).to.equal('mdl-button mdl-button--colored mdl-button--fab');
            });
            it('should be a FAB', () => {
                expect(arr[0].attributes.shape.value).to.equal('fab');
            });
        });
    });
});
<commit_msg>Minor update<commit_after>import ButtonBackToTop from '../';
const {renderIntoDocument, scryRenderedDOMComponentsWithTag, Simulate} = TestUtils;

describe('Select ButtonBackToTop Component', () => {
    describe('Rendering', () => {
        describe('When a default button-back-to-top is rendered', () => {
            let renderedButtonBackToTop, arr;
            before(() => {
                renderedButtonBackToTop = renderIntoDocument(<ButtonBackToTop />);
                renderedButtonBackToTop.setState({isVisible: true})
                arr = scryRenderedDOMComponentsWithTag(renderedButtonBackToTop, 'button');
            });
            it('should have the material button className', () => {
                expect(arr[0].className).to.equal('mdl-button mdl-button--colored mdl-button--fab');
            });
            it('should be a FAB', () => {
                expect(arr[0].attributes.shape.value).to.equal('fab');
            });
        });
    });
});
<|endoftext|>


<commit_before>/*  ============================================================================

 Copyright (C) 2006-2016 Talend Inc. - www.talend.com

 This source code is available under agreement available at
 https://github.com/Talend/data-prep/blob/master/LICENSE

 You should have received a copy of the agreement
 along with this program; if not, write to Talend SA
 9 rue Pages 92150 Suresnes, France

 ============================================================================*/

import Pikaday from "./pikaday-override";

/**
 * @ngdoc controller
 * @name talend.sunchoke.date-picker.controller:ScDatePickerCtrl
 * @description Date picker controller
 */
export default class ScDatePickerCtrl {
    constructor($element, $timeout) {
        'ngInject';
        this.$element = $element;
        this.focusState = false;
        this.$timeout = $timeout;
    }

    /**
     * @ngdoc method
     * @name $onInit
     * @methodOf talend.sunchoke.date-picker.controller:ScDatePickerCtrl
     * @description Hook when controller is initialized
     */
    $onInit() {
        //Get the input in the element dom
        const input = this.$element.find('input')[0];
        //date picker container
        const container = this.$element.find('div')[2];

        //Config object for pikaday
        const config = {
            showDaysInNextAndPreviousMonths: true,
            controller: this,
            container: container,
            field: input,
            onClose: this.onCloseHandler,
            positionLeft: this.positionLeft,
            i18n: {
                previousMonth: 'Previous Month',
                nextMonth: 'Next Month',
                months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
                weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
                weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
                none: "None"
            },
            firstDay: 0,
            noneButton: false,
            format: 'MMM D, YYYY'
        };

        //Get all specific configuration
        for (const configKey in this.config) {
            //protect controller & field parameters
            if (configKey !== 'controller' && configKey !== 'field' && container !== 'container') {
                config[configKey] = this.config[configKey];
            }
        }

        this.pikaday = new Pikaday(config);
    }

    /**
     * @ngdoc method
     * @name $onDestroy
     * @methodOf talend.sunchoke.date-picker.controller:ScDatePickerCtrl
     * @description Method called when the controller is destroyed
     */
    $onDestroy() {
        this.pikaday.destroy();
    }

    /**
     * @ngdoc method
     * @name onCloseHandler
     * @methodOf talend.sunchoke.date-picker.controller:ScDatePickerCtrl
     * @description This method is called when datepicker value changed ( onClose )
     */
    onCloseHandler() {

        //if there is a controller
        if (this._o && this._o.controller) {
            //get the controller
            const actualController = this._o.controller;
            //if there is a date
            if (this._d) {

                // if a bad date has been provided
                if (this.textErrorDate) {
                    actualController.ngModel = this.textErrorDate;
                }
                else {
                    //get the date timestamp
                    actualController.ngModel = this._d.getTime();
                }

                //Close only if not init
                if (!this.doNotCloseDp || this.doNotCloseDp === false) {
                    actualController.$timeout(() => {
                        actualController.onCloseFn();
                    });
                }

            }
            //if there is no date, the value may be reset
            else {
                //set null to ngmodel
                actualController.ngModel = null;
            }
        }
    }

    /**
     * @ngdoc method
     * @name setFocus
     * @methodOf talend.sunchoke.date-picker.controller:ScDatePickerCtrl
     * @description This method is called when gain or loose focus
     */
    setFocus(focusState) {
        this.focusState = focusState;
    }

}<commit_msg>TDS-843: calling onClose function even when there's no date in the datepicker<commit_after>/*  ============================================================================

 Copyright (C) 2006-2016 Talend Inc. - www.talend.com

 This source code is available under agreement available at
 https://github.com/Talend/data-prep/blob/master/LICENSE

 You should have received a copy of the agreement
 along with this program; if not, write to Talend SA
 9 rue Pages 92150 Suresnes, France

 ============================================================================*/

import Pikaday from "./pikaday-override";

/**
 * @ngdoc controller
 * @name talend.sunchoke.date-picker.controller:ScDatePickerCtrl
 * @description Date picker controller
 */
export default class ScDatePickerCtrl {
    constructor($element, $timeout) {
        'ngInject';
        this.$element = $element;
        this.focusState = false;
        this.$timeout = $timeout;
    }

    /**
     * @ngdoc method
     * @name $onInit
     * @methodOf talend.sunchoke.date-picker.controller:ScDatePickerCtrl
     * @description Hook when controller is initialized
     */
    $onInit() {
        //Get the input in the element dom
        const input = this.$element.find('input')[0];
        //date picker container
        const container = this.$element.find('div')[2];

        //Config object for pikaday
        const config = {
            showDaysInNextAndPreviousMonths: true,
            controller: this,
            container: container,
            field: input,
            onClose: this.onCloseHandler,
            positionLeft: this.positionLeft,
            i18n: {
                previousMonth: 'Previous Month',
                nextMonth: 'Next Month',
                months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
                weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
                weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
                none: "None"
            },
            firstDay: 0,
            noneButton: false,
            format: 'MMM D, YYYY'
        };

        //Get all specific configuration
        for (const configKey in this.config) {
            //protect controller & field parameters
            if (configKey !== 'controller' && configKey !== 'field' && container !== 'container') {
                config[configKey] = this.config[configKey];
            }
        }

        this.pikaday = new Pikaday(config);
    }

    /**
     * @ngdoc method
     * @name $onDestroy
     * @methodOf talend.sunchoke.date-picker.controller:ScDatePickerCtrl
     * @description Method called when the controller is destroyed
     */
    $onDestroy() {
        this.pikaday.destroy();
    }

    /**
     * @ngdoc method
     * @name onCloseHandler
     * @methodOf talend.sunchoke.date-picker.controller:ScDatePickerCtrl
     * @description This method is called when datepicker value changed ( onClose )
     */
    onCloseHandler() {

        //if there is a controller
        if (this._o && this._o.controller) {
            //get the controller
            const actualController = this._o.controller;
            //if there is a date
            if (this._d) {

                // if a bad date has been provided
                if (this.textErrorDate) {
                    actualController.ngModel = this.textErrorDate;
                }
                else {
                    //get the date timestamp
                    actualController.ngModel = this._d.getTime();
                }

                //Close only if not init
                if (!this.doNotCloseDp || this.doNotCloseDp === false) {
                    actualController.$timeout(() => {
                        actualController.onCloseFn();
                    });
                }

            }
            //if there is no date, the value may be reset
            else {
                //set null to ngmodel
                actualController.ngModel = null;
                actualController.$timeout(() => {
                    actualController.onCloseFn();
                });
            }
        }
    }

    /**
     * @ngdoc method
     * @name setFocus
     * @methodOf talend.sunchoke.date-picker.controller:ScDatePickerCtrl
     * @description This method is called when gain or loose focus
     */
    setFocus(focusState) {
        this.focusState = focusState;
    }

}<|endoftext|>


<commit_before>import React, {Component} from 'react';
import PropTypes, {withViewport} from '../../PropTypes.js';

import Table from 'react-bootstrap/lib/Table';
import IconButton from '@material-ui/core/IconButton';
import {Spinner} from '../../controls.js';
import {OtherMatchPlayerResultsTableRow} from './OtherMatchPlayerResults.js';
import {MatchPlayerRankings} from '../controls/MatchPlayerRankings.js';

const AmountOfOpponentMatchesToShow = 5;

@withViewport
export default class OpponentsLastMatches extends Component {
  static contextTypes = PropTypes.contextTypes;
  static propTypes = {
    opponent: PropTypes.shape({
      clubId: PropTypes.number.isRequired,
      teamCode: PropTypes.string.isRequired,
    }),
    readonlyMatches: PropTypes.object.isRequired,
    viewport: PropTypes.viewport,
  }

  constructor(props) {
    super(props);
    this.state = {
      showAll: false,
    };
  }

  render() {
    const widthRemoveColumn = 500; // combine Home&Away columns to just one Opponent column on small devices

    var matches = this.props.readonlyMatches;
    if (!this.state.showAll) {
      matches = matches.take(AmountOfOpponentMatchesToShow);
    }
    if (matches.size === 0) {
      // TODO: Do not show spinner if these guys just haven't played any matches yet...
      return

<Spinner />

;
    }

    return (

            {this.context.t('common.date')}
            {this.context.t('common.frenoy')}
            {this.props.viewport.width > widthRemoveColumn ? [
              {this.context.t('match.opponents.homeTeam')}	,
              {this.context.t('match.opponents.awayTeam')}
            ] : (
              {this.context.t('match.opponents.vsTeam')}
            )}
            {this.context.t('common.teamFormation')}
            {this.context.t('match.opponents.outcome')}

          {matches.map(match => {
            const opponent = this.props.opponent;
            const isHomeMatch = match.home.clubId === opponent.clubId && match.home.teamCode === opponent.teamCode;
            return [

 this.setState({[match.id]: !this.state[match.id]})}
              >

                {match.getDisplayDate(this.props.viewport.width > widthRemoveColumn ? 'd' : 's')}
                {match.frenoyMatchId}
                {this.props.viewport.width > widthRemoveColumn ? [
                  {match.getClub('home').name} {match.home.teamCode}	,
                  {match.getClub('away').name} {match.away.teamCode}
                ] : (

                    {isHomeMatch ? (
                      match.getClub('away').name + ' ' + match.away.teamCode
                    ) : (
                      match.getClub('home').name + ' ' + match.home.teamCode
                    )}

                )}

                <MatchPlayerRankings match={match} homeTeam={isHomeMatch} />

                {match.score.home} - {match.score.out}

,
              <OtherMatchPlayerResultsTableRow key="8" show={this.state[match.id]} match={match} colSpan={5} />
            ];
          })}
          {!this.state.showAll && this.props.readonlyMatches.size > AmountOfOpponentMatchesToShow ? (

                <IconButton iconClassName="fa fa-chevron-circle-down" onClick={() => this.setState({showAll: true})} />

          ) : null}

    );
  }
}
<commit_msg>bugfix: down arrow icon was not visible<commit_after>import React, {Component} from 'react';
import PropTypes, {withViewport} from '../../PropTypes.js';

import Table from 'react-bootstrap/lib/Table';
import IconButton from '@material-ui/core/IconButton';
import {Spinner} from '../../controls.js';
import {OtherMatchPlayerResultsTableRow} from './OtherMatchPlayerResults.js';
import {MatchPlayerRankings} from '../controls/MatchPlayerRankings.js';

const AmountOfOpponentMatchesToShow = 5;

@withViewport
export default class OpponentsLastMatches extends Component {
  static contextTypes = PropTypes.contextTypes;
  static propTypes = {
    opponent: PropTypes.shape({
      clubId: PropTypes.number.isRequired,
      teamCode: PropTypes.string.isRequired,
    }),
    readonlyMatches: PropTypes.object.isRequired,
    viewport: PropTypes.viewport,
  }

  constructor(props) {
    super(props);
    this.state = {
      showAll: false,
    };
  }

  render() {
    const widthRemoveColumn = 500; // combine Home&Away columns to just one Opponent column on small devices

    var matches = this.props.readonlyMatches;
    if (!this.state.showAll) {
      matches = matches.take(AmountOfOpponentMatchesToShow);
    }
    if (matches.size === 0) {
      // TODO: Do not show spinner if these guys just haven't played any matches yet...
      return

<Spinner />

;
    }

    return (

            {this.context.t('common.date')}
            {this.context.t('common.frenoy')}
            {this.props.viewport.width > widthRemoveColumn ? [
              {this.context.t('match.opponents.homeTeam')}	,
              {this.context.t('match.opponents.awayTeam')}
            ] : (
              {this.context.t('match.opponents.vsTeam')}
            )}
            {this.context.t('common.teamFormation')}
            {this.context.t('match.opponents.outcome')}

          {matches.map(match => {
            const opponent = this.props.opponent;
            const isHomeMatch = match.home.clubId === opponent.clubId && match.home.teamCode === opponent.teamCode;
            return [

 this.setState({[match.id]: !this.state[match.id]})}
              >

                {match.getDisplayDate(this.props.viewport.width > widthRemoveColumn ? 'd' : 's')}
                {match.frenoyMatchId}
                {this.props.viewport.width > widthRemoveColumn ? [
                  {match.getClub('home').name} {match.home.teamCode}	,
                  {match.getClub('away').name} {match.away.teamCode}
                ] : (

                    {isHomeMatch ? (
                      match.getClub('away').name + ' ' + match.away.teamCode
                    ) : (
                      match.getClub('home').name + ' ' + match.home.teamCode
                    )}

                )}

                <MatchPlayerRankings match={match} homeTeam={isHomeMatch} />

                {match.score.home} - {match.score.out}

,
              <OtherMatchPlayerResultsTableRow key="8" show={this.state[match.id]} match={match} colSpan={5} />
            ];
          })}
          {!this.state.showAll && this.props.readonlyMatches.size > AmountOfOpponentMatchesToShow ? (

                <IconButton onClick={() => this.setState({showAll: true})}>

                </IconButton>

          ) : null}

    );
  }
}
<|endoftext|>


<commit_before>let fs = require('fs');
let fns=[];
fs.readFile('./src/ec-do-3.0.0-beta.1.js', (err, data) => {
    if (err) {
        //如 果 出 错， 输 出 错 误 日 志， 并 给 客 户 端 返 回“ Server Error”
        console.error(err);
    }
    else {
        let md="";
        let obj=new Function(data.toString().replace('let','let _ecObj=')+';return _ecObj')();
        Object.keys(obj).forEach((item,index)=>{
            fns.push({
                index:index,
                name:item
            })
        })
    }
})

fs.readFile('./README.md', (err, data) => {
    if (err) {
        console.error(err);
    }
    else {
        let _data=data.toString().split('\r\n');
        let i=1;
        _data.forEach((item,index)=>{
            if(/%%/.test(item)){
                _data[index]=item.replace('%%',i+'.');
                i++;
            }
        })
        fs.writeFileSync("./README.md", _data.join('\r\n'));
    }
})
<commit_msg>修改 fnIndex.js<commit_after>let fs = require('fs');
let fns=[];
fs.readFile('./src/ec-do-3.0.0-beta.1.js', (err, data) => {
    if (err) {
        //如 果 出 错， 输 出 错 误 日 志， 并 给 客 户 端 返 回“ Server Error”
        console.error(err);
    }
    else {
        let md="";
        let obj=new Function(data.toString().replace('let','let _ecObj=')+';return _ecObj')();
        Object.keys(obj).forEach((item,index)=>{
            fns.push({
                index:index,
                name:item
            })
        })
    }
})

fs.readFile('./README.md', (err, data) => {
    if (err) {
        console.error(err);
    }
    else {
        let _data=data.toString().split('\r\n');
        let i=1;
        _data.forEach((item,index)=>{
            if(/#{3}\s([0-9]+)/.test(item)){
                _data[index]=item.replace(/#{3}\s([0-9]+)/,'### '+i);
                i++;
            }
        })
        fs.writeFileSync("./README.md", _data.join('\r\n'));
    }
})
<|endoftext|>


<commit_before>/*jshint node:true*/

'use strict';

var path = require('path');
var existsSync = require('exists-sync');
var chalk = require('chalk');
var EOL = require('os').EOL;

module.exports = {
  normalizeEntityName: function() {
    // this prevents an error when the entityName is
    // not specified (since that doesn't actually matter
    // to us
  },

  fileMapTokens: function() {
    return {
      __root__: function(options) {
        if (options.inAddon) {
          return path.join('tests', 'dummy');
        }

        return '/';
      }
    };
  },

  afterInstall: function() {
    this.insertIntoFile('.jshintrc', '    "server",', {
      after: '"predef": [\n'
    });

    this.insertIntoFile('tests/.jshintrc', '    "server",', {
      after: '"predef": [\n'
    });

    if (existsSync('tests/helpers/destroy-app.js')) {
      this.insertIntoFile('tests/helpers/destroy-app.js', '  server.shutdown();', {
        after: "Ember.run(application, 'destroy');\n"
      });
    } else {
      this.ui.writeLine(
        EOL +
        chalk.yellow(
          '******************************************************' + EOL +
          'destroy-app.js helper is not present. Please read this' + EOL +
          'https://gist.github.com/blimmer/35d3efbb64563029505a'   + EOL +
          'to see how to fix the problem.'                         + EOL +
          '******************************************************' + EOL
        )
      );
    }

    return this.addBowerPackagesToProject([
      { name: 'pretender', target: '~0.12.0' },
      { name: 'Faker', target: '~3.0.0' }
    ]);
  }
};
<commit_msg>update faker version specified in afterInstall hook (#704)<commit_after>/*jshint node:true*/

'use strict';

var path = require('path');
var existsSync = require('exists-sync');
var chalk = require('chalk');
var EOL = require('os').EOL;

module.exports = {
  normalizeEntityName: function() {
    // this prevents an error when the entityName is
    // not specified (since that doesn't actually matter
    // to us
  },

  fileMapTokens: function() {
    return {
      __root__: function(options) {
        if (options.inAddon) {
          return path.join('tests', 'dummy');
        }

        return '/';
      }
    };
  },

  afterInstall: function() {
    this.insertIntoFile('.jshintrc', '    "server",', {
      after: '"predef": [\n'
    });

    this.insertIntoFile('tests/.jshintrc', '    "server",', {
      after: '"predef": [\n'
    });

    if (existsSync('tests/helpers/destroy-app.js')) {
      this.insertIntoFile('tests/helpers/destroy-app.js', '  server.shutdown();', {
        after: "Ember.run(application, 'destroy');\n"
      });
    } else {
      this.ui.writeLine(
        EOL +
        chalk.yellow(
          '******************************************************' + EOL +
          'destroy-app.js helper is not present. Please read this' + EOL +
          'https://gist.github.com/blimmer/35d3efbb64563029505a'   + EOL +
          'to see how to fix the problem.'                         + EOL +
          '******************************************************' + EOL
        )
      );
    }

    return this.addBowerPackagesToProject([
      { name: 'pretender', target: '~0.12.0' },
      { name: 'Faker', target: '~3.1.0' }
    ]);
  }
};
<|endoftext|>


<commit_before>exports.BattleFormats = {

	// formats

	RandomBattle: {
		effectType: 'Format',
		name: "Random Battle",
		team: 'random',
		searchDefault: true,
		ranked: true,
		ruleset: ['PotD', 'SleepClause']
	},
	UnrankedRandomBattle: {
		effectType: 'Format',
		name: "Unranked Random Battle",
		team: 'random',
		challengeHide: true,
		ruleset: ['PotD', 'SleepClause']
	},
	OU: {
		effectType: 'Format',
		name: "OU",
		challengeDefault: true,
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard', 'Uber', 'CAP', 'Drizzle ++ SwiftSwim']
	},
	CAP: {
		effectType: 'Format',
		name: "CAP",
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard','Uber']
	},
	Ubers: {
		effectType: 'Format',
		name: "Ubers",
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard','CAP']
	},
	UU: {
		effectType: 'Format',
		name: "UU",
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard','Uber','OU','BL','CAP', 'Hail','Drought']
	},
	RU: {
		effectType: 'Format',
		name: "RU",
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard','Uber','OU','BL','UU','BL2','CAP', 'ShellSmash + BatonPass']
	},
	NU: {
		effectType: 'Format',
		name: "NU",
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard','Uber','OU','BL','UU','BL2','RU','CAP']
	},
	Hackmons: {
		effectType: 'Format',
		name: "Hackmons",
		searchHide: true,
		ruleset: [],
		banlist: []
	},
	BalancedHackmons: {
		effectType: 'Format',
		name: "Balanced Hackmons",
		ranked: true,
		ruleset: [],
		banlist: ['OHKO', 'WonderGuard']
	},
	Haxmons: {
		effectType: 'Format',
		name: "Haxmons",
		searchHide: true,
		ruleset: ['HaxClause', 'TeamPreview']
	},
	"DebugMode(ALPHA)": {
		effectType: 'Format',
		name: "Debug Mode (ALPHA)",
		searchHide: true,
		// no restrictions, for serious
		ruleset: ['Standard']
	},

	// rules

	Standard: {
		effectType: 'Banlist',
		banlist: ['Unreleased', 'Illegal', 'OHKO', 'Moody', 'BrightPowder', 'LaxIncense', 'Minimize', 'DoubleTeam']
	},
	PotD: {
		effectType: 'Rule',
		onPotD: '',
		onStart: function() {
			if (this.effect.onPotD)
			{
				this.add('rule Pokemon of the Day: '+this.effect.onPotD);
			}
		}
	},
	TeamPreview: {
		onStartPriority: -10,
		onStart: function() {
			for (var i=0; i<this.sides[0].pokemon.length; i++)
			{
				this.add('pokemon '+this.sides[0].pokemon[i].tpid);
			}
			for (var i=0; i<this.sides[1].pokemon.length; i++)
			{
				this.add('pokemon '+this.sides[1].pokemon[i].tpid);
			}
		},
		onTeamPreview: function() {
			this.callback('team-preview');
		}
	},
	HaxClause: {
		effectType: 'Rule',
		onStart: function() {
			this.add('rule Hax Clause');
		},
		onModifyMovePriority: -100,
		onModifyMove: function(move) {
			if (move.secondary)
			{
				move.secondary.chance = 100;
			}
			if (move.accuracy !== true && move.accuracy <= 99)
			{
				move.accuracy = 0;
			}
			move.willCrit = true;
		}
	},
	SleepClause: {
		effectType: 'Rule',
		onStart: function() {
			this.add('rule Sleep Clause');
		},
		onSetStatus: function(status, target, source) {
			if (source && source.side === target.side)
			{
				return;
			}
			if (status.id === 'slp')
			{
				for (var i=0; i<target.side.pokemon.length; i++)
				{
					var pokemon = target.side.pokemon[i];
					if (pokemon.status === 'slp')
					{
						if (!pokemon.statusData.source ||
						    pokemon.statusData.source.side !== pokemon.side)
						{
							this.add('message Sleep Clause activated.');
							return false;
						}
					}
				}
			}
		}
	},
	FreezeClause: {
		effectType: 'Rule',
		onStart: function() {
			this.add('rule Freeze Clause');
		}
	}
};<commit_msg>Ban Snow Warning in UU, not the move Hail<commit_after>exports.BattleFormats = {

	// formats

	RandomBattle: {
		effectType: 'Format',
		name: "Random Battle",
		team: 'random',
		searchDefault: true,
		ranked: true,
		ruleset: ['PotD', 'SleepClause']
	},
	UnrankedRandomBattle: {
		effectType: 'Format',
		name: "Unranked Random Battle",
		team: 'random',
		challengeHide: true,
		ruleset: ['PotD', 'SleepClause']
	},
	OU: {
		effectType: 'Format',
		name: "OU",
		challengeDefault: true,
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard', 'Uber', 'CAP', 'Drizzle ++ SwiftSwim']
	},
	CAP: {
		effectType: 'Format',
		name: "CAP",
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard','Uber']
	},
	Ubers: {
		effectType: 'Format',
		name: "Ubers",
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard','CAP']
	},
	UU: {
		effectType: 'Format',
		name: "UU",
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard','Uber','OU','BL','CAP', 'SnowWarning','Drought']
	},
	RU: {
		effectType: 'Format',
		name: "RU",
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard','Uber','OU','BL','UU','BL2','CAP', 'ShellSmash + BatonPass']
	},
	NU: {
		effectType: 'Format',
		name: "NU",
		ranked: true,
		ruleset: ['SleepClause', 'Standard', 'TeamPreview'],
		banlist: ['Standard','Uber','OU','BL','UU','BL2','RU','CAP']
	},
	Hackmons: {
		effectType: 'Format',
		name: "Hackmons",
		searchHide: true,
		ruleset: [],
		banlist: []
	},
	BalancedHackmons: {
		effectType: 'Format',
		name: "Balanced Hackmons",
		ranked: true,
		ruleset: [],
		banlist: ['OHKO', 'WonderGuard']
	},
	Haxmons: {
		effectType: 'Format',
		name: "Haxmons",
		searchHide: true,
		ruleset: ['HaxClause', 'TeamPreview']
	},
	"DebugMode(ALPHA)": {
		effectType: 'Format',
		name: "Debug Mode (ALPHA)",
		searchHide: true,
		// no restrictions, for serious
		ruleset: ['Standard']
	},

	// rules

	Standard: {
		effectType: 'Banlist',
		banlist: ['Unreleased', 'Illegal', 'OHKO', 'Moody', 'BrightPowder', 'LaxIncense', 'Minimize', 'DoubleTeam']
	},
	PotD: {
		effectType: 'Rule',
		onPotD: '',
		onStart: function() {
			if (this.effect.onPotD)
			{
				this.add('rule Pokemon of the Day: '+this.effect.onPotD);
			}
		}
	},
	TeamPreview: {
		onStartPriority: -10,
		onStart: function() {
			for (var i=0; i<this.sides[0].pokemon.length; i++)
			{
				this.add('pokemon '+this.sides[0].pokemon[i].tpid);
			}
			for (var i=0; i<this.sides[1].pokemon.length; i++)
			{
				this.add('pokemon '+this.sides[1].pokemon[i].tpid);
			}
		},
		onTeamPreview: function() {
			this.callback('team-preview');
		}
	},
	HaxClause: {
		effectType: 'Rule',
		onStart: function() {
			this.add('rule Hax Clause');
		},
		onModifyMovePriority: -100,
		onModifyMove: function(move) {
			if (move.secondary)
			{
				move.secondary.chance = 100;
			}
			if (move.accuracy !== true && move.accuracy <= 99)
			{
				move.accuracy = 0;
			}
			move.willCrit = true;
		}
	},
	SleepClause: {
		effectType: 'Rule',
		onStart: function() {
			this.add('rule Sleep Clause');
		},
		onSetStatus: function(status, target, source) {
			if (source && source.side === target.side)
			{
				return;
			}
			if (status.id === 'slp')
			{
				for (var i=0; i<target.side.pokemon.length; i++)
				{
					var pokemon = target.side.pokemon[i];
					if (pokemon.status === 'slp')
					{
						if (!pokemon.statusData.source ||
						    pokemon.statusData.source.side !== pokemon.side)
						{
							this.add('message Sleep Clause activated.');
							return false;
						}
					}
				}
			}
		}
	},
	FreezeClause: {
		effectType: 'Rule',
		onStart: function() {
			this.add('rule Freeze Clause');
		}
	}
};<|endoftext|>


<commit_before>function activateGoggles() {
  (function($){
      if (window.goggles) { return window.goggles.stop(function(){window.goggles = null;}); }

      function bind(bindee, action) {
        return function() {
          return action.apply(bindee, Array.prototype.slice.call(arguments));
        };
      }

      // SHAPES
      function Shape(t, r,g,b,a) {
        // Each shape looks like this:
        // {p: [ [x,y], [x,y], [x,y], ...], points
        //  t: 5                            thickness
        //  r: 250, g: 200, b: 125, a: 0.5  color
        // }
        // give it a position, thickness, and rgba colors
        this.t = t;
        this.r=r;
        this.g=g;
        this.b=b;
        this.a=a;
        this.p = [];
      }
      Shape.prototype.appendPoint = function(point) {
        // Append a point to this shape.
        this.p.push(
          [Math.round(point[0]*10)/10, Math.round(point[1]*10)/10]
        );
      };
      Shape.prototype.drawLast = function(ctx) {
        // Given a canvas, draw the last line of the shape
        if (this.p.length >= 2) {
          var a = this.p[this.p.length-2],
              b = this.p[this.p.length-1];
          // draws part of the shape
          ctx.strokeStyle = "rgba("+this.r+","+this.g+","+this.b+","+this.a+")";
          ctx.lineWidth = this.t;
          ctx.lineCap = "round";
          ctx.beginPath();
          ctx.moveTo.apply(ctx, a);
          ctx.lineTo.apply(ctx, b);
          ctx.stroke();
        }
      };
      Shape.prototype.draw = function(ctx) {
        // Draw a given shape if it is in view.
//      if ((p.x + shape.s) > 0 &&
//          (p.y + shape.s) > 0 &&
//          (p.x - shape.s) < canvas.width &&
//          (p.y - shape.s) < canvas.height) {
          ctx.strokeStyle = "rgba("+this.r+","+this.g+","+this.b+","+this.a+")";
          ctx.lineWidth = this.t;
          ctx.lineCap = "round";
          ctx.beginPath();
          ctx.moveTo.apply(ctx, this.p[0]);
          for (var i=0,l=this.p.length; i<l; i++) {
            ctx.lineTo.apply(ctx, this.p[i]);
          }
          ctx.stroke();
//       }
      };

      // GOGGLES
      function Goggles() {
        // Here is our goggles object.

        this.canvas = $("<canvas>").css({
          position: "fixed",
          "z-index": "100000",
          top: "0",
          left: "0"
        }).appendTo(document.body)[0];

        this.ctx = this.canvas.getContext('2d');

        this.shapes = [];
        // the list of shapes to draw.
        this.curshape = null;

        // Center coordinate
        // Guess at where the text probably is
        this.centerCoord = 0;
        this.recalculateCenter();

        // Events
        this.canvas.onmousedown = bind(this, function(ev) {
          this.curshape = new Shape(5, 0,0,0,1);
        });
        this.canvas.onmouseup = bind(this, function(ev) {
          this.shapes.push(this.curshape);
          this.curshape = null;
        });
        this.canvas.onmousemove = bind(this, function(ev) {
          if (this.curshape) {
            this.curshape.appendPoint(
              this.untransform(this.pointsFromEv(ev)));
            this.curshape.drawLast(this.ctx);
          }
        });

        // Window resize and scroll handlers
        this.resizeTimer = null;
        window.onresize = bind(this, function() {
          // Resize later
          clearTimeout(this.resizeTimer);
          this.resizeTimer = setTimeout(bind(this, this.resizeCanvas), 100);
        });
        window.onscroll = bind(this, this.redraw);
        this.resizeCanvas();
      }
      Goggles.prototype.stop = function(cb) {
        // Destroy a goggles object with optional callback
        $(this.canvas).fadeOut('fast', function() {
            window.onresize = null;
            window.onscroll = null;
            clearTimeout(this.resizeTimer);
            $(this.canvas).remove();
            cb();
          });
      };
      // Point transformation functions
      // Establish a new coordinate system. (0, 0) is at the top MIDDLE of
      // the page, +x is right and -x is left.
      // This accomodates pages that have fixed-width or centered layouts.
      // todo: actually I would really like this to be relative to either
      // the left of the content or the middle of the page.
      Goggles.prototype.transform = function(p) {
        // Given an absolute point in our new coordinate system, return the
        // point's position on the screen
        return [
          p[0]-window.scrollX + this.centerCoord,
          p[1]-window.scrollY
        ];
      };
      Goggles.prototype.untransform = function(p) {
        // Given an point wrt the screen, return the point's absolute position
        // wrt our coordinate system
        return [
          p[0]+window.scrollX - this.centerCoord,
          p[1]+window.scrollY
        ];
      };

      // Drawing functions
      Goggles.prototype.redraw = function() {
        // Redraw entire canvas
        var ctx = this.ctx;
        // clear
        this.resetCanvasXform();

        for (var i=0,l=this.shapes.length; i<l; i++) {
          this.shapes[i].draw(ctx);
        }

      };

      // Event handling
      Goggles.prototype.pointsFromEv = function(ev) {
        if ('clientX' in ev) { // Firefox
          return [ev.clientX, ev.clientY];
        } else if ('offsetX' in ev) { // Opera
          return [ev.offsetX, ev.offsetY];
        }
      };

      //////// INIT
      Goggles.prototype.resetCanvasXform = function() {
        this.ctx.setTransform(1,0,
                              0,1,  0, 0);
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.ctx.setTransform(1,0,
                              0,1,
          this.centerCoord-window.scrollX,
          -window.scrollY);
      };
      Goggles.prototype.resizeCanvas = function() {
        // Fix the canvas when resized
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight;
        this.recalculateCenter();
        this.redraw();
      };

      Goggles.prototype.recalculateCenter = function() {
        // this calculates what X-coordinate will be the 'focus' of our web
        // page.
        //
        // essentially, we want our x=0 coordinate to be the left edge of the
        // content. this works reasonably well in practice except for
        // dynamically generated things and line wrapping.

        this.centerCoord = (
          ($("#header").offset() || {left:0}).left ||
          ($(".header").offset() || {left:0}).left ||
          ($(".inner").offset()  || {left:0}).left ||
          ($(".content").offset()|| {left:0}).left ||

          // hackernews
          ($("body>center>table").offset()||{left: 0}).left ||
          // table-based layouts
          ($("body>table").offset()||{left: 0}).left ||

          // gogole results pages
          ($("#center_col").offset()||{left:0}).left ||

          (this.canvas.width/2)
        );
      };

      window.goggles = new Goggles();

  })(jQuery);
}

if (typeof jQuery == 'undefined') {
  var jQ = document.createElement('script');
  jQ.type = 'text/javascript';
  jQ.onload=activateGoggles;
  jQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
  document.body.appendChild(jQ);
} else {
  activateGoggles();
}
<commit_msg>Clip invisible shapes<commit_after>function activateGoggles() {
  (function($){
      if (window.goggles) { return window.goggles.stop(function(){window.goggles = null;}); }

      function bind(bindee, action) {
        return function() {
          return action.apply(bindee, Array.prototype.slice.call(arguments));
        };
      }

      // SHAPES
      function Shape(t, r,g,b,a) {
        // Each shape looks like this:
        // {p: [ [x,y], [x,y], [x,y], ...], points
        //  t: 5                            thickness
        //  r: 250, g: 200, b: 125, a: 0.5  color
        // }
        // give it a position, thickness, and rgba colors
        this.t = t;
        this.r=r;
        this.g=g;
        this.b=b;
        this.a=a;
        this.p = [];
      }
      Shape.prototype.appendPoint = function(point) {
        // Append a point to this shape.
        this.p.push(
          [Math.round(point[0]*10)/10, Math.round(point[1]*10)/10]
        );
      };
      Shape.prototype.drawLast = function(ctx) {
        // Given a canvas, draw the last line of the shape
        if (this.p.length >= 2) {
          var a = this.p[this.p.length-2],
              b = this.p[this.p.length-1];
          // draws part of the shape
          ctx.strokeStyle = "rgba("+this.r+","+this.g+","+this.b+","+this.a+")";
          ctx.lineWidth = this.t;
          ctx.lineCap = "round";
          ctx.beginPath();
          ctx.moveTo.apply(ctx, a);
          ctx.lineTo.apply(ctx, b);
          ctx.stroke();
        }
      };
      Shape.prototype.draw = function(ctx) {
        // Draw a given shape if it is in view.
//      if ((p.x + shape.s) > 0 &&
//          (p.y + shape.s) > 0 &&
//          (p.x - shape.s) < canvas.width &&
//          (p.y - shape.s) < canvas.height) {
          ctx.strokeStyle = "rgba("+this.r+","+this.g+","+this.b+","+this.a+")";
          ctx.lineWidth = this.t;
          ctx.lineCap = "round";
          ctx.beginPath();
          ctx.moveTo.apply(ctx, this.p[0]);
          for (var i=0,l=this.p.length; i<l; i++) {
            ctx.lineTo.apply(ctx, this.p[i]);
          }
          ctx.stroke();
//       }
      };
      Shape.prototype.boundingBox = function() {
        // return the bounding box
        return {
          left: Math.min.apply(null, this.p.map(function(point){return point[0];})),
          right: Math.max.apply(null, this.p.map(function(point){return point[0];})),
          top: Math.min.apply(null, this.p.map(function(point){return point[1];})),
          bottom: Math.max.apply(null, this.p.map(function(point){return point[1];}))
        };
      };

      // GOGGLES
      function Goggles() {
        // Here is our goggles object.

        this.canvas = $("<canvas>").css({
          position: "fixed",
          "z-index": "100000",
          top: "0",
          left: "0"
        }).appendTo(document.body)[0];

        this.ctx = this.canvas.getContext('2d');

        this.shapes = [];
        // the list of shapes to draw.
        this.curshape = null;

        // Center coordinate
        // Guess at where the text probably is
        this.centerCoord = 0;
        this.recalculateCenter();

        // Events
        this.canvas.onmousedown = bind(this, function(ev) {
          this.curshape = new Shape(5, 0,0,0,1);
        });
        this.canvas.onmouseup = bind(this, function(ev) {
          this.shapes.push(this.curshape);
          this.curshape = null;
        });
        this.canvas.onmousemove = bind(this, function(ev) {
          if (this.curshape) {
            this.curshape.appendPoint(
              this.untransform(this.pointsFromEv(ev)));
            this.curshape.drawLast(this.ctx);
          }
        });

        // Window resize and scroll handlers
        this.resizeTimer = null;
        window.onresize = bind(this, function() {
          // Resize later
          clearTimeout(this.resizeTimer);
          this.resizeTimer = setTimeout(bind(this, this.resizeCanvas), 100);
        });
        window.onscroll = bind(this, this.redraw);
        this.resizeCanvas();
      }
      Goggles.prototype.stop = function(cb) {
        // Destroy a goggles object with optional callback
        $(this.canvas).fadeOut('fast', function() {
            window.onresize = null;
            window.onscroll = null;
            clearTimeout(this.resizeTimer);
            $(this.canvas).remove();
            cb();
          });
      };
      // Point transformation functions
      // Establish a new coordinate system. (0, 0) is at the top MIDDLE of
      // the page, +x is right and -x is left.
      // This accomodates pages that have fixed-width or centered layouts.
      // todo: actually I would really like this to be relative to either
      // the left of the content or the middle of the page.
      Goggles.prototype.transform = function(p) {
        // Given an absolute point in our new coordinate system, return the
        // point's position on the screen
        return [
          p[0]-window.scrollX + this.centerCoord,
          p[1]-window.scrollY
        ];
      };
      Goggles.prototype.untransform = function(p) {
        // Given an point wrt the screen, return the point's absolute position
        // wrt our coordinate system
        return [
          p[0]+window.scrollX - this.centerCoord,
          p[1]+window.scrollY
        ];
      };

      // Drawing functions
      Goggles.prototype.redraw = function() {
        // Redraw entire canvas
        var ctx = this.ctx;
        // clear
        this.resetCanvasXform();
        for (var i=0,l=this.shapes.length; i<l; i++) {
          var bb = this.shapes[i].boundingBox();
          // clip invisible shapes
          if (bb.right - window.scrollX + this.centerCoord > 0 &&
              bb.left - window.scrollX + this.centerCoord < this.canvas.width &&
              bb.bottom - window.scrollY > 0 &&
              bb.top - window.scrollY < this.canvas.height) {
            this.shapes[i].draw(ctx);
          }
        }

      };

      // Event handling
      Goggles.prototype.pointsFromEv = function(ev) {
        if ('clientX' in ev) { // Firefox
          return [ev.clientX, ev.clientY];
        } else if ('offsetX' in ev) { // Opera
          return [ev.offsetX, ev.offsetY];
        }
      };

      //////// INIT
      Goggles.prototype.resetCanvasXform = function() {
        this.ctx.setTransform(1,0,
                              0,1,  0, 0);
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.ctx.setTransform(1,0,
                              0,1,
          this.centerCoord-window.scrollX,
          -window.scrollY);
      };
      Goggles.prototype.resizeCanvas = function() {
        // Fix the canvas when resized
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight;
        this.recalculateCenter();
        this.redraw();
      };

      Goggles.prototype.recalculateCenter = function() {
        // this calculates what X-coordinate will be the 'focus' of our web
        // page.
        //
        // essentially, we want our x=0 coordinate to be the left edge of the
        // content. this works reasonably well in practice except for
        // dynamically generated things and line wrapping.

        this.centerCoord = (
          ($("#header").offset() || {left:0}).left ||
          ($(".header").offset() || {left:0}).left ||
          ($(".inner").offset()  || {left:0}).left ||
          ($(".content").offset()|| {left:0}).left ||

          // hackernews
          ($("body>center>table").offset()||{left: 0}).left ||
          // table-based layouts
          ($("body>table").offset()||{left: 0}).left ||

          // gogole results pages
          ($("#center_col").offset()||{left:0}).left ||

          (this.canvas.width/2)
        );
      };

      window.goggles = new Goggles();

  })(jQuery);
}

if (typeof jQuery == 'undefined') {
  var jQ = document.createElement('script');
  jQ.type = 'text/javascript';
  jQ.onload=activateGoggles;
  jQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
  document.body.appendChild(jQ);
} else {
  activateGoggles();
}
<|endoftext|>