<commit_before>var Storybook = require('./storybook');
var Promise = require('bluebird');
var compact = require('lodash/compact');
var colors = require('colors/safe');

exports.startStorybook = Promise.promisify(Storybook.server);

exports.getStorybook = function(options) {
  var getStorybook = Promise.promisify(Storybook.get);
  return getStorybook(options)
    .then(function(storybook) {
      if (typeof storybook === 'object' && typeof storybook.map === 'function') {
        // make copy and extract steps
        storybook = compact(storybook.map(function(kind) {
          // check kind format
          if (typeof kind !== 'object' || !kind.kind || !kind.stories || !(typeof kind.stories === 'object' && typeof kind.stories.map === 'function') || kind.stories.length === 0) {
            console.log(colors.yellow('WARNING: Invalid kind format. Skipping.'));
            console.log(kind);
            return null;
          }
          return {
            kind: kind.kind,
            stories: compact(kind.stories.map(function(story) {
              // check story format
              if (typeof story !== 'object' || !story.name || typeof story.name !== 'string') {
                console.log(colors.yellow('WARNING: Invalid story format in \'' + kind.kind + '\'. Skipping story.'));
                console.log(kind);
                return null;
              }
              var obj = {
                name: story.name
              };
              if (typeof story.render === 'function') {
                try {
                  var result = story.render(kind);
                  // check if <Screener> is top-most component
                  if (result && result.type && result.props && result.type.name === 'Screener') {
                    // get steps prop
                    obj.steps = result.props.steps;
                  }
                } catch(ex) {
                  if (options && options.debug) {
                    console.error(colors.red('Error processing render() method of:'), story);
                    console.error(colors.red(ex.stack || ex.message || ex.toString()));
                  }
                }
              }
              return obj;
            }))
          };
        }));
      }
      return storybook;
    });
};

exports.run = require('./runner').run;
<commit_msg>handle nested steps<commit_after>var Storybook = require('./storybook');
var Promise = require('bluebird');
var compact = require('lodash/compact');
var colors = require('colors/safe');

exports.startStorybook = Promise.promisify(Storybook.server);

exports.getStorybook = function(options) {
  var getStorybook = Promise.promisify(Storybook.get);
  return getStorybook(options)
    .then(function(storybook) {
      if (typeof storybook === 'object' && typeof storybook.map === 'function') {
        // make copy and extract steps
        storybook = compact(storybook.map(function(kind) {
          // check kind format
          if (typeof kind !== 'object' || !kind.kind || !kind.stories || !(typeof kind.stories === 'object' && typeof kind.stories.map === 'function') || kind.stories.length === 0) {
            console.log(colors.yellow('WARNING: Invalid kind format. Skipping.'));
            console.log(kind);
            return null;
          }
          return {
            kind: kind.kind,
            stories: compact(kind.stories.map(function(story) {
              // check story format
              if (typeof story !== 'object' || !story.name || typeof story.name !== 'string') {
                console.log(colors.yellow('WARNING: Invalid story format in \'' + kind.kind + '\'. Skipping story.'));
                console.log(kind);
                return null;
              }
              var obj = {
                name: story.name
              };
              if (typeof story.render === 'function') {
                try {
                  var result = story.render(kind);

                  // check if <Screener> is a wrapping component
                  if (result && result.props) {
                    if (result.type && result.type.name === 'Screener') {
                      // get steps
                      obj.steps = result.props.steps;
                    } else if (result.props.initialContent && result.props.initialContent.props && result.props.initialContent.props.children && result.props.initialContent.props.children.props && result.props.initialContent.props.children.type && result.props.initialContent.props.children.type.name === 'Screener') {
                      // get steps
                      obj.steps = result.props.initialContent.props.children.props.steps;
                    }
                  }
                } catch(ex) {
                  if (options && options.debug) {
                    console.error(colors.red('Error processing render() method of:'), story);
                    console.error(colors.red(ex.stack || ex.message || ex.toString()));
                  }
                }
              }
              return obj;
            }))
          };
        }));
      }
      return storybook;
    });
};

exports.run = require('./runner').run;
<|endoftext|>


<commit_before>
// Wait for user to finish typing
// callback: The callback function
// wait: The number of milliseconds to wait after the the last key press before firing the callback
// highlight: Highlights the element when it receives focus
// allowSubmit: Allows a non-multiline element to be submitted (enter key) regardless of captureLength
// captureLength: Minimum # of characters necessary to fire the callback

$(document).ready(function() {

	$('#street').typeWatch({
		captureLength: 2,
		wait: 1750,
    		highlight: true,
		callback: function(value) {
			//alert("typing finished");
			street_to_geo(value);
		}
	});
});

function street_to_geo(street){
      //encodes the street string into url friendly format
      var street_encoded = encodeURIComponent(street);
      var uri = "http://nominatim.openstreetmap.org/search/" + street_encoded + "?format=json";
      //alert(uri);
      //makes the the jquery call and gets json back
      $.getJSON(uri, function(data) {
        //make js obj containing lat and long
        var obj = {latitude: data[0].lat, longitude: data[0].lon};
        alert(obj.latitude + " " + obj.longitude);
        //return obj;
      });
}

function calc_distance(lat1, lon1, lat2, lon2) {
	var unit = "K";
	var radlat1 = Math.PI * lat1/180;
	var radlat2 = Math.PI * lat2/180;
	var theta = lon1-lon2;
	var radtheta = Math.PI * theta/180;
	var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
	dist = Math.acos(dist);
	dist = dist * 180/Math.PI;
	dist = dist * 60 * 1.1515;
	if (unit=="K") { dist = dist * 1.609344; }
	if (unit=="N") { dist = dist * 0.8684; }
	return dist;
}

function get_places(lat, long, category) {
	var url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json";
	var method = "POST";
	var postData = "";	// TODO get key
	postData += "location=" + lat + "," + long;
	postData += "radius=5000";	// 5km, could be changed or added as a configurable later
	postData += "type=" + category;

	// if it is not true, it'll block ALL execution waiting for server response.
	var shouldBeAsync = true;

	var request = new XMLHttpRequest();

	// This function attached to the XMLHttpRequest "onload" property specifies how the HTTP response will be handled.
	// request.onreadystatechange can also be used if this doesn't work
	request.onload = function () {
		// You can get all kinds of information about the HTTP response.
		var status = request.status; // HTTP response status, e.g., 200 for "200 OK"
		var data = request.responseText; // Returned data, e.g., an HTML document.

		var jsObj = null;

		if (status == 200) {
			jsObj = data.results;
			add_details(jsObj, lat, long);
			sort_json(jsObj, 'rating_over_distance', false);	// false because we want descending order
		}

		// TODO: call whatever needs to use the jsObj
	}

	request.open(method, url, shouldBeAsync);

	request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");

	// Actually sends the request to the server.
	request.send(postData);
}

function add_details(json_object, lat, long) {
	for ( x in json_object) {
		json_object[x].distance = calc_distance(lat, lon, json_object[x].geometry.location.lat, json_object[x].geometry.location.lng);
		json_object[x].rating_over_distance = json_object[x].rating/json_object[x].distance;
	}
}

function sort_json(json_object, key_to_sort_by, ascending) {
    function sortByKey(a, b) {
        var x = a[key_to_sort_by];
        var y = b[key_to_sort_by];
        if (ascending ==  true) {
        	return ((x < y) ? -1 : ((x > y) ? 1 : 0));
        } else {
        	return ((x > y) ? -1 : ((x < y) ? 1 : 0));
        }
    }

    json_object.sort(sortByKey);
}

//returns a Coordinate, could add some other functionality of what to do when geolocation is not supported
var pos;
function get_my_location(){
	var options = {
	  enableHighAccuracy: true
	};
	if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(function(position) {
        pos = {
          lat: position.coords.latitude,
          lng: position.coords.longitude
        };
      },
      function(err){},
      options);
    }
	return pos;
}

function get_weather(lat, lon){

	//if the function does not work, maybe the get_json.php should be in root, or path should be js/get_json.php

    var api_url = "js/get_json.php?";
    var type = "type=weather"

	api_request = api_url;
    api_request += type;
    api_request += "&lat="
    api_request += lat;
    api_request += "&lon="
    api_request += lon;

    //document.write(api_request);

    $(function () {
        $.getJSON(
            api_request,
            function (data) {
                $("#reply").html(JSON.stringify(data));
                return(JSON.stringify(data.weather[0].main));
            });
    });

}
<commit_msg>fixed path on main.js/get_weather(lat,lon) now it should point to the right direction (get_json.php)<commit_after>
// Wait for user to finish typing
// callback: The callback function
// wait: The number of milliseconds to wait after the the last key press before firing the callback
// highlight: Highlights the element when it receives focus
// allowSubmit: Allows a non-multiline element to be submitted (enter key) regardless of captureLength
// captureLength: Minimum # of characters necessary to fire the callback

$(document).ready(function() {

	$('#street').typeWatch({
		captureLength: 2,
		wait: 1750,
    		highlight: true,
		callback: function(value) {
			//alert("typing finished");
			street_to_geo(value);
		}
	});
});

function street_to_geo(street){
      //encodes the street string into url friendly format
      var street_encoded = encodeURIComponent(street);
      var uri = "http://nominatim.openstreetmap.org/search/" + street_encoded + "?format=json";
      //alert(uri);
      //makes the the jquery call and gets json back
      $.getJSON(uri, function(data) {
        //make js obj containing lat and long
        var obj = {latitude: data[0].lat, longitude: data[0].lon};
        alert(obj.latitude + " " + obj.longitude);
        //return obj;
      });
}

function calc_distance(lat1, lon1, lat2, lon2) {
	var unit = "K";
	var radlat1 = Math.PI * lat1/180;
	var radlat2 = Math.PI * lat2/180;
	var theta = lon1-lon2;
	var radtheta = Math.PI * theta/180;
	var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
	dist = Math.acos(dist);
	dist = dist * 180/Math.PI;
	dist = dist * 60 * 1.1515;
	if (unit=="K") { dist = dist * 1.609344; }
	if (unit=="N") { dist = dist * 0.8684; }
	return dist;
}

function get_places(lat, long, category) {
	var url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json";
	var method = "POST";
	var postData = "";	// TODO get key
	postData += "location=" + lat + "," + long;
	postData += "radius=5000";	// 5km, could be changed or added as a configurable later
	postData += "type=" + category;

	// if it is not true, it'll block ALL execution waiting for server response.
	var shouldBeAsync = true;

	var request = new XMLHttpRequest();

	// This function attached to the XMLHttpRequest "onload" property specifies how the HTTP response will be handled.
	// request.onreadystatechange can also be used if this doesn't work
	request.onload = function () {
		// You can get all kinds of information about the HTTP response.
		var status = request.status; // HTTP response status, e.g., 200 for "200 OK"
		var data = request.responseText; // Returned data, e.g., an HTML document.

		var jsObj = null;

		if (status == 200) {
			jsObj = data.results;
			add_details(jsObj, lat, long);
			sort_json(jsObj, 'rating_over_distance', false);	// false because we want descending order
		}

		// TODO: call whatever needs to use the jsObj
	}

	request.open(method, url, shouldBeAsync);

	request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");

	// Actually sends the request to the server.
	request.send(postData);
}

function add_details(json_object, lat, long) {
	for ( x in json_object) {
		json_object[x].distance = calc_distance(lat, lon, json_object[x].geometry.location.lat, json_object[x].geometry.location.lng);
		json_object[x].rating_over_distance = json_object[x].rating/json_object[x].distance;
	}
}

function sort_json(json_object, key_to_sort_by, ascending) {
    function sortByKey(a, b) {
        var x = a[key_to_sort_by];
        var y = b[key_to_sort_by];
        if (ascending ==  true) {
        	return ((x < y) ? -1 : ((x > y) ? 1 : 0));
        } else {
        	return ((x > y) ? -1 : ((x < y) ? 1 : 0));
        }
    }

    json_object.sort(sortByKey);
}

//returns a Coordinate, could add some other functionality of what to do when geolocation is not supported
var pos;
function get_my_location(){
	var options = {
	  enableHighAccuracy: true
	};
	if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(function(position) {
        pos = {
          lat: position.coords.latitude,
          lng: position.coords.longitude
        };
      },
      function(err){},
      options);
    }
	return pos;
}

function get_weather(lat, lon){

	//if the function does not work, maybe the get_json.php should be in root, or path should be js/get_json.php

    var api_url = "get_json.php?";
    var type = "type=weather"

	api_request = api_url;
    api_request += type;
    api_request += "&lat="
    api_request += lat;
    api_request += "&lon="
    api_request += lon;

    //document.write(api_request);

    $(function () {
        $.getJSON(
            api_request,
            function (data) {
                $("#reply").html(JSON.stringify(data));
                return(JSON.stringify(data.weather[0].main));
            });
    });

}
<|endoftext|>


<commit_before>'use strict';

const FreeSurfer = require('freesurfer-parser');
const pkg = require('../package.json');
const localRunner = require('./local');
const remoteRunner = require('./remote');
const regression = require('./regression');
const n = require('numeric');
const distributions = require('distributions');
const DEFAULT_MAX_ITERATIONS = require('./constants').DEFAULT_MAX_ITERATIONS;

module.exports = {
  name: pkg.name,
  version: pkg.version,
  plugins: ['group-step', 'inputs'],
  local: [
    {
      type: 'function',
      fn(opts) {
        // simulate pre-processing step.  we actually are passing in
        // pre-processed data. required s.t. remote compute node can assert
        // that all users have correct data shape (e.g. num features)
        const rslt = localRunner.preprocess(opts);
        console.log('pre-processing complete.'); // eslint-disable-line no-console
        return rslt;
      },
      verbose: true,
      inputs: [{
        help: 'Select Freesurfer region(s) of interest',
        label: 'Freesurfer ROI',
        type: 'select',
        values: FreeSurfer.validFields,
      }, {
        defaultValue: DEFAULT_MAX_ITERATIONS,
        label: 'Iteration count',
        type: 'number',
      }, {
        defaultValue: [{
          name: 'Is Control?',
          type: 'boolean',
        }],
        label: 'Covariates',
        /**
         * @todo Determine a better `type` for this input. Something like
         * "data-map" or "covariate-map" or…something.
         */
        type: 'covariates',
      }],
    }, {
      type: 'function',
      fn(opts) {
      // if W doesn't merge, return run(), if W merge, return statistic()

        /* eslint-disable no-console */
        console.log('opts.remoteResult.data.endOfIteration is', opts.remoteResult.data.endOfIteration);
        console.log('opts.remoteResult.data.statisticStep is', opts.remoteResult.data.statisticStep);
        /* eslint-enable no-console */

        if (
          (opts.remoteResult.data.endOfIteration === true) &&
          (opts.remoteResult.data.statisticStep === 0)
        ) {
          // step 0 calculate local statistics and localYMean
          const biasedX = opts.previousData.biasedX;
          const y = opts.previousData.y;
          const localCount = y.length;
          const betaVector = regression.oneShot(biasedX, y);
          const rSquared = regression.rSquared(biasedX, y, betaVector);
          const tValue = regression.tValue(biasedX, y, betaVector);
          /* eslint-disable new-cap */
          const tdist = distributions.Studentt(localCount - betaVector.length);
          /* eslint-enable new-cap */
          const tcdf = tValue.map(r => tdist.cdf(r));
          const pValue = n.mul(2, n.sub(1, tcdf));
          const localMeanY = n.sum(y) / localCount;

          return {
            betaVector,
            localCount,
            localMeanY,
            rSquared,
            tValue,
            pValue,
            biasedX,
            y,
            endOfIteration: true,
            statisticStep: 0,
          };
        } else if (
          opts.remoteResult.data.endOfIteration === true &&
          opts.remoteResult.data.statisticStep === 1
        ) {
          // step 1 receive the globalMeanY and currW, then calculate sseLocal,
          // sstLocal and varXLocal
          const betaVector = opts.previousData.betaVector;
          const globalMeanY = opts.remoteResult.data.globalMeanY;
          const currW = opts.remoteResult.data.currW;
          const biasedX = opts.previousData.biasedX;
          const y = opts.previousData.y;
          const rSquared = opts.previousData.rSquared;
          const tValue = opts.previousData.tValue;
          const pValue = opts.previousData.pValue;
          const localCount = y.length;

          // calculate the local r squred and t value for averageBetaVector)
          const rSquaredLocal = regression.rSquared(biasedX, y, currW);
          const tValueLocal = regression.tValue(biasedX, y, currW);
          /* eslint-disable new-cap */
          const tdist = distributions.Studentt(localCount - betaVector.length);
          /* eslint-enable new-cap */
          const tcdf = tValueLocal.map(r => tdist.cdf(r));
          const pValueLocal = n.mul(2, n.sub(1, tcdf));

          // calculate sseLocal and sstLocal
          const sseLocal = n.sum(n.pow(n.sub(y, n.dot(biasedX, currW)), 2));
          const sstLocal = n.sum(n.pow(n.sub(y, n.rep(n.dim(y), globalMeanY)), 2));

          // calculate varXLocalMatrix
          const varXLocalMatrix = n.dot(n.transpose(biasedX), biasedX);

          /* eslint-disable no-console */
          console.log('local r squared for currW', rSquaredLocal);
          console.log('local t Values for currW', tValueLocal);
          console.log('local p Values for currW', pValueLocal);
          /* eslint-enable no-console */

          return {
            betaVector,
            sseLocal,
            sstLocal,
            varXLocalMatrix,
            currW,
            localCount,
            rSquared,
            tValue,
            pValue,
            rSquaredLocal,
            tValueLocal,
            pValueLocal,
            endOfIteration: true,
            statisticStep: 1,
          };
        }

        return localRunner.run(opts);
      },
      verbose: true,
    },
  ],
  remote: {
    type: 'function',
    fn(opts) {
      if (
        opts.userResults[0].data.endOfIteration === true &&
        opts.userResults[0].data.statisticStep === 0
      ) {
        // if statisticStep==0, remote node calculates the globalMeanY and return it to local node
        const userResults = opts.userResults;

        // Not all user results contain betas. Return early.
        if (userResults.some(userResult => !((userResult || {}).data || {}).betaVector)) {
          return {};
        }

        // calculate averageBetaVector
        const currW = opts.previousData.currW;

        // calculate globalMeanY
        const siteCount = userResults.length;
        let totalY = 0;
        let globalYCount = 0;

        for (let i = 0; i < siteCount; i += 1) {
          totalY += userResults[i].data.localMeanY * userResults[i].data.localCount;
          globalYCount += userResults[i].data.localCount;
        }

        const globalMeanY = totalY / globalYCount;

        /* eslint-disable no-console */
        console.log('currW :', currW);
        console.log('globalMeanY is :', globalMeanY);
        /* eslint-enable no-console */

        return { currW,
          globalMeanY,
          endOfIteration: true,
          statisticStep: 1,
        };
      } else if (
        opts.userResults[0].data.endOfIteration === true &&
        opts.userResults[0].data.statisticStep === 1
      ) {
        // if statisticStep==1, remote node calculates the global statistics

        const userResults = opts.userResults;

        // get passed parameters from local nodes
        const currW = opts.previousData.currW;
        const betaVectorLocal = userResults.map(r => r.data.betaVector);
        const rSquaredLocalOriginal = userResults.map(r => r.data.rSquared);
        const tValueLocalOriginal = userResults.map(r => r.data.tValue);
        const pValueLocalOriginal = userResults.map(r => r.data.pValue);
        const rSquaredLocal = userResults.map(r => r.data.rSquaredLocal);
        const tValueLocal = userResults.map(r => r.data.tValueLocal);
        const pValueLocal = userResults.map(r => r.data.pValueLocal);

        // calculate global parameters
        const sseGlobal = userResults.reduce(
          (sum, userResult) => sum + userResult.data.sseLocal, 0
        );
        const sstGlobal = userResults.reduce(
          (sum, userResult) => sum + userResult.data.sstLocal, 0
        );
        const globalYCount = userResults.reduce(
          (sum, userResult) => sum + userResult.data.localCount, 0
        );

        const varError = (1 / (globalYCount - currW.length)) * sseGlobal;
        const seBetaGlobal = [];
        const tValueGlobal = [];

        // calculate tValueGlobal
        var varXGlobalMatrix=n.rep([currW.length,currW.length],0);

        for (let i=0; i < userResults.length; i += 1) {
          varXGlobalMatrix = n.add(varXGlobalMatrix, userResults[i].data.varXLocalMatrix);
        };

        console.log('varXGlobalMatrix is',varXGlobalMatrix);

        const varBetaGlobal = n.mul(n.inv(varXGlobalMatrix),varError);

        for (let i=0; i < currW.length; i +=1) {
             seBetaGlobal[i] = Math.sqrt(varBetaGlobal[i][i]);
             tValueGlobal[i] = currW[i] / seBetaGlobal[i];
         }

        // calculate r squared global
        const rSquaredGlobal = 1 - (sseGlobal / sstGlobal);

        // add t to p value transformation //
        /* eslint-disable new-cap */
        const tdist = distributions.Studentt(globalYCount - currW.length);
        /* eslint-enable new-cap */
        const tcdf = tValueGlobal.map(r => tdist.cdf(r));
        const pValueGlobal = n.mul(2, (n.sub(1, tcdf))); // two tail pValue

        /* eslint-disable no-console */
        console.log('The global r squared for currW :', rSquaredGlobal);
        console.log('The global t Values for currW :', tValueGlobal);
        console.log('The global p Values for currW :', pValueGlobal);
        /* eslint-enable no-console */

        return {
          betaVectorLocal,
          currW,
          rSquaredLocalOriginal,
          tValueLocalOriginal,
          pValueLocalOriginal,
          rSquaredLocal,
          tValueLocal,
          pValueLocal,
          rSquaredGlobal,
          tValueGlobal,
          pValueGlobal,
          complete: true,
        };
      }

      return remoteRunner.run(opts);
    },
    verbose: true,
  },
};
<commit_msg>Fix linting errors.<commit_after>'use strict';

const FreeSurfer = require('freesurfer-parser');
const pkg = require('../package.json');
const localRunner = require('./local');
const remoteRunner = require('./remote');
const regression = require('./regression');
const n = require('numeric');
const distributions = require('distributions');
const DEFAULT_MAX_ITERATIONS = require('./constants').DEFAULT_MAX_ITERATIONS;

module.exports = {
  name: pkg.name,
  version: pkg.version,
  plugins: ['group-step', 'inputs'],
  local: [
    {
      type: 'function',
      fn(opts) {
        // simulate pre-processing step.  we actually are passing in
        // pre-processed data. required s.t. remote compute node can assert
        // that all users have correct data shape (e.g. num features)
        const rslt = localRunner.preprocess(opts);
        console.log('pre-processing complete.'); // eslint-disable-line no-console
        return rslt;
      },
      verbose: true,
      inputs: [{
        help: 'Select Freesurfer region(s) of interest',
        label: 'Freesurfer ROI',
        type: 'select',
        values: FreeSurfer.validFields,
      }, {
        defaultValue: DEFAULT_MAX_ITERATIONS,
        label: 'Iteration count',
        type: 'number',
      }, {
        defaultValue: [{
          name: 'Is Control?',
          type: 'boolean',
        }],
        label: 'Covariates',
        /**
         * @todo Determine a better `type` for this input. Something like
         * "data-map" or "covariate-map" or…something.
         */
        type: 'covariates',
      }],
    }, {
      type: 'function',
      fn(opts) {
      // if W doesn't merge, return run(), if W merge, return statistic()

        /* eslint-disable no-console */
        console.log('opts.remoteResult.data.endOfIteration is', opts.remoteResult.data.endOfIteration);
        console.log('opts.remoteResult.data.statisticStep is', opts.remoteResult.data.statisticStep);
        /* eslint-enable no-console */

        if (
          (opts.remoteResult.data.endOfIteration === true) &&
          (opts.remoteResult.data.statisticStep === 0)
        ) {
          // step 0 calculate local statistics and localYMean
          const biasedX = opts.previousData.biasedX;
          const y = opts.previousData.y;
          const localCount = y.length;
          const betaVector = regression.oneShot(biasedX, y);
          const rSquared = regression.rSquared(biasedX, y, betaVector);
          const tValue = regression.tValue(biasedX, y, betaVector);
          /* eslint-disable new-cap */
          const tdist = distributions.Studentt(localCount - betaVector.length);
          /* eslint-enable new-cap */
          const tcdf = tValue.map(r => tdist.cdf(r));
          const pValue = n.mul(2, n.sub(1, tcdf));
          const localMeanY = n.sum(y) / localCount;

          return {
            betaVector,
            localCount,
            localMeanY,
            rSquared,
            tValue,
            pValue,
            biasedX,
            y,
            endOfIteration: true,
            statisticStep: 0,
          };
        } else if (
          opts.remoteResult.data.endOfIteration === true &&
          opts.remoteResult.data.statisticStep === 1
        ) {
          // step 1 receive the globalMeanY and currW, then calculate sseLocal,
          // sstLocal and varXLocal
          const betaVector = opts.previousData.betaVector;
          const globalMeanY = opts.remoteResult.data.globalMeanY;
          const currW = opts.remoteResult.data.currW;
          const biasedX = opts.previousData.biasedX;
          const y = opts.previousData.y;
          const rSquared = opts.previousData.rSquared;
          const tValue = opts.previousData.tValue;
          const pValue = opts.previousData.pValue;
          const localCount = y.length;

          // calculate the local r squred and t value for averageBetaVector)
          const rSquaredLocal = regression.rSquared(biasedX, y, currW);
          const tValueLocal = regression.tValue(biasedX, y, currW);
          /* eslint-disable new-cap */
          const tdist = distributions.Studentt(localCount - betaVector.length);
          /* eslint-enable new-cap */
          const tcdf = tValueLocal.map(r => tdist.cdf(r));
          const pValueLocal = n.mul(2, n.sub(1, tcdf));

          // calculate sseLocal and sstLocal
          const sseLocal = n.sum(n.pow(n.sub(y, n.dot(biasedX, currW)), 2));
          const sstLocal = n.sum(n.pow(n.sub(y, n.rep(n.dim(y), globalMeanY)), 2));

          // calculate varXLocalMatrix
          const varXLocalMatrix = n.dot(n.transpose(biasedX), biasedX);

          /* eslint-disable no-console */
          console.log('local r squared for currW', rSquaredLocal);
          console.log('local t Values for currW', tValueLocal);
          console.log('local p Values for currW', pValueLocal);
          /* eslint-enable no-console */

          return {
            betaVector,
            sseLocal,
            sstLocal,
            varXLocalMatrix,
            currW,
            localCount,
            rSquared,
            tValue,
            pValue,
            rSquaredLocal,
            tValueLocal,
            pValueLocal,
            endOfIteration: true,
            statisticStep: 1,
          };
        }

        return localRunner.run(opts);
      },
      verbose: true,
    },
  ],
  remote: {
    type: 'function',
    fn(opts) {
      if (
        opts.userResults[0].data.endOfIteration === true &&
        opts.userResults[0].data.statisticStep === 0
      ) {
        // if statisticStep==0, remote node calculates the globalMeanY and return it to local node
        const userResults = opts.userResults;

        // Not all user results contain betas. Return early.
        if (userResults.some(userResult => !((userResult || {}).data || {}).betaVector)) {
          return {};
        }

        // calculate averageBetaVector
        const currW = opts.previousData.currW;

        // calculate globalMeanY
        const siteCount = userResults.length;
        let totalY = 0;
        let globalYCount = 0;

        for (let i = 0; i < siteCount; i += 1) {
          totalY += userResults[i].data.localMeanY * userResults[i].data.localCount;
          globalYCount += userResults[i].data.localCount;
        }

        const globalMeanY = totalY / globalYCount;

        /* eslint-disable no-console */
        console.log('currW :', currW);
        console.log('globalMeanY is :', globalMeanY);
        /* eslint-enable no-console */

        return { currW,
          globalMeanY,
          endOfIteration: true,
          statisticStep: 1,
        };
      } else if (
        opts.userResults[0].data.endOfIteration === true &&
        opts.userResults[0].data.statisticStep === 1
      ) {
        // if statisticStep==1, remote node calculates the global statistics

        const userResults = opts.userResults;

        // get passed parameters from local nodes
        const currW = opts.previousData.currW;
        const betaVectorLocal = userResults.map(r => r.data.betaVector);
        const rSquaredLocalOriginal = userResults.map(r => r.data.rSquared);
        const tValueLocalOriginal = userResults.map(r => r.data.tValue);
        const pValueLocalOriginal = userResults.map(r => r.data.pValue);
        const rSquaredLocal = userResults.map(r => r.data.rSquaredLocal);
        const tValueLocal = userResults.map(r => r.data.tValueLocal);
        const pValueLocal = userResults.map(r => r.data.pValueLocal);

        // calculate global parameters
        const sseGlobal = userResults.reduce(
          (sum, userResult) => sum + userResult.data.sseLocal, 0
        );
        const sstGlobal = userResults.reduce(
          (sum, userResult) => sum + userResult.data.sstLocal, 0
        );
        const globalYCount = userResults.reduce(
          (sum, userResult) => sum + userResult.data.localCount, 0
        );

        const varError = (1 / (globalYCount - currW.length)) * sseGlobal;
        const seBetaGlobal = [];
        const tValueGlobal = [];

        // calculate tValueGlobal
        let varXGlobalMatrix = n.rep([currW.length, currW.length], 0);

        for (let i = 0; i < userResults.length; i += 1) {
          varXGlobalMatrix = n.add(varXGlobalMatrix, userResults[i].data.varXLocalMatrix);
        }

        /* eslint-disable no-console */
        console.log('varXGlobalMatrix is', varXGlobalMatrix);
        /* eslint-enable no-console */

        const varBetaGlobal = n.mul(n.inv(varXGlobalMatrix), varError);

        for (let i = 0; i < currW.length; i += 1) {
          seBetaGlobal[i] = Math.sqrt(varBetaGlobal[i][i]);
          tValueGlobal[i] = currW[i] / seBetaGlobal[i];
        }

        // calculate r squared global
        const rSquaredGlobal = 1 - (sseGlobal / sstGlobal);

        // add t to p value transformation //
        /* eslint-disable new-cap */
        const tdist = distributions.Studentt(globalYCount - currW.length);
        /* eslint-enable new-cap */
        const tcdf = tValueGlobal.map(r => tdist.cdf(r));
        const pValueGlobal = n.mul(2, (n.sub(1, tcdf))); // two tail pValue

        /* eslint-disable no-console */
        console.log('The global r squared for currW :', rSquaredGlobal);
        console.log('The global t Values for currW :', tValueGlobal);
        console.log('The global p Values for currW :', pValueGlobal);
        /* eslint-enable no-console */

        return {
          betaVectorLocal,
          currW,
          rSquaredLocalOriginal,
          tValueLocalOriginal,
          pValueLocalOriginal,
          rSquaredLocal,
          tValueLocal,
          pValueLocal,
          rSquaredGlobal,
          tValueGlobal,
          pValueGlobal,
          complete: true,
        };
      }

      return remoteRunner.run(opts);
    },
    verbose: true,
  },
};
<|endoftext|>


<commit_before>/* Nitro Core
 *
 * Copyright (C) 2012 Caffeinated Code <http://caffeinatedco.de>
 * Copyright (C) 2012 Jono Cooper
 * Copyright (C) 2012 George Czabania
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Neither the name of Caffeinated Code nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

//When everything is ready
$(document).ready(function() {
	//Cache Selectors
	ui.initLoad();
	ui.reload();
});

var ui = {
	initLoad: function() {
		//Buttons
		$('#smartlists').html('
Focus

');
		ui.lists.draw('today');
		ui.lists.draw('next');
		ui.lists.draw('logbook');
		ui.lists.draw('all');

		$$.document.append(ui.buttons.taskAddBTN, $('#tasks .panel'));
		$$.document.append(ui.buttons.taskDeleteBTN, $('#tasks .panel'));

		//Splitter
		$('#content').splitter({sizeLeft: true});
		var height = $(window).height(),
			width = $(window).width()

		$(window).resize(function() {
			//Causes lag without it?
			if (height != $(window).height() || width != $(window).width()) {
				//Redefines
				height = $(window).height(),
				width = $(window).width()

				$('#content').trigger('resize');
			}
		});
	},
	session: {
		selected: 'today'
	},
	reload: function() {
		//Populates Template
		$('#lists').html('
Lists

');
		$$.document.append(ui.buttons.listAddBTN, $('#lists h2'));
		for (var i=0; i<core.storage.lists.order.length; i++) {
			ui.lists.draw(core.storage.lists.order[i]);
		}
		//Simulates Click on selected list
		$('#L' + ui.session.selected).click();
	},
	lists: {
		//Draws a list to the DOM
		draw: function(listId) {
			if (typeof(listId) == 'string') {

				switch(listId) {
					case 'all':
						var obj = $$(ui.templates.listTemplate, {id: listId, name: listId, count: core.list('all').populate().length});
						break;
					default:
						var obj = $$(ui.templates.listTemplate, {id: listId, name: listId});
						break;
				}

				$$.document.append(obj, $('#smartlists ul'));
			} else {
				var list = core.storage.lists.items[listId];
				var obj = $$(ui.templates.listTemplate, {id: listId, name: list.name, count: list.order.length});
				$$.document.append(obj, $('#lists ul'));
			}
			$(obj.view.$()).attr('id', 'L' + obj.model.get('id'))
		},
		update: function(listId) {
			var list = core.storage.lists.items[listId];
			return {
				count: function() {

					// Update specified list
					$('#L' + listId).find('.count').html(list.order.length);

					// Update the All Tasks list
					$('#Lall').find('.count').html(core.list('all').populate().length);
				}
			}
		}
	},
	templates: {
		listTemplate: $$({}, '
<button class="delete">Delete</button>
', {
			'click &': function() {
				//Selected List
				$('#sidebar .selected').removeClass('selected');
				$(this.view.$()).addClass('selected');
				ui.session.selected = this.model.get('id');

				//Gets list id & populates
				$('#tasks .content').empty().html('
' + this.model.get('name') + '

')
				var tasks = core.list(this.model.get('id')).populate();

				//Loops and adds each task to a tmp view
				var tmpView = $$({});
				for (var i=0; i<tasks.length; i++) {
					//Makes it nice
					var data = core.storage.tasks[tasks[i]];

					//Checked Tasks
					var logged = 'checkbox';
					if (data.list == 'logbook') {
						logged += ' checked';
					}

					tmpView.append(
						$$(ui.templates.task.compressed, {
							id: tasks[i],
							content: data.content,
							notes: data.notes,
							date: data.date,
							priority: data.priority,
							logged: logged
						})
					);
				}
				$$.document.append(tmpView, $('#tasks ul'));
			},
			'dblclick .name': function() {
				var name = prompt("New name", this.model.get('name'));
				if(name) {
					core.storage.lists.items[this.model.get('id')].name = name;
					this.model.set({name: name});
					core.storage.save();
				}
			}
		}),

		task: {
			compressed: $$({}, '

', {

				'click &': function(e) {

					//No event handler things in input or selected.
					if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA' || e.target.nodeName == 'BUTTON' || $(e.target).hasClass('checkbox')) {
						return;
					}

					if (e.metaKey) {
						$(this.view.$()).toggleClass('selected');
					} else {
						$('#tasks .selected').removeClass('selected');
						$(this.view.$()).addClass('selected');
					}
				},

				'click .checkbox': function(e) {
					//Changes Appearance
					$(e.currentTarget).toggleClass('checked')

					//Moves it around for real.
					if($(e.currentTarget).hasClass('checked')) {
						core.task(this.model.get('id')).move('logbook');
					} else {
						core.task(this.model.get('id')).move(ui.session.selected);
					}
				},

				'dblclick &': function(e) {
					//Cache the selector
					var view = $(this.view.$());

					//No event handler things in input or selected.
					if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA' || e.target.nodeName == 'BUTTON' || $(e.target).hasClass('checkbox')) {
						return;
					}

					//Checks if it's expanded & if it isn't expand it.
					if (!view.hasClass('expanded')) {
						//Clear out the Dom
						view.empty();
						//Checked Tasks
						var logged = 'checkbox';
						if (core.storage.tasks[this.model.get('id')].list == 'logbook') {
							logged += ' checked';
						}

						$$.document.append(
							$$(ui.templates.task.expand,
								{id: this.model.get('id'),
								content: this.model.get('content'),
								notes: this.model.get('notes'),
								date: this.model.get('date'),
								priority: this.model.get('priority'),
								logged: logged
							}), view);

						view.addClass('expanded').height(view.height() + view.removeClass('selected').children('div').children('.hidden').show(0).height());

					} else {
						//Collapses
						view.removeClass('expanded').css('height', '');
						var id = this.model.get('id');

						setTimeout(function() {
							var orig = view.prev()
							view.remove();
							var data = core.storage.tasks[id];

							//Checked Tasks
							var logged = 'checkbox';
							if (data.list == 'logbook') {
								logged += ' checked';
							}

							var model = $$(ui.templates.task.compressed, {
								id: id,
								content: data.content,
								notes: data.notes,
								date: data.date,
								priority: data.priority,
								logged: logged
							})

							//If it's the first task in a list, .prev won't work
							if (orig.length == 0) {
								$$.document.prepend(model, $('#tasks ul'));
							} else {
								$$.document.after(model, orig);
							}

						}, 150);
					}
				}
			}),

			expand: $$({}, '

<input data-bind="content" type="text"><button data-bind="priority"></button><input placeholder="Due Date" type="text" class="date">
<textarea data-bind="notes"></textarea>

', {

				'create': function() {
					//Sets the localized date =D
					$(this.view.$()).children('.date').datepicker().datepicker('setDate', new Date(this.model.get('date')));
				},

				'change input[data-bind=content]': function() {
					core.storage.tasks[this.model.get('id')].content = this.model.get('content');
					core.storage.save();
				},

				'change .date': function() {
					var view = $(this.view.$());
					core.storage.tasks[this.model.get('id')].date = view.children('.date').datepicker("getDate").getTime();
					core.storage.save();
				},

				'click button[data-bind=priority]': function() {
					var p = this.model.get('priority');

					if (p == 'none') {
						this.model.set({priority: 'low'});
					} else if (p == 'low') {
						this.model.set({priority: 'medium'});
					} else if (p == 'medium') {
						this.model.set({priority: 'high'});
					} else if (p == 'high') {
						this.model.set({priority: 'none'});
					}
				},

				'change textarea[data-bind=notes]': function() {
					core.storage.tasks[this.model.get('id')].notes = this.model.get('notes');
					core.storage.save();
				}
			})
		}
	},
	buttons: {
		//Buttons
		listAddBTN: $$({name: 'Add List'}, '<button data-bind="name"/>', {
			'click &': function() {
				//Adds a list with the core
				var listId = core.list().add('New List');
				ui.lists.draw(listId);

				//Selects List
				$('#L' + listId).click();
			}
		}),
		taskAddBTN: $$({name: 'Add'}, '<button data-bind="name"/>', {
			'click &': function() {
				var list = ui.session.selected;
				if (list != 'all') {
					//Adds a task with the core
					var taskId = core.task().add('New Task', list);
					var data = core.storage.tasks[taskId];

					//Checked Tasks
					var logged = 'checkbox';
					if (data.list == 'logbook') {
						logged += ' checked';
					}

					// Add to DOM
					$$.document.prepend(
						$$(ui.templates.task.compressed, {
							id: taskId,
							content: data.content,
							notes: data.notes,
							date: data.date,
							priority: data.priority,
							logged: logged
						}), $('#tasks ul')
					);

					// Update list count
					ui.lists.update(list).count();
				}
			}
		}),
		taskDeleteBTN: $$({name: 'Delete'}, '<button data-bind="name"/>', {
			'click &': function() {
				var selected = $('#tasks .selected'),
					lists = {};

				// Deletes from CLI
				for(var i = 0; i < selected.length; i++) {
					var taskId = Number($(selected[i]).removeClass('selected').attr('class'));
					lists[core.storage.tasks[taskId].list] = true;

					// Remove task
					core.task(taskId).move('trash');
				}

				// Update list count
				for(var key in lists) {
					ui.lists.update(key).count();
				}

				// Remove from DOM
				selected.remove();
			}
		})
	}
}
//This is the best plugin system in the world.
var plugin = {
	add: function(fn) {
		fn();
	}
}<commit_msg>Started deleting tasks<commit_after>/* Nitro Core
 *
 * Copyright (C) 2012 Caffeinated Code <http://caffeinatedco.de>
 * Copyright (C) 2012 Jono Cooper
 * Copyright (C) 2012 George Czabania
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Neither the name of Caffeinated Code nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

//When everything is ready
$(document).ready(function() {
	//Cache Selectors
	ui.initLoad();
	ui.reload();
});

var ui = {
	initLoad: function() {
		//Buttons
		$('#smartlists').html('
Focus

');
		ui.lists.draw('today');
		ui.lists.draw('next');
		ui.lists.draw('logbook');
		ui.lists.draw('all');

		$$.document.append(ui.buttons.taskAddBTN, $('#tasks .panel'));
		$$.document.append(ui.buttons.taskDeleteBTN, $('#tasks .panel'));

		//Splitter
		$('#content').splitter({sizeLeft: true});
		var height = $(window).height(),
			width = $(window).width()

		$(window).resize(function() {
			//Causes lag without it?
			if (height != $(window).height() || width != $(window).width()) {
				//Redefines
				height = $(window).height(),
				width = $(window).width()

				$('#content').trigger('resize');
			}
		});
	},
	session: {
		selected: 'today'
	},
	reload: function() {
		//Populates Template
		$('#lists').html('
Lists

');
		$$.document.append(ui.buttons.listAddBTN, $('#lists h2'));
		for (var i=0; i<core.storage.lists.order.length; i++) {
			ui.lists.draw(core.storage.lists.order[i]);
		}
		//Simulates Click on selected list
		$('#L' + ui.session.selected).click();
	},
	lists: {
		//Draws a list to the DOM
		draw: function(listId) {
			if (typeof(listId) == 'string') {

				switch(listId) {
					case 'all':
						var obj = $$(ui.templates.listTemplate, {id: listId, name: listId, count: core.list('all').populate().length});
						break;
					default:
						var obj = $$(ui.templates.listTemplate, {id: listId, name: listId});
						break;
				}

				$$.document.append(obj, $('#smartlists ul'));
			} else {
				var list = core.storage.lists.items[listId];
				var obj = $$(ui.templates.listTemplate, {id: listId, name: list.name, count: list.order.length});
				$$.document.append(obj, $('#lists ul'));
			}
			$(obj.view.$()).attr('id', 'L' + obj.model.get('id'))
		},
		update: function(listId) {
			var list = core.storage.lists.items[listId];
			return {
				count: function() {

					// Update specified list
					$('#L' + listId).find('.count').html(list.order.length);

					// Update the All Tasks list
					$('#Lall').find('.count').html(core.list('all').populate().length);
				}
			}
		}
	},
	templates: {
		listTemplate: $$({}, '
<button class="delete">Delete</button>
', {
			'click &': function() {
				//Selected List
				$('#sidebar .selected').removeClass('selected');
				$(this.view.$()).addClass('selected');
				ui.session.selected = this.model.get('id');

				//Gets list id & populates
				$('#tasks .content').empty().html('
' + this.model.get('name') + '

')
				var tasks = core.list(this.model.get('id')).populate();

				//Loops and adds each task to a tmp view
				var tmpView = $$({});
				for (var i=0; i<tasks.length; i++) {
					//Makes it nice
					var data = core.storage.tasks[tasks[i]];

					//Checked Tasks
					var logged = 'checkbox';
					if (data.list == 'logbook') {
						logged += ' checked';
					}

					tmpView.append(
						$$(ui.templates.task.compressed, {
							id: tasks[i],
							content: data.content,
							notes: data.notes,
							date: data.date,
							priority: data.priority,
							logged: logged
						})
					);
				}
				$$.document.append(tmpView, $('#tasks ul'));
			},
			'dblclick .name': function() {
				var name = prompt("New name", this.model.get('name'));
				if(name) {
					core.storage.lists.items[this.model.get('id')].name = name;
					this.model.set({name: name});
					core.storage.save();
				}
			},
			'click .delete': function() {
				$(this.view.$()).remove();
			}
		}),

		task: {
			compressed: $$({}, '

', {

				'click &': function(e) {

					//No event handler things in input or selected.
					if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA' || e.target.nodeName == 'BUTTON' || $(e.target).hasClass('checkbox')) {
						return;
					}

					if (e.metaKey) {
						$(this.view.$()).toggleClass('selected');
					} else {
						$('#tasks .selected').removeClass('selected');
						$(this.view.$()).addClass('selected');
					}
				},

				'click .checkbox': function(e) {
					//Changes Appearance
					$(e.currentTarget).toggleClass('checked')

					//Moves it around for real.
					if($(e.currentTarget).hasClass('checked')) {
						core.task(this.model.get('id')).move('logbook');
					} else {
						core.task(this.model.get('id')).move(ui.session.selected);
					}
				},

				'dblclick &': function(e) {
					//Cache the selector
					var view = $(this.view.$());

					//No event handler things in input or selected.
					if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA' || e.target.nodeName == 'BUTTON' || $(e.target).hasClass('checkbox')) {
						return;
					}

					//Checks if it's expanded & if it isn't expand it.
					if (!view.hasClass('expanded')) {
						//Clear out the Dom
						view.empty();
						//Checked Tasks
						var logged = 'checkbox';
						if (core.storage.tasks[this.model.get('id')].list == 'logbook') {
							logged += ' checked';
						}

						$$.document.append(
							$$(ui.templates.task.expand,
								{id: this.model.get('id'),
								content: this.model.get('content'),
								notes: this.model.get('notes'),
								date: this.model.get('date'),
								priority: this.model.get('priority'),
								logged: logged
							}), view);

						view.addClass('expanded').height(view.height() + view.removeClass('selected').children('div').children('.hidden').show(0).height());

					} else {
						//Collapses
						view.removeClass('expanded').css('height', '');
						var id = this.model.get('id');

						setTimeout(function() {
							var orig = view.prev()
							view.remove();
							var data = core.storage.tasks[id];

							//Checked Tasks
							var logged = 'checkbox';
							if (data.list == 'logbook') {
								logged += ' checked';
							}

							var model = $$(ui.templates.task.compressed, {
								id: id,
								content: data.content,
								notes: data.notes,
								date: data.date,
								priority: data.priority,
								logged: logged
							})

							//If it's the first task in a list, .prev won't work
							if (orig.length == 0) {
								$$.document.prepend(model, $('#tasks ul'));
							} else {
								$$.document.after(model, orig);
							}

						}, 150);
					}
				}
			}),

			expand: $$({}, '

<input data-bind="content" type="text"><button data-bind="priority"></button><input placeholder="Due Date" type="text" class="date">
<textarea data-bind="notes"></textarea>

', {

				'create': function() {
					//Sets the localized date =D
					$(this.view.$()).children('.date').datepicker().datepicker('setDate', new Date(this.model.get('date')));
				},

				'change input[data-bind=content]': function() {
					core.storage.tasks[this.model.get('id')].content = this.model.get('content');
					core.storage.save();
				},

				'change .date': function() {
					var view = $(this.view.$());
					core.storage.tasks[this.model.get('id')].date = view.children('.date').datepicker("getDate").getTime();
					core.storage.save();
				},

				'click button[data-bind=priority]': function() {
					var p = this.model.get('priority');

					if (p == 'none') {
						this.model.set({priority: 'low'});
					} else if (p == 'low') {
						this.model.set({priority: 'medium'});
					} else if (p == 'medium') {
						this.model.set({priority: 'high'});
					} else if (p == 'high') {
						this.model.set({priority: 'none'});
					}
				},

				'change textarea[data-bind=notes]': function() {
					core.storage.tasks[this.model.get('id')].notes = this.model.get('notes');
					core.storage.save();
				}
			})
		}
	},
	buttons: {
		//Buttons
		listAddBTN: $$({name: 'Add List'}, '<button data-bind="name"/>', {
			'click &': function() {
				//Adds a list with the core
				var listId = core.list().add('New List');
				ui.lists.draw(listId);

				//Selects List
				$('#L' + listId).click();
			}
		}),
		taskAddBTN: $$({name: 'Add'}, '<button data-bind="name"/>', {
			'click &': function() {
				var list = ui.session.selected;
				if (list != 'all') {
					//Adds a task with the core
					var taskId = core.task().add('New Task', list);
					var data = core.storage.tasks[taskId];

					//Checked Tasks
					var logged = 'checkbox';
					if (data.list == 'logbook') {
						logged += ' checked';
					}

					// Add to DOM
					$$.document.prepend(
						$$(ui.templates.task.compressed, {
							id: taskId,
							content: data.content,
							notes: data.notes,
							date: data.date,
							priority: data.priority,
							logged: logged
						}), $('#tasks ul')
					);

					// Update list count
					ui.lists.update(list).count();
				}
			}
		}),
		taskDeleteBTN: $$({name: 'Delete'}, '<button data-bind="name"/>', {
			'click &': function() {
				var selected = $('#tasks .selected'),
					lists = {};

				// Deletes from CLI
				for(var i = 0; i < selected.length; i++) {
					var taskId = Number($(selected[i]).removeClass('selected').attr('class'));
					lists[core.storage.tasks[taskId].list] = true;

					// Remove task
					core.task(taskId).move('trash');
				}

				// Update list count
				for(var key in lists) {
					ui.lists.update(key).count();
				}

				// Remove from DOM
				selected.remove();
			}
		})
	}
}
//This is the best plugin system in the world.
var plugin = {
	add: function(fn) {
		fn();
	}
}<|endoftext|>


<commit_before>/*
 * sshowjs
 * mjhoy | 2011
 *
 * ermm, beta...
 *
 */

(function ( $, undefined ) {

  // Helper function. Returns the indexes `k` items away from
  // index `n` for an array of length `len`. Useful for
  // getting nearby images in the slideshow to pre-load.
  var indexNeighbors = function ( n, k, len ) {
    if ( n >= len ) return undefined;
    var arr = [],
        i, x, r, offset;
    for ( i = 0, x = k * 2; i <= x; i += 1 ) {
      offset = ( i - k ) + n;
      if ( offset < 0 ) {
        r = len + offset;
      } else if ( offset >= len ) {
        r = offset - len;
      } else {
        r = offset;
      }
      if ( ( r >= 0 ) && ( r < len ) && ( arr.indexOf( r ) < 0 ) ) {
        arr.push( r );
      }
      if ( arr.length === len ) {
        break;
      }
    }
    return arr;
  }

  // The classes we will use in constructing new elements.
  var domClass = {
    sshow        : 'sshow',
    wrapper      : 'sshow_wrapper',
    stage        : 'sshow_stage',
    source       : 'sshow_source',
    status       : 'sshow_status',
    caption      : 'sshow_caption',
    navigation   : 'sshow_navigation',
    location     : 'sshow_location',
    nextLink     : 'sshow_nextLink',
    prevLink     : 'sshow_prevLink',
    placeholder  : 'sshow_placeholder',
    imageWrapper : 'sshow_image_wrapper'
  };

  // Same as `domClass` but with the dot in front, for CSS selectors.
  var sel = (function() {
    var obj = {};
    $.each( domClass, function ( k, v ) {
      obj[k] = '.' + v;
    } );
    return obj;
  })();

  // The default DOM set up of status and next/prev indicators.
  var statusSetup = function ( el ) {
    var status     = $( "
" ),
        navigation = $( "
" ),
        next       = $( "Next" ),
        location   = $( "" ),
        prev       = $( "Prev" ),
        caption    = $( "
" );
    // status
    // |- caption
    // `- navigation
    //    |- next
    //    |- location
    //    `- prev
    status.prepend( caption ).
      append( navigation.prepend( location ) );
    navigation.prepend( next ).append( prev );
    $( sel.wrapper, el ).prepend( status );
  };

  var handlerSetup = function ( el ) {
    var self = this;
    $( sel.nextLink, el ).click( function() { self.next(); } );
    $( sel.prevLink, el ).click( function() { self.prev(); } );
  };

  // Set the caption
  var setCaption = function ( caption, index ) {
    $( sel.caption, this.el ).html( caption );
  };

  // Set the location (e.g., "2 of 5")
  var setLocation = function ( index ) {
    var num = index + 1,
        total = this.fulls.length;
    $( sel.location, this.el ).text( num + " of " + total );
  };

  // Default options for the sshow function.
  var defaultOptions = {
    statusSetup : statusSetup,
    handlerSetup : handlerSetup,
    prefetch : 3,
    allowLoop : true,
    animationTime : 100,
    setCaption : setCaption,
    setLocation : setLocation
  };

  Sshow = function() {
    // Options are provided to the `init` method.
    this.options = {};

    // The `el` variable contains the jQuery-wrapped DOM element.
    this.el = undefined;

    // Current index displaying.
    this.currentIndex = 0;

    // Array of URLs to the full-sized (non-thumbnail) images.
    this.fulls  = [];

    // Array of URLs to thumbnail images.
    this.thumbs = [];

    // References the original elements if they are anchors to
    // full-sized images.
    this.originalElements = [];

    // Captions
    this.captions = [];
  };

  $.extend( Sshow.prototype, {

    _setupDom : function () {

      var options = this.options,
          el = this.el,
          wrapper, stage, placeholder, source;

      wrapper = $( '

' );
      stage   = $( '

' );

      el.wrapInner( '

' );
      source = $( sel.source, el );
      wrapper.prepend( stage );
      el.prepend( wrapper );

      // Call "status" setup -- meant for DOM insertion of status elements.
      if ( $.isFunction( options.statusSetup ) ) options.statusSetup.call( this, el );
      // Call "handler" setup -- meant to attach handlers to DOM events.
      if ( $.isFunction( options.handlerSetup ) ) options.handlerSetup.call( this, el );

      placeholder = $( '

' ).
        appendTo( stage );

      // Hide the original elements.
      $( source ).hide();
    },

    _setupImages : function() {

      var el = this.el,
          self = this,
          options = this.options,
          source = $( sel.source, el );

      // Finding our images
      // The first type of information we look for are links that wrap
      // images. We assume the link goes to a display (large) version
      // of the image it wraps, which maints a lot of usability with
      // no JavaScript running.
      if ( $( source ).find( 'a' ).length > 0 ) {
        $( source ).find( 'a' ).each( function() {
          var ln = $( this ), // The anchor element
              src = ln.attr( 'href' ),
              caption;

          self.originalElements.push( ln );
          self.fulls.push( src );

          if ( $.isFunction( options.getCaption ) ) {
            self.captions.push( options.getCaption.call( this, ln ) );
          }
        });
      } else {
      // Just look for all images, and use the `src` attribute as the
      // display src.
        $( source ).find( 'img' ).each( function() {
          var img = $(this),
              src = img.attr( 'src' ),
              caption;
          self.originalElements.push( img );
          self.fulls.push( src );
          if ( $.isFunction( options.getCaption ) ) {
            self.captions.push( options.getCaption.call( this, img ) );
          }

        });
      }

      // Push any `img` elements' `src` atttributes as thumbs.
      $( source ).find( 'img' ).each( function() {
        self.thumbs.push( $( this ).attr( 'src' ) );
      });

    },

    init : function ( el, opts ) {
      var self = this,
          options;

      el = $( el ).addClass( domClass.sshow ).css( { position : 'relative'} );
      this.el = el;
      options = this.options = $.extend( defaultOptions, ( opts || {} ) );

      this._setupDom();
      this._setupImages();

      self.set( 0 );

      return this;
    },

    // Setting an image
    set : function ( index ) {
      var el = this.el,
          // Are we showing the current image?
          same = ( this.currentIndex === index ),
          options = this.options,
          prefetch = options.prefetch,
          neighbors = indexNeighbors(index, prefetch, this.fulls.length ),
          href = this.fulls[index],
          placeholder = sel.placeholder,
          _currentImage, _i, _l;

      // Update currentIndex.
      this.currentIndex = index;

      if ( href ) {

        // Load the image.
        this.load( index );

        // Load neighboring images, too (prefetch for better interaction.)
        if ( neighbors ) {
          for ( _i = 0, _l = neighbors.length; _i < _l; _i+=1 ) {
            this.load( neighbors[_i] );
          }
        }

        // If it's a new image, fade out the old one.
        if ( !same ) {
          $( placeholder + ' img.active', el ).fadeOut( options.animationTime , function() {
            $( this ).css( { opacity: 0.0 } );
          });
          $( placeholder + ' img', el ).removeClass( 'active' );
        }

        // Get the new image.
        _currentImage = $( placeholder + ' img[src="' + href + '"]', el ).
          addClass( 'active' ).css( { display: 'inline' } );

        if ( same ) {
          _currentImage.css( { opacity: 1.0 } );
        } else {
          _currentImage.animate( { opacity: 1.0 }, options.animationTime );
        }

        // Update our status (caption and navigation text)
        this.updateStatus();

        // Call onImageChange.
        if ( $.isFunction( options.onImageChange ) ) options.onImageChange.call( this, _currentImage );

      }

      return this;
    },

    load : function ( index ) {
      var href = this.fulls[index],
          orig = this.originalElements[index],
          self = this,
          el   = this.el,
          options = this.options,
          placeholder = sel.placeholder,
          _newImage, _i, _l, _attr;

      // Check whether this image exists already.
      if ( $( placeholder + ' img[src="' + href + '"]', el ).length === 0 ) {
        // Create an image element for the full-sized image source.
        // Put in the "placeholder" tray and hide it.
        _newImage = $( '' ).
          appendTo( $( placeholder ) ).css( {
            position : 'absolute',
            display  : 'none',
            opacity  : 0
          } ).wrap( '

' );

        // Copy any "data-" attributes from the original link to the image.
        if ( orig ) {
          for ( _i = 0, _l = orig[0].attributes.length; _i < _l; _i+=1 ) {
            _attr = orig[0].attributes[_i];
            if ( _attr.name.indexOf( 'data-' ) === 0 ) {
              _newImage.attr( _attr.name, _attr.value );
            }
          }
        }

        // Call onImageLoad and onImageClick handler setup.
        if ( $.isFunction( options.onImageLoad ) ) options.onImageLoad.call( this, _newImage, index );
        if ( $.isFunction( options.onImageClick ) ) {
          $( _newImage ).click( function ( e ) {
            options.onImageClick.call( self, _newImage, e );
          });
        }
      }

      return this;
    },

    updateStatus : function() {
      var options = this.options,
          index = this.currentIndex,
          caption = this.captions[index],
          el = this.el,
          total = this.fulls.length;
      if ( $.isFunction( options.setLocation ) ) options.setLocation.call( this, index );
      if ( $.isFunction( options.setCaption ) ) options.setCaption.call( this, caption, index );
    },

    next : function() {
      var canChange = true,
          index = this.currentIndex,
          fulls = this.fulls,
          allowLoop = this.options.allowLoop;

      if ( index < fulls.length - 1 ) {
        index += 1;
      } else if ( allowLoop ) {
        index = 0;
      } else {
        canChange = false;
      }

      if ( canChange ) {
        this.set( index );
      }

      return this;
    },

    prev : function() {
      var canChange = true,
          index = this.currentIndex,
          fulls = this.fulls,
          allowLoop = this.options.allowLoop;

      if ( index > 0 ) {
        index -= 1;
      } else if ( allowLoop ) {
        index = fulls.length - 1;
      } else {
        canChange = false;
      }

      if ( canChange ) {
        this.set( index );
      }

      return this;
    },

  });

  // The main sshow function.
  $.fn.sshow = function ( opts ) {
    return this.each( function() {
      $( this ).data( 'sshow', new Sshow().init( this, opts ) );
    });
  };

})( jQuery );
<commit_msg>defaultOptions are property of Sshow to allow modification<commit_after>/*
 * sshowjs
 * mjhoy | 2011
 *
 * ermm, beta...
 *
 */

(function ( $, undefined ) {

  // Helper function. Returns the indexes `k` items away from
  // index `n` for an array of length `len`. Useful for
  // getting nearby images in the slideshow to pre-load.
  var indexNeighbors = function ( n, k, len ) {
    if ( n >= len ) return undefined;
    var arr = [],
        i, x, r, offset;
    for ( i = 0, x = k * 2; i <= x; i += 1 ) {
      offset = ( i - k ) + n;
      if ( offset < 0 ) {
        r = len + offset;
      } else if ( offset >= len ) {
        r = offset - len;
      } else {
        r = offset;
      }
      if ( ( r >= 0 ) && ( r < len ) && ( arr.indexOf( r ) < 0 ) ) {
        arr.push( r );
      }
      if ( arr.length === len ) {
        break;
      }
    }
    return arr;
  }

  // The classes we will use in constructing new elements.
  var domClass = {
    sshow        : 'sshow',
    wrapper      : 'sshow_wrapper',
    stage        : 'sshow_stage',
    source       : 'sshow_source',
    status       : 'sshow_status',
    caption      : 'sshow_caption',
    navigation   : 'sshow_navigation',
    location     : 'sshow_location',
    nextLink     : 'sshow_nextLink',
    prevLink     : 'sshow_prevLink',
    placeholder  : 'sshow_placeholder',
    imageWrapper : 'sshow_image_wrapper'
  };

  // Same as `domClass` but with the dot in front, for CSS selectors.
  var sel = (function() {
    var obj = {};
    $.each( domClass, function ( k, v ) {
      obj[k] = '.' + v;
    } );
    return obj;
  })();

  // The default DOM set up of status and next/prev indicators.
  var statusSetup = function ( el ) {
    var status     = $( "
" ),
        navigation = $( "
" ),
        next       = $( "Next" ),
        location   = $( "" ),
        prev       = $( "Prev" ),
        caption    = $( "
" );
    // status
    // |- caption
    // `- navigation
    //    |- next
    //    |- location
    //    `- prev
    status.prepend( caption ).
      append( navigation.prepend( location ) );
    navigation.prepend( next ).append( prev );
    $( sel.wrapper, el ).prepend( status );
  };

  var handlerSetup = function ( el ) {
    var self = this;
    $( sel.nextLink, el ).click( function() { self.next(); } );
    $( sel.prevLink, el ).click( function() { self.prev(); } );
  };

  // Set the caption
  var setCaption = function ( caption, index ) {
    $( sel.caption, this.el ).html( caption );
  };

  // Set the location (e.g., "2 of 5")
  var setLocation = function ( index ) {
    var num = index + 1,
        total = this.fulls.length;
    $( sel.location, this.el ).text( num + " of " + total );
  };

  Sshow = function() {

    // The `el` variable contains the jQuery-wrapped DOM element.
    this.el = undefined;

    // Current index displaying.
    this.currentIndex = 0;

    // Array of URLs to the full-sized (non-thumbnail) images.
    this.fulls  = [];

    // Array of URLs to thumbnail images.
    this.thumbs = [];

    // References the original elements if they are anchors to
    // full-sized images.
    this.originalElements = [];

    // Captions
    this.captions = [];
  };

  // Default options for the sshow function.
  var defaultOptions = {
    statusSetup : statusSetup,
    handlerSetup : handlerSetup,
    prefetch : 3,
    allowLoop : true,
    animationTime : 100,
    setCaption : setCaption,
    setLocation : setLocation
  };

  Sshow.defaultOptions = defaultOptions;

  $.extend( Sshow.prototype, {

    _setupDom : function () {

      var options = this.options,
          el = this.el,
          wrapper, stage, placeholder, source;

      wrapper = $( '

' );
      stage   = $( '

' );

      el.wrapInner( '

' );
      source = $( sel.source, el );
      wrapper.prepend( stage );
      el.prepend( wrapper );

      // Call "status" setup -- meant for DOM insertion of status elements.
      if ( $.isFunction( options.statusSetup ) ) options.statusSetup.call( this, el );
      // Call "handler" setup -- meant to attach handlers to DOM events.
      if ( $.isFunction( options.handlerSetup ) ) options.handlerSetup.call( this, el );

      placeholder = $( '

' ).
        appendTo( stage );

      // Hide the original elements.
      $( source ).hide();
    },

    _setupImages : function() {

      var el = this.el,
          self = this,
          options = this.options,
          source = $( sel.source, el );

      // Finding our images
      // The first type of information we look for are links that wrap
      // images. We assume the link goes to a display (large) version
      // of the image it wraps, which maints a lot of usability with
      // no JavaScript running.
      if ( $( source ).find( 'a' ).length > 0 ) {
        $( source ).find( 'a' ).each( function() {
          var ln = $( this ), // The anchor element
              src = ln.attr( 'href' ),
              caption;

          self.originalElements.push( ln );
          self.fulls.push( src );

          if ( $.isFunction( options.getCaption ) ) {
            self.captions.push( options.getCaption.call( this, ln ) );
          }
        });
      } else {
      // Just look for all images, and use the `src` attribute as the
      // display src.
        $( source ).find( 'img' ).each( function() {
          var img = $(this),
              src = img.attr( 'src' ),
              caption;
          self.originalElements.push( img );
          self.fulls.push( src );
          if ( $.isFunction( options.getCaption ) ) {
            self.captions.push( options.getCaption.call( this, img ) );
          }

        });
      }

      // Push any `img` elements' `src` atttributes as thumbs.
      $( source ).find( 'img' ).each( function() {
        self.thumbs.push( $( this ).attr( 'src' ) );
      });

    },

    init : function ( el, opts ) {
      var self = this,
          options;

      el = $( el ).addClass( domClass.sshow ).css( { position : 'relative'} );
      this.el = el;
      options = this.options = $.extend( Sshow.defaultOptions, ( opts || {} ) );

      this._setupDom();
      this._setupImages();

      self.set( 0 );

      return this;
    },

    // Setting an image
    set : function ( index ) {
      var el = this.el,
          // Are we showing the current image?
          same = ( this.currentIndex === index ),
          options = this.options,
          prefetch = options.prefetch,
          neighbors = indexNeighbors(index, prefetch, this.fulls.length ),
          href = this.fulls[index],
          placeholder = sel.placeholder,
          _currentImage, _i, _l;

      // Update currentIndex.
      this.currentIndex = index;

      if ( href ) {

        // Load the image.
        this.load( index );

        // Load neighboring images, too (prefetch for better interaction.)
        if ( neighbors ) {
          for ( _i = 0, _l = neighbors.length; _i < _l; _i+=1 ) {
            this.load( neighbors[_i] );
          }
        }

        // If it's a new image, fade out the old one.
        if ( !same ) {
          $( placeholder + ' img.active', el ).fadeOut( options.animationTime , function() {
            $( this ).css( { opacity: 0.0 } );
          });
          $( placeholder + ' img', el ).removeClass( 'active' );
        }

        // Get the new image.
        _currentImage = $( placeholder + ' img[src="' + href + '"]', el ).
          addClass( 'active' ).css( { display: 'inline' } );

        if ( same ) {
          _currentImage.css( { opacity: 1.0 } );
        } else {
          _currentImage.animate( { opacity: 1.0 }, options.animationTime );
        }

        // Update our status (caption and navigation text)
        this.updateStatus();

        // Call onImageChange.
        if ( $.isFunction( options.onImageChange ) ) options.onImageChange.call( this, _currentImage );

      }

      return this;
    },

    load : function ( index ) {
      var href = this.fulls[index],
          orig = this.originalElements[index],
          self = this,
          el   = this.el,
          options = this.options,
          placeholder = sel.placeholder,
          _newImage, _i, _l, _attr;

      // Check whether this image exists already.
      if ( $( placeholder + ' img[src="' + href + '"]', el ).length === 0 ) {
        // Create an image element for the full-sized image source.
        // Put in the "placeholder" tray and hide it.
        _newImage = $( '' ).
          appendTo( $( placeholder ) ).css( {
            position : 'absolute',
            display  : 'none',
            opacity  : 0
          } ).wrap( '

' );

        // Copy any "data-" attributes from the original link to the image.
        if ( orig ) {
          for ( _i = 0, _l = orig[0].attributes.length; _i < _l; _i+=1 ) {
            _attr = orig[0].attributes[_i];
            if ( _attr.name.indexOf( 'data-' ) === 0 ) {
              _newImage.attr( _attr.name, _attr.value );
            }
          }
        }

        // Call onImageLoad and onImageClick handler setup.
        if ( $.isFunction( options.onImageLoad ) ) options.onImageLoad.call( this, _newImage, index );
        if ( $.isFunction( options.onImageClick ) ) {
          $( _newImage ).click( function ( e ) {
            options.onImageClick.call( self, _newImage, e );
          });
        }
      }

      return this;
    },

    updateStatus : function() {
      var options = this.options,
          index = this.currentIndex,
          caption = this.captions[index],
          el = this.el,
          total = this.fulls.length;
      if ( $.isFunction( options.setLocation ) ) options.setLocation.call( this, index );
      if ( $.isFunction( options.setCaption ) ) options.setCaption.call( this, caption, index );
    },

    next : function() {
      var canChange = true,
          index = this.currentIndex,
          fulls = this.fulls,
          allowLoop = this.options.allowLoop;

      if ( index < fulls.length - 1 ) {
        index += 1;
      } else if ( allowLoop ) {
        index = 0;
      } else {
        canChange = false;
      }

      if ( canChange ) {
        this.set( index );
      }

      return this;
    },

    prev : function() {
      var canChange = true,
          index = this.currentIndex,
          fulls = this.fulls,
          allowLoop = this.options.allowLoop;

      if ( index > 0 ) {
        index -= 1;
      } else if ( allowLoop ) {
        index = fulls.length - 1;
      } else {
        canChange = false;
      }

      if ( canChange ) {
        this.set( index );
      }

      return this;
    },

  });

  // The main sshow function.
  $.fn.sshow = function ( opts ) {
    return this.each( function() {
      $( this ).data( 'sshow', new Sshow().init( this, opts ) );
    });
  };

})( jQuery );
<|endoftext|>


<commit_before>/* global AFRAME */

if (typeof AFRAME === 'undefined') {
  throw new Error('Component attempted to register before AFRAME was available.');
}

require('./activators');
require('./behaviours');

AFRAME.currentInputMapping = null;
AFRAME.inputMappings = {};
AFRAME.inputActions = {};

var behaviour = {
  trackpad: 'dpad'
};

AFRAME.registerSystem('input-mapping', {
  mappings: {},
  mappingsPerControllers: {},
  loadedControllers: [],

  init: function () {
    var self = this;

    this.keyboardHandler = this.keyboardHandler.bind(this);

    this.sceneEl.addEventListener('inputmappingregistered', function () {
      self.removeControllersListeners();
      for (var i = 0; i < self.loadedControllers.length; i++) {
        var controllerObj = self.loadedControllers[i];
        self.updateControllersListeners(controllerObj);
      }
    });

    // Controllers
    this.sceneEl.addEventListener('controllerconnected', function (event) {
      var matchedController = self.findMatchingController(event.target);

      if (matchedController) {
        self.updateControllersListeners(matchedController);
        return;
      }

      var controllerObj = {
        name: event.detail.name,
        hand: event.detail.component.data.hand,
        element: event.target,
        handlers: {},
        activators: {}
      };
      self.loadedControllers.push(controllerObj);

      self.updateControllersListeners(controllerObj);
    });

    this.sceneEl.addEventListener('controllerdisconnected', function (event) {
      var controller = self.findMatchingController(event.target);
      if (controller) {
        self.removeControllerListeners(controller);
      }
    });

    // Keyboard
    this.addKeyboardListeners();
  },

  findMatchingController: function (matchElement) {
    var controller;
    var i;
    for (i = 0; i < this.loadedControllers.length; i++) {
      controller = this.loadedControllers[i];
      if (controller.element === matchElement) {
        return controller;
      }
    }
    return undefined;
  },

  addKeyboardListeners: function () {
    document.addEventListener('keyup', this.keyboardHandler);
    document.addEventListener('keydown', this.keyboardHandler);
    document.addEventListener('keypress', this.keyboardHandler);
  },

  removeKeyboardListeners: function () {
    document.removeEventListener('keyup', this.keyboardHandler);
    document.removeEventListener('keydown', this.keyboardHandler);
    document.removeEventListener('keypress', this.keyboardHandler);
  },

  removeControllerListeners: function (controller) {
    // Remove events handlers
    for (var eventName in controller.handlers) {
      var handler = controller.handlers[eventName];
      controller.element.removeEventListener(eventName, handler);
    }
    controller.handlers = {};

    // Remove activators
    for (var activatorName in controller.activators) {
      var activator = controller.activators[activatorName];
      activator.removeListeners();
    }

    controller.activators = {};
  },

  updateBehaviours: function (controllerObj) {
    var controllerBehaviour = AFRAME.inputBehaviours[controllerObj.name];
    var behavioursPerController = this.mappingsPerControllers[controllerObj.name].behaviours;
    if (!behavioursPerController) { return; }
    for (var button in behavioursPerController) {
      var behaviourName = behavioursPerController[button];
      var behaviourDefinition = AFRAME.inputBehaviours[behaviourName];
      if (behaviourDefinition) {
        var behaviour = new behaviourDefinition(controllerObj.element, button);
      }
    }
  },

  updateControllersListeners: function (controllerObj) {
    this.removeControllerListeners(controllerObj);

    if (!AFRAME.inputMappings) {
      console.warn('input-mapping: No mappings defined');
      return;
    }

    var mappingsPerController = this.mappingsPerControllers[controllerObj.name] = {
      mappings: {},
      behaviours: {}
    };

    // Create the listener for each event
    for (var mappingName in AFRAME.inputMappings.mappings) {
      var mapping = AFRAME.inputMappings.mappings[mappingName];

      var commonMappings = mapping.common;
      if (commonMappings) {
        this.updateMappingsPerController(commonMappings, mappingsPerController, mappingName);
      }

      var controllerMappings = mapping[controllerObj.name];
      if (controllerMappings) {
        this.updateMappingsPerController(controllerMappings, mappingsPerController, mappingName);
      } else {
        console.warn('input-mapping: No mappings defined for controller type: ', controllerObj.name);
      }
    }

    // Mapping the behaviours
    for (var mappingName in AFRAME.inputMappings.behaviours) {
      var behaviour = AFRAME.inputMappings.behaviours[mappingName];

      var controllerBehaviours = behaviour[controllerObj.name];
      if (controllerBehaviours) {
        this.updateBehavioursPerController(controllerBehaviours, mappingsPerController, mappingName);
      }
    }

    var self = this;

    var OnActivate = function(eventName)  {
      return function (event) {
        var mapping = mappingsPerController.mappings[eventName];
        var mappedEvent = mapping[AFRAME.currentInputMapping];
        if (typeof mappedEvent ==='object') {
          // Handedness
          var controller = self.findMatchingController(event.target);
          mappedEvent = mappedEvent[controller.hand];
          if (!mappedEvent) { return; }
        }
        event.target.emit(mappedEvent, event.detail);
      }
    };

    for (var eventName in mappingsPerController.mappings) {
      // Check for activators
      if (eventName.indexOf('.') !== -1) {
        var aux = eventName.split('.');
        var button = aux[0]; // eg: trackpad
        var activatorName = aux[1]; // eg: doublepress
        var onActivate = OnActivate(eventName);
        var Activator = AFRAME.inputActivators[activatorName];
        controllerObj.activators[eventName] = new Activator(controllerObj.element, button, onActivate);
      }

      var onActivate = OnActivate(eventName);
      controllerObj.element.addEventListener(eventName, onActivate);
      controllerObj.handlers[eventName] = onActivate;
    }

    this.updateBehaviours(controllerObj);
  },

  checkValidInputMapping: function () {
    if (AFRAME.currentInputMapping === null) {
      console.warn('input-mapping: No current input mapping defined.');
    }
  },

  keyboardHandler: function (event) {
    this.checkValidInputMapping();
    if (mappings && mappings.keyboard) {
      mappings = mappings.keyboard;
      var key = event.keyCode === 32 ? 'Space' : event.key;
      var keyEvent = (key + '_' + event.type.substr(3)).toLowerCase();
      var mapEvent = mappings[keyEvent];
      if (mapEvent) {
        this.sceneEl.emit(mapEvent);
      }
    }
  },

  updateBehavioursPerController: function (behaviours, mappingsPerController, mappingName) {
    for (var button in behaviours) {
      var behaviour = behaviours[button];

      if (!mappingsPerController.behaviours[button]) {
        mappingsPerController.behaviours[button] = behaviour;
      }
    }
  },

  updateMappingsPerController: function (mappings, mappingsPerController, mappingName) {
    // Generate a mapping for each controller: (Eg: vive-controls.triggerdown.default.paint)
    for (var eventName in mappings) {
      var mapping = mappings[eventName];
      if (!mappingsPerController.mappings[eventName]) {
        mappingsPerController.mappings[eventName] = {};
      }
      mappingsPerController.mappings[eventName][mappingName] = mapping;
    }
  },

  removeControllersListeners: function () {
    for (var i = 0; i < this.loadedControllers.length; i++) {
      var controller = this.loadedControllers[i];
      this.removeControllerListeners(controller);
    }
    this.mappingsPerControllers = {
      mappings: {},
      behaviours: {}
    };
  }
});

AFRAME.registerInputActions = function (inputActions, defaultActionSet) {
  AFRAME.inputActions = inputActions;
  if (typeof defaultActionSet !== 'undefined') {
    if (AFRAME.inputActions[defaultActionSet]) {
      AFRAME.currentInputMapping = defaultActionSet;
    } else {
      console.error(`input-mapping: trying to set a non registered action set '${defaultActionSet}'`);
    }
  }
};

AFRAME.registerInputMappings = function (data, override) {
  if (override || Object.keys(AFRAME.inputMappings).length === 0) {
    AFRAME.inputMappings = data;
  } else {
    // @todo Merge behaviours too
    AFRAME.inputMappings.behaviours = data.behaviours;

    // Merge mappings
    for (var mappingName in data.mappings) {
      var mapping = data.mappings[mappingName];
      if (!AFRAME.inputMappings[mappingName]) {
        AFRAME.inputMappings[mappingName] = mapping;
        continue;
      }

      for (var controllerName in mapping) {
        var controllerMapping = mapping[controllerName];
        if (!AFRAME.inputMappings[mappingName][controllerName]) {
          AFRAME.inputMappings[mappingName][controllerName] = controllerMapping;
          continue;
        }

        for (var eventName in controllerMapping) {
          AFRAME.inputMappings[mappingName][controllerName][eventName] = controllerMapping[eventName];
        }
      }
    }
  }

  if (!AFRAME.scenes) { return; }

  for (var i = 0; i < AFRAME.scenes.length; i++) {
    AFRAME.scenes[i].emit('inputmappingregistered');
  }
};<commit_msg>Fix keyboard handler<commit_after>/* global AFRAME */

if (typeof AFRAME === 'undefined') {
  throw new Error('Component attempted to register before AFRAME was available.');
}

require('./activators');
require('./behaviours');

AFRAME.currentInputMapping = null;
AFRAME.inputMappings = {};
AFRAME.inputActions = {};

var behaviour = {
  trackpad: 'dpad'
};

AFRAME.registerSystem('input-mapping', {
  mappings: {},
  mappingsPerControllers: {},
  loadedControllers: [],

  init: function () {
    var self = this;

    this.keyboardHandler = this.keyboardHandler.bind(this);

    this.sceneEl.addEventListener('inputmappingregistered', function () {
      self.removeControllersListeners();
      for (var i = 0; i < self.loadedControllers.length; i++) {
        var controllerObj = self.loadedControllers[i];
        self.updateControllersListeners(controllerObj);
      }
    });

    // Controllers
    this.sceneEl.addEventListener('controllerconnected', function (event) {
      var matchedController = self.findMatchingController(event.target);

      if (matchedController) {
        self.updateControllersListeners(matchedController);
        return;
      }

      var controllerObj = {
        name: event.detail.name,
        hand: event.detail.component.data.hand,
        element: event.target,
        handlers: {},
        activators: {}
      };
      self.loadedControllers.push(controllerObj);

      self.updateControllersListeners(controllerObj);
    });

    this.sceneEl.addEventListener('controllerdisconnected', function (event) {
      var controller = self.findMatchingController(event.target);
      if (controller) {
        self.removeControllerListeners(controller);
      }
    });

    // Keyboard
    this.addKeyboardListeners();
  },

  findMatchingController: function (matchElement) {
    var controller;
    var i;
    for (i = 0; i < this.loadedControllers.length; i++) {
      controller = this.loadedControllers[i];
      if (controller.element === matchElement) {
        return controller;
      }
    }
    return undefined;
  },

  addKeyboardListeners: function () {
    document.addEventListener('keyup', this.keyboardHandler);
    document.addEventListener('keydown', this.keyboardHandler);
    document.addEventListener('keypress', this.keyboardHandler);
  },

  removeKeyboardListeners: function () {
    document.removeEventListener('keyup', this.keyboardHandler);
    document.removeEventListener('keydown', this.keyboardHandler);
    document.removeEventListener('keypress', this.keyboardHandler);
  },

  removeControllerListeners: function (controller) {
    // Remove events handlers
    for (var eventName in controller.handlers) {
      var handler = controller.handlers[eventName];
      controller.element.removeEventListener(eventName, handler);
    }
    controller.handlers = {};

    // Remove activators
    for (var activatorName in controller.activators) {
      var activator = controller.activators[activatorName];
      activator.removeListeners();
    }

    controller.activators = {};
  },

  updateBehaviours: function (controllerObj) {
    var controllerBehaviour = AFRAME.inputBehaviours[controllerObj.name];
    var behavioursPerController = this.mappingsPerControllers[controllerObj.name].behaviours;
    if (!behavioursPerController) { return; }
    for (var button in behavioursPerController) {
      var behaviourName = behavioursPerController[button];
      var behaviourDefinition = AFRAME.inputBehaviours[behaviourName];
      if (behaviourDefinition) {
        var behaviour = new behaviourDefinition(controllerObj.element, button);
      }
    }
  },

  updateControllersListeners: function (controllerObj) {
    this.removeControllerListeners(controllerObj);

    if (!AFRAME.inputMappings) {
      console.warn('input-mapping: No mappings defined');
      return;
    }

    var mappingsPerController = this.mappingsPerControllers[controllerObj.name] = {
      mappings: {},
      behaviours: {}
    };

    // Create the listener for each event
    for (var mappingName in AFRAME.inputMappings.mappings) {
      var mapping = AFRAME.inputMappings.mappings[mappingName];

      var commonMappings = mapping.common;
      if (commonMappings) {
        this.updateMappingsPerController(commonMappings, mappingsPerController, mappingName);
      }

      var controllerMappings = mapping[controllerObj.name];
      if (controllerMappings) {
        this.updateMappingsPerController(controllerMappings, mappingsPerController, mappingName);
      } else {
        console.warn('input-mapping: No mappings defined for controller type: ', controllerObj.name);
      }
    }

    // Mapping the behaviours
    for (var mappingName in AFRAME.inputMappings.behaviours) {
      var behaviour = AFRAME.inputMappings.behaviours[mappingName];

      var controllerBehaviours = behaviour[controllerObj.name];
      if (controllerBehaviours) {
        this.updateBehavioursPerController(controllerBehaviours, mappingsPerController, mappingName);
      }
    }

    var self = this;

    var OnActivate = function(eventName)  {
      return function (event) {
        var mapping = mappingsPerController.mappings[eventName];
        var mappedEvent = mapping[AFRAME.currentInputMapping];
        if (typeof mappedEvent ==='object') {
          // Handedness
          var controller = self.findMatchingController(event.target);
          mappedEvent = mappedEvent[controller.hand];
          if (!mappedEvent) { return; }
        }
        event.target.emit(mappedEvent, event.detail);
      }
    };

    for (var eventName in mappingsPerController.mappings) {
      // Check for activators
      if (eventName.indexOf('.') !== -1) {
        var aux = eventName.split('.');
        var button = aux[0]; // eg: trackpad
        var activatorName = aux[1]; // eg: doublepress
        var onActivate = OnActivate(eventName);
        var Activator = AFRAME.inputActivators[activatorName];
        controllerObj.activators[eventName] = new Activator(controllerObj.element, button, onActivate);
      }

      var onActivate = OnActivate(eventName);
      controllerObj.element.addEventListener(eventName, onActivate);
      controllerObj.handlers[eventName] = onActivate;
    }

    this.updateBehaviours(controllerObj);
  },

  checkValidInputMapping: function () {
    if (AFRAME.currentInputMapping === null) {
      console.warn('input-mapping: No current input mapping defined.');
    }
  },

  keyboardHandler: function (event) {
    this.checkValidInputMapping();
    if (AFRAME.inputMappings &&
        AFRAME.inputMappings.mappings[AFRAME.currentInputMapping] &&
        AFRAME.inputMappings.mappings[AFRAME.currentInputMapping].keyboard
    ) {
      var currentKeyboardMapping =
            AFRAME.inputMappings.mappings[AFRAME.currentInputMapping].keyboard;
      var key = event.keyCode === 32 ? "Space" : event.key;
      var keyEvent = (key + "_" + event.type.substr(3)).toLowerCase();
      var mapEvent = currentKeyboardMapping[keyEvent];
      if (mapEvent) {
        this.sceneEl.emit(mapEvent);
      }
    }
  },

  updateBehavioursPerController: function (behaviours, mappingsPerController, mappingName) {
    for (var button in behaviours) {
      var behaviour = behaviours[button];

      if (!mappingsPerController.behaviours[button]) {
        mappingsPerController.behaviours[button] = behaviour;
      }
    }
  },

  updateMappingsPerController: function (mappings, mappingsPerController, mappingName) {
    // Generate a mapping for each controller: (Eg: vive-controls.triggerdown.default.paint)
    for (var eventName in mappings) {
      var mapping = mappings[eventName];
      if (!mappingsPerController.mappings[eventName]) {
        mappingsPerController.mappings[eventName] = {};
      }
      mappingsPerController.mappings[eventName][mappingName] = mapping;
    }
  },

  removeControllersListeners: function () {
    for (var i = 0; i < this.loadedControllers.length; i++) {
      var controller = this.loadedControllers[i];
      this.removeControllerListeners(controller);
    }
    this.mappingsPerControllers = {
      mappings: {},
      behaviours: {}
    };
  }
});

AFRAME.registerInputActions = function (inputActions, defaultActionSet) {
  AFRAME.inputActions = inputActions;
  if (typeof defaultActionSet !== 'undefined') {
    if (AFRAME.inputActions[defaultActionSet]) {
      AFRAME.currentInputMapping = defaultActionSet;
    } else {
      console.error(`input-mapping: trying to set a non registered action set '${defaultActionSet}'`);
    }
  }
};

AFRAME.registerInputMappings = function (data, override) {
  if (override || Object.keys(AFRAME.inputMappings).length === 0) {
    AFRAME.inputMappings = data;
  } else {
    // @todo Merge behaviours too
    AFRAME.inputMappings.behaviours = data.behaviours;

    // Merge mappings
    for (var mappingName in data.mappings) {
      var mapping = data.mappings[mappingName];
      if (!AFRAME.inputMappings[mappingName]) {
        AFRAME.inputMappings[mappingName] = mapping;
        continue;
      }

      for (var controllerName in mapping) {
        var controllerMapping = mapping[controllerName];
        if (!AFRAME.inputMappings[mappingName][controllerName]) {
          AFRAME.inputMappings[mappingName][controllerName] = controllerMapping;
          continue;
        }

        for (var eventName in controllerMapping) {
          AFRAME.inputMappings[mappingName][controllerName][eventName] = controllerMapping[eventName];
        }
      }
    }
  }

  if (!AFRAME.scenes) { return; }

  for (var i = 0; i < AFRAME.scenes.length; i++) {
    AFRAME.scenes[i].emit('inputmappingregistered');
  }
};<|endoftext|>