<commit_before>/*******************************
	EasyPromise Version 0.1

    A truly simple promise library for avoiding asynchronous callback spaghetti.

  	The MIT License (MIT)

	Copyright (c) 2014 Greg McLeod <cleod9{at}gmail.com>

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
*******************************/

//Constructor
function EasyPromise (args) {
	this.status = EasyPromise.STATUS_CODES.IDLE;

	var fullArgs = null;
	var tmpArgs = Array.prototype.slice.call(arguments);
	if(tmpArgs.length === 1)
		fullArgs = args; //Assume initialized via create(), we expect to be receiving an array
	else
		fullArgs = tmpArgs; //Assume initialized via 'new', we expect to be receiving parameters individually

	this.options = {
		asyncContext: null, //Reference to context of the asynchronous call (will default to the EasyPromise object)
		callbackContext: null, //Reference to context for the callbacks (will default to the EasyPromise object)
		prependArgs: [] //List of arguments to be prepended to this promise's callback functions
	}
	this.children = {}; //Reference to the next promises stored here

	if (fullArgs.length <= 0)
		throw new Error('Error, promise needs initial function as the first arg.');

	//The actual function we want to run is the first arg
	this.fn = fullArgs.shift();

	if(typeof this.fn !== 'function' && !(this.fn && this.fn._isEasyPromise))
		throw new Error('Error, expecting a function or promise as the first argument of the promise constructor');

	if (fullArgs.length <= 0)
		throw new Error('Error, promise expects at least 1 other argument (i.e. args/callback(s))');

	//Queue up rest of  arguments
	if (typeof fullArgs[0] !== 'function') {
		if(typeof fullArgs[0].length === 'undefined')
			throw new Error('Error, second argument of promise must be either an array of args, or a callback function.');
		this.arguments = fullArgs[0].slice(0);
		fullArgs.splice(0, 1);
	} else {
		this.arguments = [];
	}

	if (fullArgs.length <= 0)
		throw new Error('Error, promise missing a callback function.');

	//Assume the last remaining args are callbacks
	this.callbacks = fullArgs.slice(0);
	//Check the first one, we'll let the rest throw an error if there is a problem
	if (typeof this.callbacks[0] !== 'function')
		throw new Error('Error, promise expects the callback arguments to be of type "function"');
};

//Static vars
EasyPromise.STATUS_CODES = { IDLE: 0, PENDING: 1, SUCCESS: 2, FAILURE: 3, CLOSED: 4 };

//Instance variables
EasyPromise.prototype.parent = null; //Reference to a preceding promise
EasyPromise.prototype.children = null; //Reference to a child promises
EasyPromise.prototype.fn = null; //Async func
EasyPromise.prototype.beforeFn = null; //Func to run before async func is executed
EasyPromise.prototype.afterFn = null; //Func to run after callback is returned
EasyPromise.prototype.errorFn = null; //Func to run after an exception is thrown
EasyPromise.prototype.catchFn = null; //Func to run after an exception is thrown (for full tree)
EasyPromise.prototype.finishFn = null; //Func to run after a promise chain finishes
EasyPromise.prototype.arguments = null; //List of arguments for the async func
EasyPromise.prototype.callbacks = null; //Callback func array
EasyPromise.prototype.options = null; //Options obj
EasyPromise.prototype.status = 0; //Current status of the promise object (0 = Idle, 1 = Pending, 2 = Success, 3 = Failure, 4 = Closed)
EasyPromise.prototype._finalArgs = null; //Temporary container for callback arguments to make it easier to do promise-promise chains
EasyPromise.prototype._hasError = false; //Tracks error status for closed promise
EasyPromise.prototype._qFlag = false; //Flag to indicate that this promise is nested within another promise
EasyPromise.prototype._catchFlag = false; //Flag for try-catch mode
EasyPromise.prototype._isEasyPromise = true; //For type checking without instanceof

//Instance functions

EasyPromise.prototype.run = function () {
	if (this.parent) {
		//Find the top level promise
		this.parent.run();
	} else {
		//Execute
		this.execute();
	}
};
EasyPromise.prototype.execute = function () {
	//Execute the asynchronous function
	var self = this;
	var rootPromise = self.getRoot();
	self.status = EasyPromise.STATUS_CODES.PENDING;
	var startExecution = function () {
		//If a 'before' function is set, run it before executing
		if (self.beforeFn) {
			self.beforeFn.call(self);
		}
		//Function to make a wrapper for the original callbacks so that EasyPromise can call the next callback manually
		var callbackArr = [];
		var makeWrapper = function (callback) {
			return function () {
				//Grab arguments for this function call and prepend the extra callback args
				var args = self.options.prependArgs.concat(Array.prototype.slice.call(arguments));

				//Grant success code
				self.status = EasyPromise.STATUS_CODES.SUCCESS;

				//Run the callback in specified context
				callback.apply(self.options.callbackContext || self, args);

				//If an 'after' function is set, run it after the callback is run
				if (self.afterFn) {
					self.afterFn.call(self);
				}

				//If this promise is marked as closed, run the root promise's finish function
				if (self.status === EasyPromise.STATUS_CODES.CLOSED) {
					if(rootPromise.finishFn && rootPromise.finishFn) {
						rootPromise.finishFn.call(rootPromise);
					}
				}
			};
		};

		//For each callback, create a new wrapper
		for (var i = 0; i < self.callbacks.length; i++) {
			callbackArr.push(makeWrapper(self.callbacks[i]));
		}

		 //For pflag'd promises, replace function with its returned promise
		if(self._qFlag)
			self.fn = self.fn.apply(self.options.asyncContext || self, self.arguments);

		if (self.fn && self.fn._isEasyPromise) {
			//The function is of type EasyPromise, so we will run it like a promise
			self.fn.finish(function() {
				//When complete, run the callback for the containing promise using the arguments from the inner promise's callback
				var fnIndex = (this._hasError) ? 1 : 0;
				if (fnIndex < callbackArr.length)
					callbackArr[fnIndex].apply(self.options.callbackContext || self, this._finalArgs); //At this point, inner promises have completed
			}).run();
		} else {
			//Execute the asynchronous function by combining the arguments list with the callback list
			self.fn.apply(self.options.asyncContext || self, self.arguments.concat(callbackArr));
		}
	};
	//If error function is set, use try-catch
	if (self.errorFn || rootPromise.catchFn) {
		try {
			startExecution();
		} catch (e) {
			self.status = EasyPromise.STATUS_CODES.FAILURE;
			if(self.errorFn)
				self.errorFn(e);
			else
				rootPromise.catchFn(e);
		}
	} else {
		startExecution();
	}
};
EasyPromise.prototype.config = function (options) {
	//Modifies the options variable
	for (var i in options) {
		this.options[i] = options[i];
	}
	return this;
};
EasyPromise.prototype.abind = function (context) {
	//Bind context for asynchronous function
	this.options.asyncContext = context;

	return this;
};
EasyPromise.prototype.cbind = function (context) {
	//Bind context for the callback
	this.options.callbackContext = context;

	return this;
};
EasyPromise.prototype.prepend = function (callbackPrependArgs) {
	//Prepends custom args to the this promise's callbacks
	this.options.prependArgs = callbackPrependArgs;

	return this;
};
EasyPromise.prototype.proceed = function (fnArgs) {
	//Proceed to the next child promise
	EasyPromise.prototype.proceedTo.call(this, 'default', fnArgs);
};
EasyPromise.prototype.proceedTo = function (name, fnArgs) {
	//Execute the next callback (if it exists)
	if(this.children[name]) {
		this.children[name].arguments = this.children[name].arguments.concat(fnArgs);
		this.children[name].execute.call(this.children[name]);
	}
};
EasyPromise.prototype.proceedWith = function (callbackPrependArgs, fnArgs) {
	//Prepends custom args to the child's callback functions
	this.children['default'].prepend(callbackPrependArgs);
	this.proceed(fnArgs);
};
EasyPromise.prototype.proceedToWith = function (name, callbackPrependArgs, fnArgs) {
	//Prepends custom args to the child's callback functions for the specified child promise name
	this.children[name].prepend(callbackPrependArgs);
	this.proceedTo(name, fnArgs);
};
EasyPromise.prototype.define = function () {
	//Defines a child promise for this current promise
	var args = Array.prototype.slice.call(arguments);
	var name = args.shift();
	var promise = new EasyPromise(args);
	promise.parent = this;
	this.children[name] = promise;
	return this;
};
EasyPromise.prototype.defineq = function () {
	//Defines a promise that runs another promise (Q-style)
	var args = Array.prototype.slice.call(arguments);
	var promise = this.define.apply(this, args);
	promise._qFlag = true;
	return promise;
};
EasyPromise.prototype.then = function () {
	var args = Array.prototype.slice.call(arguments);
	args.unshift('default');
	EasyPromise.prototype.define.apply(this, args);
	return this.children['default'];
};
EasyPromise.prototype.thenq = function () {
	var args = Array.prototype.slice.call(arguments);
	var promise = this.then.apply(this, args);
	promise._qFlag = true;
	return promise;
};
EasyPromise.prototype.after = function (fn) {
	//Occurs after a callback is run but before the next promise
	this.afterFn = fn;

	return this;
};
EasyPromise.prototype.before = function (fn) {
	//Occurs before the asynchronous function is run
	this.beforeFn = fn;

	return this;
};
EasyPromise.prototype.resolve = function () {
	//For Q-styled chaining, calls the success callback
	var args = Array.prototype.slice.call(arguments);
	this._finalArgs = args;
	this._hasError = false;
	this.getRoot().status = EasyPromise.STATUS_CODES.CLOSED;
	this.status = EasyPromise.STATUS_CODES.CLOSED;
};
EasyPromise.prototype.reject = function () {
	//For Q-styled chaining, calls the error callback
	var args = Array.prototype.slice.call(arguments);
	this._finalArgs = args;
	this._hasError = true;
	this.getRoot().status = EasyPromise.STATUS_CODES.CLOSED;
	this.status = EasyPromise.STATUS_CODES.CLOSED;
};
EasyPromise.prototype.getRoot = function () {
	//Find the root promise
	if(!this.parent)
		return this;
	else
		return this.parent.getRoot();
};
EasyPromise.prototype.finish = function (fn) {
	//Attach a function to run when the full promise chain is finished (attaches to root promise only)
	this.getRoot().finishFn = fn; //Function to run when a promise chain finishes
	return this;
};
EasyPromise.prototype.error = function (fn) {
	//Handle errors for a particular promise
	this.errorFn = fn;

	return this;
};
EasyPromise.prototype.catch = function (fn) {
	//Handle errors for all promises. At this point only run() will be exposed
	this.getRoot()._catchFlag = true;
	this.getRoot().catchFn = fn;

	return this;
};

//Static functions
EasyPromise.create = function () {
	//Starts chaining a promise. (The first promise will have a null parent)
	var args = Array.prototype.slice.call(arguments);
	var promise = new EasyPromise(args);
	return promise;
}
EasyPromise.createq = function () {
	//Starts chaining a promise. (The first promise will have a null parent)
	var args = Array.prototype.slice.call(arguments);
	if(args.length > 0 && args[0] && args[0]._isEasyPromise)
		throw new Error("Error, EasyPromise.createq() does not accept a promise object directly. Please supply a function instead, or try using EasyPromise.create()");
	var promise = EasyPromise.create.apply(EasyPromise, args);
	promise._qFlag = true;

	return promise;
}<commit_msg>-Minor scope error<commit_after>/*******************************
	EasyPromise Version 0.1

    A truly simple promise library for avoiding asynchronous callback spaghetti.

  	The MIT License (MIT)

	Copyright (c) 2014 Greg McLeod <cleod9{at}gmail.com>

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
*******************************/

//Constructor
function EasyPromise (args) {
	this.status = EasyPromise.STATUS_CODES.IDLE;

	var fullArgs = null;
	var tmpArgs = Array.prototype.slice.call(arguments);
	if(tmpArgs.length === 1)
		fullArgs = args; //Assume initialized via create(), we expect to be receiving an array
	else
		fullArgs = tmpArgs; //Assume initialized via 'new', we expect to be receiving parameters individually

	this.options = {
		asyncContext: null, //Reference to context of the asynchronous call (will default to the EasyPromise object)
		callbackContext: null, //Reference to context for the callbacks (will default to the EasyPromise object)
		prependArgs: [] //List of arguments to be prepended to this promise's callback functions
	}
	this.children = {}; //Reference to the next promises stored here

	if (fullArgs.length <= 0)
		throw new Error('Error, promise needs initial function as the first arg.');

	//The actual function we want to run is the first arg
	this.fn = fullArgs.shift();

	if(typeof this.fn !== 'function' && !(this.fn && this.fn._isEasyPromise))
		throw new Error('Error, expecting a function or promise as the first argument of the promise constructor');

	if (fullArgs.length <= 0)
		throw new Error('Error, promise expects at least 1 other argument (i.e. args/callback(s))');

	//Queue up rest of  arguments
	if (typeof fullArgs[0] !== 'function') {
		if(typeof fullArgs[0].length === 'undefined')
			throw new Error('Error, second argument of promise must be either an array of args, or a callback function.');
		this.arguments = fullArgs[0].slice(0);
		fullArgs.splice(0, 1);
	} else {
		this.arguments = [];
	}

	if (fullArgs.length <= 0)
		throw new Error('Error, promise missing a callback function.');

	//Assume the last remaining args are callbacks
	this.callbacks = fullArgs.slice(0);
	//Check the first one, we'll let the rest throw an error if there is a problem
	if (typeof this.callbacks[0] !== 'function')
		throw new Error('Error, promise expects the callback arguments to be of type "function"');
};

//Static vars
EasyPromise.STATUS_CODES = { IDLE: 0, PENDING: 1, SUCCESS: 2, FAILURE: 3, CLOSED: 4 };

//Instance variables
EasyPromise.prototype.parent = null; //Reference to a preceding promise
EasyPromise.prototype.children = null; //Reference to a child promises
EasyPromise.prototype.fn = null; //Async func
EasyPromise.prototype.beforeFn = null; //Func to run before async func is executed
EasyPromise.prototype.afterFn = null; //Func to run after callback is returned
EasyPromise.prototype.errorFn = null; //Func to run after an exception is thrown
EasyPromise.prototype.catchFn = null; //Func to run after an exception is thrown (for full tree)
EasyPromise.prototype.finishFn = null; //Func to run after a promise chain finishes
EasyPromise.prototype.arguments = null; //List of arguments for the async func
EasyPromise.prototype.callbacks = null; //Callback func array
EasyPromise.prototype.options = null; //Options obj
EasyPromise.prototype.status = 0; //Current status of the promise object (0 = Idle, 1 = Pending, 2 = Success, 3 = Failure, 4 = Closed)
EasyPromise.prototype._finalArgs = null; //Temporary container for callback arguments to make it easier to do promise-promise chains
EasyPromise.prototype._hasError = false; //Tracks error status for closed promise
EasyPromise.prototype._qFlag = false; //Flag to indicate that this promise is nested within another promise
EasyPromise.prototype._catchFlag = false; //Flag for try-catch mode
EasyPromise.prototype._isEasyPromise = true; //For type checking without instanceof

//Instance functions

EasyPromise.prototype.run = function () {
	if (this.parent) {
		//Find the top level promise
		this.parent.run();
	} else {
		//Execute
		this.execute();
	}
};
EasyPromise.prototype.execute = function () {
	//Execute the asynchronous function
	var self = this;
	var rootPromise = self.getRoot();
	self.status = EasyPromise.STATUS_CODES.PENDING;
	var startExecution = function () {
		//If a 'before' function is set, run it before executing
		if (self.beforeFn) {
			self.beforeFn.call(self);
		}
		//Function to make a wrapper for the original callbacks so that EasyPromise can call the next callback manually
		var callbackArr = [];
		var makeWrapper = function (callback) {
			return function () {
				//Grab arguments for this function call and prepend the extra callback args
				var args = self.options.prependArgs.concat(Array.prototype.slice.call(arguments));

				//Grant success code
				self.status = EasyPromise.STATUS_CODES.SUCCESS;

				//Run the callback in specified context
				callback.apply(self.options.callbackContext || self, args);

				//If an 'after' function is set, run it after the callback is run
				if (self.afterFn) {
					self.afterFn.call(self);
				}

				//If this promise is marked as closed, run the root promise's finish function
				if (self.status === EasyPromise.STATUS_CODES.CLOSED) {
					if(rootPromise.finishFn && rootPromise.finishFn) {
						rootPromise.finishFn.call(rootPromise);
					}
				}
			};
		};

		//For each callback, create a new wrapper
		for (var i = 0; i < self.callbacks.length; i++) {
			callbackArr.push(makeWrapper(self.callbacks[i]));
		}

		 //For pflag'd promises, replace function with its returned promise
		if(self._qFlag)
			self.fn = self.fn.apply(self.options.asyncContext || self, self.arguments);

		if (self.fn && self.fn._isEasyPromise) {
			//The function is of type EasyPromise, so we will run it like a promise
			self.fn.finish(function() {
				//When complete, run the callback for the containing promise using the arguments from the inner promise's callback
				var fnIndex = (self._hasError) ? 1 : 0;
				if (fnIndex < callbackArr.length)
					callbackArr[fnIndex].apply(self.options.callbackContext || self, self._finalArgs); //At this point, inner promises have completed
			}).run();
		} else {
			//Execute the asynchronous function by combining the arguments list with the callback list
			self.fn.apply(self.options.asyncContext || self, self.arguments.concat(callbackArr));
		}
	};
	//If error function is set, use try-catch
	if (self.errorFn || rootPromise.catchFn) {
		try {
			startExecution();
		} catch (e) {
			self.status = EasyPromise.STATUS_CODES.FAILURE;
			if(self.errorFn)
				self.errorFn(e);
			else
				rootPromise.catchFn(e);
		}
	} else {
		startExecution();
	}
};
EasyPromise.prototype.config = function (options) {
	//Modifies the options variable
	for (var i in options) {
		this.options[i] = options[i];
	}
	return this;
};
EasyPromise.prototype.abind = function (context) {
	//Bind context for asynchronous function
	this.options.asyncContext = context;

	return this;
};
EasyPromise.prototype.cbind = function (context) {
	//Bind context for the callback
	this.options.callbackContext = context;

	return this;
};
EasyPromise.prototype.prepend = function (callbackPrependArgs) {
	//Prepends custom args to the this promise's callbacks
	this.options.prependArgs = callbackPrependArgs;

	return this;
};
EasyPromise.prototype.proceed = function (fnArgs) {
	//Proceed to the next child promise
	EasyPromise.prototype.proceedTo.call(this, 'default', fnArgs);
};
EasyPromise.prototype.proceedTo = function (name, fnArgs) {
	//Execute the next callback (if it exists)
	if(this.children[name]) {
		this.children[name].arguments = this.children[name].arguments.concat(fnArgs);
		this.children[name].execute.call(this.children[name]);
	}
};
EasyPromise.prototype.proceedWith = function (callbackPrependArgs, fnArgs) {
	//Prepends custom args to the child's callback functions
	this.children['default'].prepend(callbackPrependArgs);
	this.proceed(fnArgs);
};
EasyPromise.prototype.proceedToWith = function (name, callbackPrependArgs, fnArgs) {
	//Prepends custom args to the child's callback functions for the specified child promise name
	this.children[name].prepend(callbackPrependArgs);
	this.proceedTo(name, fnArgs);
};
EasyPromise.prototype.define = function () {
	//Defines a child promise for this current promise
	var args = Array.prototype.slice.call(arguments);
	var name = args.shift();
	var promise = new EasyPromise(args);
	promise.parent = this;
	this.children[name] = promise;
	return this;
};
EasyPromise.prototype.defineq = function () {
	//Defines a promise that runs another promise (Q-style)
	var args = Array.prototype.slice.call(arguments);
	var promise = this.define.apply(this, args);
	promise._qFlag = true;
	return promise;
};
EasyPromise.prototype.then = function () {
	var args = Array.prototype.slice.call(arguments);
	args.unshift('default');
	EasyPromise.prototype.define.apply(this, args);
	return this.children['default'];
};
EasyPromise.prototype.thenq = function () {
	var args = Array.prototype.slice.call(arguments);
	var promise = this.then.apply(this, args);
	promise._qFlag = true;
	return promise;
};
EasyPromise.prototype.after = function (fn) {
	//Occurs after a callback is run but before the next promise
	this.afterFn = fn;

	return this;
};
EasyPromise.prototype.before = function (fn) {
	//Occurs before the asynchronous function is run
	this.beforeFn = fn;

	return this;
};
EasyPromise.prototype.resolve = function () {
	//For Q-styled chaining, calls the success callback
	var args = Array.prototype.slice.call(arguments);
	this._finalArgs = args;
	this._hasError = false;
	this.getRoot().status = EasyPromise.STATUS_CODES.CLOSED;
	this.status = EasyPromise.STATUS_CODES.CLOSED;
};
EasyPromise.prototype.reject = function () {
	//For Q-styled chaining, calls the error callback
	var args = Array.prototype.slice.call(arguments);
	this._finalArgs = args;
	this._hasError = true;
	this.getRoot().status = EasyPromise.STATUS_CODES.CLOSED;
	this.status = EasyPromise.STATUS_CODES.CLOSED;
};
EasyPromise.prototype.getRoot = function () {
	//Find the root promise
	if(!this.parent)
		return this;
	else
		return this.parent.getRoot();
};
EasyPromise.prototype.finish = function (fn) {
	//Attach a function to run when the full promise chain is finished (attaches to root promise only)
	this.getRoot().finishFn = fn; //Function to run when a promise chain finishes
	return this;
};
EasyPromise.prototype.error = function (fn) {
	//Handle errors for a particular promise
	this.errorFn = fn;

	return this;
};
EasyPromise.prototype.catch = function (fn) {
	//Handle errors for all promises. At this point only run() will be exposed
	this.getRoot()._catchFlag = true;
	this.getRoot().catchFn = fn;

	return this;
};

//Static functions
EasyPromise.create = function () {
	//Starts chaining a promise. (The first promise will have a null parent)
	var args = Array.prototype.slice.call(arguments);
	var promise = new EasyPromise(args);
	return promise;
}
EasyPromise.createq = function () {
	//Starts chaining a promise. (The first promise will have a null parent)
	var args = Array.prototype.slice.call(arguments);
	if(args.length > 0 && args[0] && args[0]._isEasyPromise)
		throw new Error("Error, EasyPromise.createq() does not accept a promise object directly. Please supply a function instead, or try using EasyPromise.create()");
	var promise = EasyPromise.create.apply(EasyPromise, args);
	promise._qFlag = true;

	return promise;
}<|endoftext|>


<commit_before>var request = require("request");
var FetchedRepo = require('../Schemas/fetchedRepos.js').FetchedRepo;
var Results = require('../Schemas/result.js').Results;
//var api = require('../api.js');
var db = require('../Schemas/config.js');

var pubnubPublishKey = process.env.PUBNUB_PUBLISH_KEY || api.PUBNUB_PUBLISH_KEY;
var pubnubSubscribeKey = process.env.PUBNUB_SUBSCRIBE_KEY || api.PUBNUB_SUBSCRIBE_KEY;
var pubnub = require("pubnub")({
  ssl: true, // <- enable TLS Tunneling over TCP
  publish_key: pubnubPublishKey,
  subscribe_key: pubnubSubscribeKey
});

String.prototype.contains = function(str, ignoreCase) {
  return (ignoreCase ? this.toUpperCase() : this)
    .indexOf(ignoreCase ? str.toUpperCase() : str) >= 0;
};
// sample url just for testing
// REGEX /\S*.js\w*/gi
var repoObjs;
var numFilesToParse;
var reposFound = [];

var parseFiles = function() {
  FetchedRepo.find(function(err, data) {
    if (err) {
      throw err;
    } else {
      repoObjs = data;
      numFilesToParse = repoObjs.length;
      var interval = setInterval(function(){
        if(repoObjs.length > 0){
          parseForJS(repoObjs.pop());
        } else {
          clearInterval(interval);
          emitPubNubEvent();
        }
      }, 100);
    }
  });
};

var parseForJS = function(obj) {
  var result;
  var repoData = {
    repoLink: obj.file_url,
    libraryCollection: {
      react: false,
      angular: false,
      ember: false,
      backbone: false,
      mithril: false,
      polymer: false,
      flight: false,
      capuccino: false,
      spine: false,
      aurelia: false
    }
  };
  request(obj.file_url, function(error, response, body) {
    // create an object to track framework occurences
    if (!error && response.statusCode == 200) {
      // parse raw html for all strings ending in js
      if(obj.file_url.match(/package\.json/) !== null && reposFound.indexOf(obj.repo_namei + 'h') === -1){
        body = JSON.parse(body);
	      var dependencies = body.dependencies;
        for(var dep in dependencies){
          // loop through our comparators
			    for(var key in repoData.libraryCollection){
				    if(dep.contains(key, true)){
					    reposFound.push(obj.repo_name + 'j');
              repoData.libraryCollection[key] = true;
              console.log('STORING PACKAGE: ' + obj.repo_name);
					    // flag comparator as true if found
				    }
			    }
		    }
      }

      if(obj.file_url.match(/index\.html/) !== null && reposFound.indexOf(obj.repo_name + 'j') === -1) {
        var test = body.match(/\S*.js\w*/gi);
        if (test !== null) {
          for (var i = 0; i < test.length; i++) {
            // loop through the array of matches
            test[i] = test[i].match(/[^/]*$/gi);
            var foundlib = test[i][0];
            for (var key2 in repoData.libraryCollection) {
              // compare each framework in our collection
              // to see if that string is contained in our js strings
              if (foundlib.contains(key2, true)) {
                repoData.libraryCollection[key2] = true;
                reposFound.push(obj.repo_name = 'h');
                // set that framework to true indicating use
                console.log('STORING INDEX: ' + obj.repo_name);
              }
            }
          }
        }
      }

      var repoStats = new Results({
        repo_name: obj.repo_name,
        repo_url: obj.repo_url,
        file_url: obj.file_url,
        repo_data: JSON.stringify(repoData)
      });
      repoStats.save(function(err) {
        if(err){
          console.log(err);
        }
        FetchedRepo.find({
          repo_name: obj.repo_name
        }).remove(function(){
          numFilesToParse --;
        }).exec();
      });
    }
  });
};

// LISTEN ON PUBNUB MESSAGES !
pubnub.subscribe({
  channel: "gitit_messages",
  callback: function(message) {
    console.log("parseReposWorker > ", message);
    if (message.type === 'fetchFilesWorker_job_complete') {
      parseFiles();
    }
  }
});

var emitPubNubEvent = function() {
  var message = {
    "type": "parseReposWorker_job_complete"
  };

  pubnub.publish({
    channel: 'gitit_messages',
    message: message,
    callback: function(e) {
      console.log("SUCCESS!", e);
    },
    error: function(e) {
      console.log("FAILED! RETRY PUBLISH!", e);
    }
  });
};

<commit_msg>fixing duplication error<commit_after>var request = require("request");
var FetchedRepo = require('../Schemas/fetchedRepos.js').FetchedRepo;
var Results = require('../Schemas/result.js').Results;
//var api = require('../api.js');
var db = require('../Schemas/config.js');

var pubnubPublishKey = process.env.PUBNUB_PUBLISH_KEY || api.PUBNUB_PUBLISH_KEY;
var pubnubSubscribeKey = process.env.PUBNUB_SUBSCRIBE_KEY || api.PUBNUB_SUBSCRIBE_KEY;
var pubnub = require("pubnub")({
  ssl: true, // <- enable TLS Tunneling over TCP
  publish_key: pubnubPublishKey,
  subscribe_key: pubnubSubscribeKey
});

String.prototype.contains = function(str, ignoreCase) {
  return (ignoreCase ? this.toUpperCase() : this)
    .indexOf(ignoreCase ? str.toUpperCase() : str) >= 0;
};
// sample url just for testing
// REGEX /\S*.js\w*/gi
var repoObjs;
var numFilesToParse;
var reposFound = [];

var parseFiles = function() {
  FetchedRepo.find(function(err, data) {
    if (err) {
      throw err;
    } else {
      repoObjs = data;
      numFilesToParse = repoObjs.length;
      var interval = setInterval(function(){
        if(repoObjs.length > 0){
          parseForJS(repoObjs.pop());
        } else {
          clearInterval(interval);
          emitPubNubEvent();
        }
      }, 100);
    }
  });
};

var parseForJS = function(obj) {
  var result;
  var repoData = {
    repoLink: obj.file_url,
    libraryCollection: {
      react: false,
      angular: false,
      ember: false,
      backbone: false,
      mithril: false,
      polymer: false,
      flight: false,
      capuccino: false,
      spine: false,
      aurelia: false
    }
  };
  request(obj.file_url, function(error, response, body) {
    // create an object to track framework occurences
    if (!error && response.statusCode == 200) {
      // parse raw html for all strings ending in js
      if(obj.file_url.match(/package\.json/) !== null && reposFound.indexOf(obj.repo_namei + 'h') === -1){
        body = JSON.parse(body);
	      var dependencies = body.dependencies;
        for(var dep in dependencies){
          // loop through our comparators
			    for(var key in repoData.libraryCollection){
				    if(dep.contains(key, true)){
					    reposFound.push(obj.repo_name + 'j');
              repoData.libraryCollection[key] = true;
              console.log('STORING PACKAGE: ' + obj.repo_name);
					    // flag comparator as true if found
				    }
			    }
		    }
      }

      if(obj.file_url.match(/index\.html/) !== null && reposFound.indexOf(obj.repo_name + 'j') === -1) {
        var test = body.match(/\S*.js\w*/gi);
        if (test !== null) {
          for (var i = 0; i < test.length; i++) {
            // loop through the array of matches
            test[i] = test[i].match(/[^/]*$/gi);
            var foundlib = test[i][0];
            for (var key2 in repoData.libraryCollection) {
              // compare each framework in our collection
              // to see if that string is contained in our js strings
              if (foundlib.contains(key2, true)) {
                repoData.libraryCollection[key2] = true;
                reposFound.push(obj.repo_name = 'h');
                // set that framework to true indicating use
                console.log('STORING INDEX: ' + obj.repo_name);
              }
            }
          }
        }
      }

      var repoStats = new Results({
        repo_name: obj.repo_name,
        repo_url: obj.repo_url,
        file_url: obj.file_url,
        repo_data: JSON.stringify(repoData)
      });
      repoStats.save(function(err) {
        if(err){
          console.log('Ignoring duplicate entry');
        }
        FetchedRepo.find({
          repo_name: obj.repo_name
        }).remove(function(){
          numFilesToParse --;
        }).exec();
      });
    }
  });
};

// LISTEN ON PUBNUB MESSAGES !
pubnub.subscribe({
  channel: "gitit_messages",
  callback: function(message) {
    console.log("parseReposWorker > ", message);
    if (message.type === 'fetchFilesWorker_job_complete') {
      parseFiles();
    }
  }
});

var emitPubNubEvent = function() {
  var message = {
    "type": "parseReposWorker_job_complete"
  };

  pubnub.publish({
    channel: 'gitit_messages',
    message: message,
    callback: function(e) {
      console.log("SUCCESS!", e);
    },
    error: function(e) {
      console.log("FAILED! RETRY PUBLISH!", e);
    }
  });
};

<|endoftext|>


<commit_before>/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, strict:true, trailing:true, white:true */
/*global X:true, issue:true */

(function () {
  "use strict";

  var _ = X._;

  /**
    Session object for datasource.

    @class
    @extends X.Object
   */
  X.Session = X.Object.extend(/** @lends X.Session.prototype */{

    isReady: false,
    isLoaded: false,

    init: function () {
      var id = this.get("id"), sid = this.get("sid"),
          selected = this.get("selected"), logout = this.get("logout");
      if (logout) {
        this.load(_.bind(this.didLoadForLogout, this));
      } else if (!sid) {
        X.Session.init.call(this);
        process.nextTick(_.bind(function () { this.set("isReady", true); }, this));
        this.commit();
      } else if (selected && id && sid) {
        this.load(_.bind(this.didLoadForSelection, this));
      } else {
        this.load();
      }
    },

    //.....................................
    // ACTION METHODS
    //
    /**
      Commit.

     */
    commit: function () {
      //X.log("commit(): ", _util.inspect(this));

      var K = this.get("model"), k;

      if (this.get("isLoaded")) {
        // we were loaded so a commit needs to update
        // not create a new session entry
        k = {
          id: this.get("id"),
          sid: this.get("sid")
        };
        return K.findOne(k, _.bind(this.updateForCommit, this));
      }

      k = new K(this.get("details"));
      k.save(_.bind(this.didCommit, this));
    },
    /**
      Update for commit

     */
    updateForCommit: function (err, res) {
      //X.log("updateForCommit(): ");

      var details = this.get("details"), key;

      if (err || !res) {
        return this.set("error", "could not update");
      }

      for (key in details) {
        if (!details.hasOwnProperty(key)) continue;
        res[key] = details[key];
      }

      res.save(_.bind(this.didCommit, this));
    },

    //.....................................
    // POST-ACTION METHODS
    //

    didLoad: function (err, res) {
      //X.log("didLoad(): ", err, res);

      if (err) {
        return this.set("error", err.message, err.stack);
      } else if (!res) {
        // something is wrong, we could not find the session that
        // was requested

        return this.set("error", "could not retrieve session");
      }

      X.mixin(this, res.toObject());

      this.set("isLoaded", true);

      this.created = res.created;
      this.checksum = res.checksum;
      this.lastModified = X.Session.timestamp();
      this.set("isReady", true);

      //this.isReadyDidChange();

      // commit update?
      process.nextTick(_.bind(this.commit, this));
    },

    didCommit: function (err) {
      //X.log("didCommit(): ", err);

      if (err) {
        this.set("error", err.message, err.stack);
      } else {
        // TODO: this _can_ be done lazily right?
        // this.set("isReady", true);
      }
    },

    didLoadForSelection: function (err, res) {
      //X.debug("didLoadForSelection(): ", res);
      var organizations = this.get("organizations"), selected, found;
      if (!organizations || organizations.length <= 0) {
        return this.set("error", "no organizations available for selection");
      } else if (err) { return this.didLoad(err, res); }
      selected = this.get("selected");
      if ((found = _.find(organizations, function (o) {
        return o.name === selected? true: false;
      }))) {
        // TODO: this needs to seriously be reevaluated
        // as it seems like if for any reason the session
        // already had an organization listed (somehow)
        // it will be overwritten and cause unknown
        // behaviors as a result
        this.set("organization", selected);
        this.set("username", found.username);
        this.didLoad(null, res);
      } else this.set("error", "invalid organization selected for user");
    },

    didLoadForLogout: function (err, res) {
      if (err) {
        return this.set("error", "could not load the session to logout");
      }
      // successfully loaded the session which means its valid
      // lets go ahead and logout by destroying ourselves
      this.set("isLoaded", true);
      this.destroy(res);
    },

    destroy: function (session) {
      if (session && session.remove) session.remove();
      this.set("isReady", true);
    },

    query: function (query, callback) {
      var organization = this.get("organization"), orig = callback;
      if (!this.get("isLoaded")) {
        X.debug("Error: cannot query unloaded session");
        return this.set("error", "cannot query unloaded session");
      }
      callback = _.bind(this.didQuery, this, orig);
      //X.debug("query: %@".f(query));
      X.database.query(organization, query, callback);
      return this;
    },

    didQuery: function (callback, err, res) {
      if (err) return callback(err);
      if (res) {
        callback(null, res);
      } else this.set("error", "no result from query");
    },

    //.....................................
    // PROPERTY METHODS
    //

    model: function () {
      return X.Session.cache.model("Session");
    }.property(),

    details: function () {
      var d = {
        id: this.get("id"),
        sid: this.get("sid"),
        lastModified: this.get("lastModified") || X.Session.timestamp(),
        created: this.get("created"),
        checksum: "",
        username: this.get("username"),
        organization: this.get("organization"),
        organizations: this.get("organizations")
      };
      return d;
    }.property(),

    //.....................................
    // PROXIED METHODS
    //

    load: function () {
      return X.Session.load.apply(this, arguments);
    }
  });

  X.mixin(X.Session, /** @lends X.Session */{

    cache: null,

    load: function (callback) {
      //X.log("load(): ");

      var K = this.get("model"), details = {
        id: this.get("id"),
        sid: this.get("sid")
      };

      if (!callback) callback = _.bind(this.didLoad, this);

      //X.log("load(): ", details);

      K.findOne(details, callback);
      return this;
    },

    checksum: function () {
      //var hash = X.Session.sha1hash(), data = ;
      //data = X.typeOf(data) === X.T_HASH ? X.json(data) : data;
      //return hash.update(data).digest('hex');
    },

    init: function () {
      this.sid = X.Session.generateSID();
      this.created = X.Session.timestamp();
    },

    generateSID: function () {
      var hash = this.md5hash();
      return hash.update(Math.random().toString()).digest('hex');
    },

    timestamp: function () { return new Date().getTime(); },

    sha1hash: function () { return X.crypto.createHash('sha1'); },

    md5hash: function () { return X.crypto.createHash('md5'); },

    /**
      Polls cache and logs uses out upon session timeout. This method
      can be used to do any actions that are driven from the cache.
     */
    pollCache: function () {
      var K = X.Session.cache.model("Session"), i = 0, len, diff, ok, now;
      K.find(function (err, res) {
        if (err) {
          // we have serious issues if we have an error here!
          return issue(X.fatal("error polling cache", err.message, err.stack));
        }

        ok = (X.options.datasource.sessionTimeout || 15) * 60000;
        now = X.Session.timestamp();

        if (res && res.length > 0) {
          len = res.length;
          for (; i < len; ++i) {
            diff = Math.abs(now - (res[i].lastModified || 1000000000));
            if (diff > ok) {
              //console.log("removing ", res[i]);
              res[i].remove();
            } //else { console.log("not removing ", res[i]); }
          }
        }
      });
    },

    isActiveSession: function () {
    }
  });

  X.run(function () {
    X.cachePollingInterval = setInterval(X.Session.pollCache, 60000);
    X.addCleanupTask(function () {
      clearInterval(X.cachePollingInterval);
    });
  });
}());
<commit_msg>report session errors via computed property<commit_after>/*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, strict:true, trailing:true, white:true */
/*global X:true, issue:true */

(function () {
  "use strict";

  var _ = X._;

  /**
    Session object for datasource.

    @class
    @extends X.Object
   */
  X.Session = X.Object.extend(/** @lends X.Session.prototype */{

    isReady: false,
    isLoaded: false,

    init: function () {
      var id = this.get("id"), sid = this.get("sid"),
          selected = this.get("selected"), logout = this.get("logout");
      if (logout) {
        this.load(_.bind(this.didLoadForLogout, this));
      } else if (!sid) {
        X.Session.init.call(this);
        process.nextTick(_.bind(function () { this.set("isReady", true); }, this));
        this.commit();
      } else if (selected && id && sid) {
        this.load(_.bind(this.didLoadForSelection, this));
      } else {
        this.load();
      }
    },

    //.....................................
    // ACTION METHODS
    //
    /**
      Commit.

     */
    commit: function () {
      //X.log("commit(): ", _util.inspect(this));

      var K = this.get("model"), k;

      if (this.get("isLoaded")) {
        // we were loaded so a commit needs to update
        // not create a new session entry
        k = {
          id: this.get("id"),
          sid: this.get("sid")
        };
        return K.findOne(k, _.bind(this.updateForCommit, this));
      }

      k = new K(this.get("details"));
      k.save(_.bind(this.didCommit, this));
    },
    /**
      Update for commit

     */
    updateForCommit: function (err, res) {
      //X.log("updateForCommit(): ");

      var details = this.get("details"), key;

      if (err || !res) {
        return this.set("error", "could not update");
      }

      for (key in details) {
        if (!details.hasOwnProperty(key)) continue;
        res[key] = details[key];
      }

      res.save(_.bind(this.didCommit, this));
    },

    //.....................................
    // POST-ACTION METHODS
    //

    didLoad: function (err, res) {
      //X.log("didLoad(): ", err, res);

      if (err) {
        return this.set("error", err.message, {stack: err.stack});
      } else if (!res) {
        // something is wrong, we could not find the session that
        // was requested
        return this.set("error", "could not retrieve session", {code: "INVALID_SESSION"});
      }

      X.mixin(this, res.toObject());

      this.set("isLoaded", true);

      this.created = res.created;
      this.checksum = res.checksum;
      this.lastModified = X.Session.timestamp();
      this.set("isReady", true);

      //this.isReadyDidChange();

      // commit update?
      process.nextTick(_.bind(this.commit, this));
    },

    didCommit: function (err) {
      //X.log("didCommit(): ", err);

      if (err) {
        this.set("error", err.message, err.stack);
      } else {
        // TODO: this _can_ be done lazily right?
        // this.set("isReady", true);
      }
    },

    didLoadForSelection: function (err, res) {
      //X.debug("didLoadForSelection(): ", res);
      var organizations = this.get("organizations"), selected, found;
      if (!organizations || organizations.length <= 0) {
        return this.set("error", "no organizations available for selection");
      } else if (err) { return this.didLoad(err, res); }
      selected = this.get("selected");
      if ((found = _.find(organizations, function (o) {
        return o.name === selected? true: false;
      }))) {
        // TODO: this needs to seriously be reevaluated
        // as it seems like if for any reason the session
        // already had an organization listed (somehow)
        // it will be overwritten and cause unknown
        // behaviors as a result
        this.set("organization", selected);
        this.set("username", found.username);
        this.didLoad(null, res);
      } else this.set("error", "invalid organization selected for user");
    },

    didLoadForLogout: function (err, res) {
      if (err) {
        return this.set("error", "could not load the session to logout");
      }
      // successfully loaded the session which means its valid
      // lets go ahead and logout by destroying ourselves
      this.set("isLoaded", true);
      this.destroy(res);
    },

    destroy: function (session) {
      if (session && session.remove) session.remove();
      this.set("isReady", true);
    },

    query: function (query, callback) {
      var organization = this.get("organization"), orig = callback;
      if (!this.get("isLoaded")) {
        X.warn("Error: cannot query unloaded session");
        return this.set("error", "cannot query unloaded session");
      }
      callback = _.bind(this.didQuery, this, orig);
      //X.debug("query: %@".f(query));
      X.database.query(organization, query, callback);
      return this;
    },

    didQuery: function (callback, err, res) {
      if (err) return callback(err);
      if (res) {
        callback(null, res);
      } else this.set("error", "no result from query");
    },

    //.....................................
    // PROPERTY METHODS
    //

    model: function () {
      return X.Session.cache.model("Session");
    }.property(),

    details: function () {
      var d = {
        id: this.get("id"),
        sid: this.get("sid"),
        lastModified: this.get("lastModified") || X.Session.timestamp(),
        created: this.get("created"),
        checksum: "",
        username: this.get("username"),
        organization: this.get("organization"),
        organizations: this.get("organizations")
      };
      return d;
    }.property(),

    error: function () {
      if (arguments.length === 0) return this._error;
      var err = this._error = {}, args = X.$A(arguments);
      err.reason = {};
      err.reason.message = args.shift();
      while (args.length > 0) {
        X.mixin(err, args.shift());
      }
    }.property(),

    //.....................................
    // PROXIED METHODS
    //

    load: function () {
      return X.Session.load.apply(this, arguments);
    }
  });

  X.mixin(X.Session, /** @lends X.Session */{

    cache: null,

    load: function (callback) {
      //X.log("load(): ");

      var K = this.get("model"), details = {
        id: this.get("id"),
        sid: this.get("sid")
      };

      if (!callback) callback = _.bind(this.didLoad, this);

      //X.log("load(): ", details);

      K.findOne(details, callback);
      return this;
    },

    checksum: function () {
      //var hash = X.Session.sha1hash(), data = ;
      //data = X.typeOf(data) === X.T_HASH ? X.json(data) : data;
      //return hash.update(data).digest('hex');
    },

    init: function () {
      this.sid = X.Session.generateSID();
      this.created = X.Session.timestamp();
    },

    generateSID: function () {
      var hash = this.md5hash();
      return hash.update(Math.random().toString()).digest('hex');
    },

    timestamp: function () { return new Date().getTime(); },

    sha1hash: function () { return X.crypto.createHash('sha1'); },

    md5hash: function () { return X.crypto.createHash('md5'); },

    /**
      Polls cache and logs uses out upon session timeout. This method
      can be used to do any actions that are driven from the cache.
     */
    pollCache: function () {
      var K = X.Session.cache.model("Session"), i = 0, len, diff, ok, now;
      K.find(function (err, res) {
        if (err) {
          // we have serious issues if we have an error here!
          return issue(X.fatal("error polling cache", err.message, err.stack));
        }

        ok = (X.options.datasource.sessionTimeout || 15) * 60000;
        now = X.Session.timestamp();

        if (res && res.length > 0) {
          len = res.length;
          for (; i < len; ++i) {
            diff = Math.abs(now - (res[i].lastModified || 1000000000));
            if (diff > ok) {
              //console.log("removing ", res[i]);
              res[i].remove();
            } //else { console.log("not removing ", res[i]); }
          }
        }
      });
    },

    isActiveSession: function () {
    }
  });

  X.run(function () {
    X.cachePollingInterval = setInterval(X.Session.pollCache, 60000);
    X.addCleanupTask(function () {
      clearInterval(X.cachePollingInterval);
    });
  });
}());
<|endoftext|>


<commit_before>var Flow = require('./flow/flow');

// init flow with core module
Flow({

    // load module bundles and return the entry-point exports
    module: function (name, callback) {

        // crate script dom elemeent
        var node = document.createElement('script');

        node.onload = function () {
            callback(null, require(name));
        };

        // set url and append dom script elm to the document head
        node.src = '/@/' + name + '/client.js';
        document.head.appendChild(node);
        node.remove();
    },
    composition: '@C',
    markup: '@M',
    cache: function () {},
    log: function (err) {return err} //require('./logs') ||
});

var ws = new WebSocket('ws://' + location.host);

ws.onopen = function () {
    ws.send(JSON.stringify(['instance', 'event', {from: 'client'}]));
};
ws.onmessage = function (msg) {
    console.log(JSON.parse(msg.data));
};<commit_msg>use secure websockets<commit_after>var Flow = require('./flow/flow');

// init flow with core module
Flow({

    // load module bundles and return the entry-point exports
    module: function (name, callback) {

        // crate script dom elemeent
        var node = document.createElement('script');

        node.onload = function () {
            callback(null, require(name));
        };

        // set url and append dom script elm to the document head
        node.src = '/@/' + name + '/client.js';
        document.head.appendChild(node);
        node.remove();
    },
    composition: '@C',
    markup: '@M',
    cache: function () {},
    log: function (err) {return err} //require('./logs') ||
});

var ws = new WebSocket('wss://' + location.host);

ws.onopen = function () {
    ws.send(JSON.stringify(['instance', 'event', {from: 'client'}]));
};
ws.onmessage = function (msg) {
    console.log(JSON.parse(msg.data));
};<|endoftext|>


<commit_before>#! /usr/bin/env node
/*
 * git-tool-uk
 * https://github.com/kayaniu/git-tool
 *
 * Copyright (c) 2015 Umair Kayani
 * Licensed under the MIT license.
 */

var fs = require('fs')
    ,p = require('path')
    ,inquirer = require('inquirer')
    ,_ = require('lodash')
    ,git = require('./git-utils/git-utils')
    ,parseArgs = require('minimist');

var ops = {checkout: 'checkout', pull:'pull', fetch:'fetch', status:'status', stash: 'stash'};

var argv = parseArgs(process.argv.slice(2), {boolean:['select', 'help']});
console.log(argv);
var wd = process.cwd();

main(wd, argv);

function main(workingDir, argv){

    if (argv.help){
        showHelp();
        return;
    }

    if (!validateArgs(argv)) {
        console.log('Invalid arguments');
        showHelp();
        return;
    }

    var op = argv._[0];
    var config = {workingDir: workingDir,
            argv: argv,
            condition: git.isGitRepository,
            options: null};

    if (op.toLowerCase() == ops.pull){

       config.operation = pull;
       command(config);
    }
    else if (op.toLowerCase() == ops.checkout){

        // validation
        if (!('b' in argv)) {
            console.log('You must specify a branch name with the -b param');
            return;
        }

        config.options = {branch: argv.b};
        config.operation = checkout;

        command(config);
    }
    else if (op.toLowerCase() == ops.fetch){
        config.operation = fetch;
        command(config);
    }
    else if (op.toLowerCase() == ops.status){
        config.operation = status;
        command(config);
    }
    else if (op.toLowerCase() == ops.stash){
        config.operation = stash;
        if ('a' in argv) config.options = {action: argv.a.toLowerCase()};
        command(config);
    }
    else {
        console.log('Invalid arguments');
        showHelp();
    }
}

/**
 * Given a config object, run a command in the CL
 * @param config {workingDir:s, argv:o, condition:f, operation:f, options:(o | null)}
 * Properties:
 * workingDir: path of working directory
 * argv: object with command line arguments as properties
 * condition: a boolean function taking a (path) and returning if the folder/file is a match
 * operation: a function taking (folders, options) where folders is a list of folders, options (see below)
 * options: an object of options to pass to the operation which will be executed
 */
function command(config){

    var options = config.options;

    var select = config.argv.select;

    var handler = function handleFolder(folders){
        config.operation(folders, options);
    };

    getDirectories(config.workingDir, config.condition, function(err, folders){

        if (err !== null) {
            console.log("Could not retrieve directories");
            return;
        }

        if (folders.length == 0){
            console.log('No repositories found.');
            return;
        }

        // make sure they want to select, also make sure there are enough directories to make selection useful
        if (select && folders.length > 1){
            filterDirectories("Repositories", folders, handler);
        }
        else {
            handler(folders);
        }

    });
}

/**
 * Do a sanity check on the args
 * @param argv
 * @returns {boolean}
 */
function validateArgs(argv){

    return argv._.length != 1 ? false : true;
}

function showHelp(){
    console.log('usage: [operation] [params] [--select]');
    console.log('operations:');
    console.log('\tpull');
    console.log('\tcheckout');
    console.log('params:');
    console.log('\t-b branchname');
    console.log('--select - use this flag to select which folders to operate on');
    console.log('Examples:');
    console.log('To do a git pull op on selected folders');
    console.log('git-tool pull --select');
    console.log('To do a git checkout on selected folders');
    console.log('git-tool checkout -b release/test --select');
}

/**
 * Given a path and boolean operator accepting a path, returns a list of directories
 * which pass the boolean operator condition, calls the callback with the params (err, folders) where folders is a list
 * of folder objects {name: name, path: somepath}
 * @param path
 * @param condition
 * @param callback
 */
function getDirectories(path, condition, callback){

    fs.readdir(path, function(err, files){

        if (err !== null){
            callback(err);
            return;
        }

        var folders = [];

        for (var i in files){

            var fname = files[i];
            var filePath = p.join(path, fname);

            if (condition(filePath)) folders.push({name: fname, path: filePath});
        }

        callback(null, folders);
    });

}

/**
 * Given a name and list of folders, present a command line prompt to filter the list
 * A callback is called once the user has selected folders, with params (folders) which is a list of filtered/selected
 * folders
 * @param name
 * @param folders
 * @param callback
 */
function filterDirectories(name, folders, callback){

    // transform into a format appropriate for inquirer
    var choices = _.transform(folders, function(result, o){
        result.push({name: o.name, value: o.path});
    });

    inquirer.prompt([
        {
            type: "checkbox",
            message: "Select " + name,
            name: name,
            choices: choices,
            validate: function(answer){
                if (answer.length < 1){
                    return "You must choose at least one.";
                }

                return true;
            }
        }
    ], function(answers){

        var paths = answers[name];
        var filteredFolders = folders.filter(function(el){
            if (paths.indexOf(el.path) >= 0) return true;
        });

        callback(filteredFolders);

    });
}

function pull(selection, options){
    handleSelection(selection, git.pull, options);
}

function checkout(selection, options){
    handleSelection(selection, git.checkout, options);
}

function fetch(selection, options){
    handleSelection(selection, git.fetch, options);
}

function status(selection, options){
    handleSelection(selection, git.status, options);
}

function stash(selection, options){
    handleSelection(selection, git.stash, options);
}

/**
 * Execute an action on each selected folder
 * @param selection
 */
function handleSelection(selection, action, options){

    selection.forEach(function(o){
        console.log("Operating on " + o.name);
        action(o.path, options, function(err, command, stdout){
            if (err !== null) {;
                console.log("Failed to execute command " + command + " on " + o.name);
                console.log(err);
                return;
            }
            console.log("Executed " + command + " on " + o.name);
            console.log(stdout);
        });
    });

}

<commit_msg>removed a debug statement<commit_after>#! /usr/bin/env node
/*
 * git-tool-uk
 * https://github.com/kayaniu/git-tool
 *
 * Copyright (c) 2015 Umair Kayani
 * Licensed under the MIT license.
 */

var fs = require('fs')
    ,p = require('path')
    ,inquirer = require('inquirer')
    ,_ = require('lodash')
    ,git = require('./git-utils/git-utils')
    ,parseArgs = require('minimist');

var ops = {checkout: 'checkout', pull:'pull', fetch:'fetch', status:'status', stash: 'stash'};

var argv = parseArgs(process.argv.slice(2), {boolean:['select', 'help']});
var wd = process.cwd();

main(wd, argv);

function main(workingDir, argv){

    if (argv.help){
        showHelp();
        return;
    }

    if (!validateArgs(argv)) {
        console.log('Invalid arguments');
        showHelp();
        return;
    }

    var op = argv._[0];
    var config = {workingDir: workingDir,
            argv: argv,
            condition: git.isGitRepository,
            options: null};

    if (op.toLowerCase() == ops.pull){

       config.operation = pull;
       command(config);
    }
    else if (op.toLowerCase() == ops.checkout){

        // validation
        if (!('b' in argv)) {
            console.log('You must specify a branch name with the -b param');
            return;
        }

        config.options = {branch: argv.b};
        config.operation = checkout;

        command(config);
    }
    else if (op.toLowerCase() == ops.fetch){
        config.operation = fetch;
        command(config);
    }
    else if (op.toLowerCase() == ops.status){
        config.operation = status;
        command(config);
    }
    else if (op.toLowerCase() == ops.stash){
        config.operation = stash;
        if ('a' in argv) config.options = {action: argv.a.toLowerCase()};
        command(config);
    }
    else {
        console.log('Invalid arguments');
        showHelp();
    }
}

/**
 * Given a config object, run a command in the CL
 * @param config {workingDir:s, argv:o, condition:f, operation:f, options:(o | null)}
 * Properties:
 * workingDir: path of working directory
 * argv: object with command line arguments as properties
 * condition: a boolean function taking a (path) and returning if the folder/file is a match
 * operation: a function taking (folders, options) where folders is a list of folders, options (see below)
 * options: an object of options to pass to the operation which will be executed
 */
function command(config){

    var options = config.options;

    var select = config.argv.select;

    var handler = function handleFolder(folders){
        config.operation(folders, options);
    };

    getDirectories(config.workingDir, config.condition, function(err, folders){

        if (err !== null) {
            console.log("Could not retrieve directories");
            return;
        }

        if (folders.length == 0){
            console.log('No repositories found.');
            return;
        }

        // make sure they want to select, also make sure there are enough directories to make selection useful
        if (select && folders.length > 1){
            filterDirectories("Repositories", folders, handler);
        }
        else {
            handler(folders);
        }

    });
}

/**
 * Do a sanity check on the args
 * @param argv
 * @returns {boolean}
 */
function validateArgs(argv){

    return argv._.length != 1 ? false : true;
}

function showHelp(){
    console.log('usage: [operation] [params] [--select]');
    console.log('operations:');
    console.log('\tpull');
    console.log('\tcheckout');
    console.log('params:');
    console.log('\t-b branchname');
    console.log('--select - use this flag to select which folders to operate on');
    console.log('Examples:');
    console.log('To do a git pull op on selected folders');
    console.log('git-tool pull --select');
    console.log('To do a git checkout on selected folders');
    console.log('git-tool checkout -b release/test --select');
}

/**
 * Given a path and boolean operator accepting a path, returns a list of directories
 * which pass the boolean operator condition, calls the callback with the params (err, folders) where folders is a list
 * of folder objects {name: name, path: somepath}
 * @param path
 * @param condition
 * @param callback
 */
function getDirectories(path, condition, callback){

    fs.readdir(path, function(err, files){

        if (err !== null){
            callback(err);
            return;
        }

        var folders = [];

        for (var i in files){

            var fname = files[i];
            var filePath = p.join(path, fname);

            if (condition(filePath)) folders.push({name: fname, path: filePath});
        }

        callback(null, folders);
    });

}

/**
 * Given a name and list of folders, present a command line prompt to filter the list
 * A callback is called once the user has selected folders, with params (folders) which is a list of filtered/selected
 * folders
 * @param name
 * @param folders
 * @param callback
 */
function filterDirectories(name, folders, callback){

    // transform into a format appropriate for inquirer
    var choices = _.transform(folders, function(result, o){
        result.push({name: o.name, value: o.path});
    });

    inquirer.prompt([
        {
            type: "checkbox",
            message: "Select " + name,
            name: name,
            choices: choices,
            validate: function(answer){
                if (answer.length < 1){
                    return "You must choose at least one.";
                }

                return true;
            }
        }
    ], function(answers){

        var paths = answers[name];
        var filteredFolders = folders.filter(function(el){
            if (paths.indexOf(el.path) >= 0) return true;
        });

        callback(filteredFolders);

    });
}

function pull(selection, options){
    handleSelection(selection, git.pull, options);
}

function checkout(selection, options){
    handleSelection(selection, git.checkout, options);
}

function fetch(selection, options){
    handleSelection(selection, git.fetch, options);
}

function status(selection, options){
    handleSelection(selection, git.status, options);
}

function stash(selection, options){
    handleSelection(selection, git.stash, options);
}

/**
 * Execute an action on each selected folder
 * @param selection
 */
function handleSelection(selection, action, options){

    selection.forEach(function(o){
        console.log("Operating on " + o.name);
        action(o.path, options, function(err, command, stdout){
            if (err !== null) {;
                console.log("Failed to execute command " + command + " on " + o.name);
                console.log(err);
                return;
            }
            console.log("Executed " + command + " on " + o.name);
            console.log(stdout);
        });
    });

}

<|endoftext|>


<commit_before>var API_URL = "http://api.github.com/repos/";
var githubUser = "tabycat";
var githubPass = "tabycat0";
var githubRepo = "bookmarks";
var Request = require("sdk/request").Request;
var base64 = require("sdk/base64");

exports.getBookmarks = getBookmarks;
exports.setBookmarks = setBookmarks;
/*
callback to decide what you want with the data. the callback will actually
be called many times for each bookmark.
*/
function getBookmarks(callback) {
    Request({
        url: API_URL + githubUser + "/" + githubRepo + "/contents",
        onComplete: function(response) {
            var responseData = JSON.parse(response["text"]);
            for (var i in responseData) {
                Request({
                    url: responseData[i].git_url,
                    onComplete: function(response2) {
                        var innerData = JSON.parse(response2["text"]);
                        callback(innerData);
                    }
                }).get();
            }
        }
    }).get();
}
/*
data will be an array of bookmarks file names, if it is in a folder from
root directory then it is more correctly the path of the bookmark. for ways to format this
see https://developer.github.com/v3/repos/contents/#update-a-file.
The only change is the bookmarks is an array of objects of path and data. for example
[
    { // where this one creates a new one
        path: "newCoolBookmarName",
        data: {
          "message": "my commit message",
          "committer": {
            "name": "Scott Chacon",
            "email": "schacon@gmail.com"
          },
          "content": "bXkgbmV3IGZpbGUgY29udGVudHM="
        }
    },
    {//where this one updates one
        path: "oldSaggyBookmar",
        data: {
          "message": "my commit message",
          "committer": {
            "name": "Scott Chacon",
            "email": "schacon@gmail.com"
          },
          "content": "bXkgdXBkYXRlZCBmaWxlIGNvbnRlbnRz",
          "sha": "329688480d39049927147c162b9d2deaf885005f"
        }
    }
]
there is an optional callback in this one.
*/
function setBookmarks(bookmarks, callback) {
    if (callback) {
        for (var i in bookmarks) {
            var bookmark = bookmarks[i];

            console.log(bookmark);
            console.log("bookmark.data......");
            console.log(JSON.stringify(bookmark.data));

            var authMessage = base64.encode(githubUser+':'+githubPass);
            Request({
                url: API_URL + githubUser + "/" + githubRepo + "/contents/" + bookmark.path,
                onComplete: function(response) {
                    callback(JSON.parse(response["text"]));
                },
                headers: {'Authorization': 'Basic ' + authMessage}
            }).put(JSON.stringify(bookmark.data));
        }
    } else { // same thing but with no onComplete and I didnt want to check this over and over in loop.
        for (var i in bookmarks) {
            var bookmark = bookmarks[i];
            Request({
                url: API_URL + githubUser + "/" + githubRepo + "/contents/" + bookmark.path
            }).put(bookmark.data);
        }
    }
}
<commit_msg>Fixed PUT to GitHub. Finally WORKING!<commit_after>var API_URL = "http://api.github.com/repos/";
var githubUser = "tabycat";
var githubPass = "tabycat0";
var githubRepo = "bookmarks";
var Request = require("sdk/request").Request;
var base64 = require("sdk/base64");

exports.getBookmarks = getBookmarks;
exports.setBookmarks = setBookmarks;
/*
callback to decide what you want with the data. the callback will actually
be called many times for each bookmark.
*/
function getBookmarks(callback) {
    Request({
        url: API_URL + githubUser + "/" + githubRepo + "/contents",
        onComplete: function(response) {
            var responseData = JSON.parse(response["text"]);
            for (var i in responseData) {
                Request({
                    url: responseData[i].git_url,
                    onComplete: function(response2) {
                        var innerData = JSON.parse(response2["text"]);
                        callback(innerData);
                    }
                }).get();
            }
        }
    }).get();
}
/*
data will be an array of bookmarks file names, if it is in a folder from
root directory then it is more correctly the path of the bookmark. for ways to format this
see https://developer.github.com/v3/repos/contents/#update-a-file.
The only change is the bookmarks is an array of objects of path and data. for example
[
    { // where this one creates a new one
        path: "newCoolBookmarName",
        data: {
          "message": "my commit message",
          "committer": {
            "name": "Scott Chacon",
            "email": "schacon@gmail.com"
          },
          "content": "bXkgbmV3IGZpbGUgY29udGVudHM="
        }
    },
    {//where this one updates one
        path: "oldSaggyBookmar",
        data: {
          "message": "my commit message",
          "committer": {
            "name": "Scott Chacon",
            "email": "schacon@gmail.com"
          },
          "content": "bXkgdXBkYXRlZCBmaWxlIGNvbnRlbnRz",
          "sha": "329688480d39049927147c162b9d2deaf885005f"
        }
    }
]
there is an optional callback in this one.
*/
function setBookmarks(bookmarks, callback) {
    if (callback) {
        for (var i in bookmarks) {
            var bookmark = bookmarks[i];

            console.log(bookmark);
            console.log("bookmark.data......");
            console.log(JSON.stringify(bookmark.data));

            var authMessage = base64.encode(githubUser+':'+githubPass);
            Request({
                url: API_URL + githubUser + "/" + githubRepo + "/contents/" + bookmark.path,
                onComplete: function(response) {
                    callback(JSON.parse(response["text"]));
                },
                headers: {'Authorization': 'Basic ' + authMessage},
                content: JSON.stringify(bookmark.data)
            }).put();
        }
    } else { // same thing but with no onComplete and I didnt want to check this over and over in loop.
        for (var i in bookmarks) {
            var bookmark = bookmarks[i];
            Request({
                url: API_URL + githubUser + "/" + githubRepo + "/contents/" + bookmark.path
            }).put(bookmark.data);
        }
    }
}
<|endoftext|>


<commit_before>var fs = require('fs'),
    ejs = require('ejs'),
    request = require('request'),
    querystring = require('querystring')

exports.Client = function(apiKey) {
    var userPosts = function(userId, callback) {
        var url = 'https://www.googleapis.com/plus/v1/people/' + userId + '/activities/public?' + querystring.stringify({key: apiKey})
        request(url, function(error, response, body) {
            if (error) return callback(error)
            try {
                var json = JSON.parse(body)
                if (json.error) throw new Error(json.error.message)
                var posts = []
                json.items.each(function(item) {
                    posts.push({
                        url: item.url,
                        title: postTitle(item),
                        updated: new Date(item.updated)
                    })
                })
                callback(null, posts)
            } catch (error) {
                callback(error)
            }
        })
    }

    return {
        userFeed: function(userId, callback) {
            userPosts(userId, function(error, posts) {
                if (error) return callback(error)

                fs.readFile(__dirname + '/../views/feed.ejs', 'utf8', function(error, template) {
                    if (error) return callback(error)

                    var feed = ejs.render(template, {
                        locals: {
                            profileUrl: 'https://plus.google.com/' + userId,
                            posts: posts
                        }
                    })

                    callback(null, feed)
                })
            })
        }
    }
}

var postTitle = function(item) {
    var title = item.title // Already cutted to 100 chars

    // If there is no title try to get it from attachments
    if (! title && item.object.attachments) {
        for (var i = 0; i < item.object.attachments.length; i++) {
            var title = item.object.attachments[i].displayName
            if (title) break
        }
    }

    // Attachment type
    var attachment = ''
    if (item.object.attachments) {
        var type = (function() {
            if (item.object.attachments.some(function(a) { return a.objectType === 'article' })) return 'link'
            if (item.object.attachments.any(function(a) { return a.objectType === 'photo' })) return 'photo'
            if (item.object.attachments.any(function(a) { return a.objectType === 'video' })) return 'video'
        })()
        if (type) attachment = '[' + type + ']'
    }

    var finalTitle = []
    if (title) finalTitle.push(title)
    if (attachment) finalTitle.push(attachment)
    return finalTitle.join(' ')
}
<commit_msg>"Cannot call method 'each' of undefined"<commit_after>var fs = require('fs'),
    ejs = require('ejs'),
    request = require('request'),
    querystring = require('querystring')

exports.Client = function(apiKey) {
    var userPosts = function(userId, callback) {
        var url = 'https://www.googleapis.com/plus/v1/people/' + userId + '/activities/public?' + querystring.stringify({key: apiKey})
        request(url, function(error, response, body) {
            if (error) return callback(error)
            try {
                var json = JSON.parse(body)
                if (json.error) throw new Error(json.error.message)
                var posts = []
                if (json.items) {
                    json.items.each(function(item) {
                        posts.push({
                            url: item.url,
                            title: postTitle(item),
                            updated: new Date(item.updated)
                        })
                    })
                }
                callback(null, posts)
            } catch (error) {
                callback(error)
            }
        })
    }

    return {
        userFeed: function(userId, callback) {
            userPosts(userId, function(error, posts) {
                if (error) return callback(error)

                fs.readFile(__dirname + '/../views/feed.ejs', 'utf8', function(error, template) {
                    if (error) return callback(error)

                    var feed = ejs.render(template, {
                        locals: {
                            profileUrl: 'https://plus.google.com/' + userId,
                            posts: posts
                        }
                    })

                    callback(null, feed)
                })
            })
        }
    }
}

var postTitle = function(item) {
    var title = item.title // Already cutted to 100 chars

    // If there is no title try to get it from attachments
    if (! title && item.object.attachments) {
        for (var i = 0; i < item.object.attachments.length; i++) {
            var title = item.object.attachments[i].displayName
            if (title) break
        }
    }

    // Attachment type
    var attachment = ''
    if (item.object.attachments) {
        var type = (function() {
            if (item.object.attachments.some(function(a) { return a.objectType === 'article' })) return 'link'
            if (item.object.attachments.any(function(a) { return a.objectType === 'photo' })) return 'photo'
            if (item.object.attachments.any(function(a) { return a.objectType === 'video' })) return 'video'
        })()
        if (type) attachment = '[' + type + ']'
    }

    var finalTitle = []
    if (title) finalTitle.push(title)
    if (attachment) finalTitle.push(attachment)
    return finalTitle.join(' ')
}
<|endoftext|>


<commit_before>const utils = require('./utils');
const WebGLRunner = require('./backend/web-gl/runner');
const CPURunner = require('./backend/cpu/runner');
const WebGLValidatorKernel = require('./backend/web-gl/validator-kernel');

///
/// Class: GPU
///
/// Initialises the GPU.js library class which manages the WebGL context for the created functions.
///
module.exports = class GPU {
	constructor(settings) {
		settings = settings || {};
		this._canvas = settings.canvas || null;
		this._webGl = settings.webGl || null;
		let mode = settings.mode || 'webgl';
		if (!utils.isWebGlSupported) {
			console.warn('Warning: gpu not supported, falling back to cpu support');
			mode = 'cpu';
		}

		this.kernels = [];

		const runnerSettings = {
			canvas: this._canvas,
			webGl: this._webGl
		};

		if (mode) {
			switch (mode.toLowerCase()) {
				case 'cpu':
					this._runner = new CPURunner(runnerSettings);
					break;
				case 'gpu':
				case 'webgl':
					this._runner = new WebGLRunner(runnerSettings);
					break;
				case 'webgl-validator':
					this._runner = new WebGLRunner(runnerSettings);
					this._runner.Kernel = WebGLValidatorKernel;
					break;
				default:
					throw new Error(`"${mode}" mode is not defined`);
			}
		}
	}
	///
	/// Function: createKernel
	///
	/// This creates a callable function object to call the kernel function with the argument parameter set
	///
	/// The parameter object contains the following sub parameters
	///
	/// |---------------|---------------|---------------------------------------------------------------------------|
	/// | Name          | Default value | Description                                                               |
	/// |---------------|---------------|---------------------------------------------------------------------------|
	/// | dimensions    | [1024]        | Thread dimension array                                                    |
	/// | mode          | null          | CPU / GPU configuration mode, 'auto' / null. Has the following modes.     |
	/// |               |               |     + null / 'auto' : Attempts to build GPU mode, else fallbacks          |
	/// |               |               |     + 'gpu' : Attempts to build GPU mode, else fallbacks                  |
	/// |               |               |     + 'cpu' : Forces JS fallback mode only                                |
	/// |---------------|---------------|---------------------------------------------------------------------------|
	///
	/// Parameters:
	/// 	inputFunction   {JS Function} The calling to perform the conversion
	/// 	settings        {Object}      The parameter configuration object (see above)
	///
	/// Returns:
	/// 	{Function} callable function to run
	///
	createKernel(fn, settings) {
		//
		// basic parameters safety checks
		//
		if (typeof fn === 'undefined') {
			throw 'Missing fn parameter';
		}
		if (!utils.isFunction(fn)) {
			throw 'fn parameter not a function';
		}

		const kernel = this._runner.buildKernel(fn, settings || {});

		//if canvas didn't come from this, propagate from kernel
		if (!this._canvas) {
			this._canvas = kernel.canvas;
		}
		if (!this._runner.canvas) {
			this._runner.canvas = kernel.canvas;
		}

		this.kernels.push(kernel);

		return kernel;
	}

	///
	///
	/// Function: createKernels
	///
	/// Create a super kernel which executes sub kernels
	/// and saves their output to be used with the next sub kernel.
	/// This can be useful if we want to save the output on one kernel,
	///	and then use it as an input to another kernel. *Machine Learning*
	///
	/// Example:
	/// (start code)
	///	 		const megaKernel = gpu.createKernels({
	///				addResult: function add(a, b) {
	///	  				return a[this.thread.x] + b[this.thread.x];
	///				},
	///				multiplyResult: function multiply(a, b) {
	///					return a[this.thread.x] * b[this.thread.x];
	///				},
	///			  }, function(a, b, c) {
	///				return multiply(add(a, b), c);
	///			});
	///
	///			megaKernel(a, b, c);
	/// (end code)
	///
	/// *Note:* You can also define subKernels as an array of functions.
	/// > [add, multiply]
	///
	/// Parameters:
	///      subKernels - {Object|Array}  Sub kernels for this kernel
	///		 rootKernel - {Function}  	  Root kernel
	///
	/// Returns:
	/// 	{Function} callable kernel function
	///
	createKernels() {
		let fn;
		let settings;
		if (typeof arguments[arguments.length - 2] === 'function') {
			fn = arguments[arguments.length - 2];
			settings = arguments[arguments.length - 1];
		} else {
			fn = arguments[arguments.length - 1];
		}

		if (!utils.isWebGlDrawBuffersSupported) {
			this._runner = new CPURunner({
				canvas: this._canvas,
				webGl: this._webGl
			});
		}

		const kernel = this.createKernel(fn, settings);
		if (Array.isArray(arguments[0])) {
			const functions = arguments[0];
			for (let i = 0; i < functions.length; i++) {
				kernel.addSubKernel(functions[i]);
			}
		} else {
			const functions = arguments[0];
			for (let p in functions) {
				if (!functions.hasOwnProperty(p)) continue;
				kernel.addSubKernelProperty(p, functions[p]);
			}
		}

		return kernel;
	}

	///
	/// Function: combineKernels
	///
	/// Combine different kernels into one super Kernel,
	/// useful to perform multiple operations inside one
	/// kernel without the penalty of data transfer between
	/// cpu and gpu.
	///
	/// The number of kernel functions sent to this method can be variable.
	/// You can send in one, two, etc.
	///
	/// Example:
	/// >	combineKernels(add, multiply, function(a,b,c){
	///	>	 	return add(multiply(a,b), c)
	///	>	})
	///
	/// Parameters:
	///      subKernels - {Function}  Kernel function(s) to combine.
	///		 rootKernel - {Function}  Root kernel to combine kernels into
	///
	/// Returns:
	/// 	{Function} callable kernel function
	///
	combineKernels() {
		const lastKernel = arguments[arguments.length - 2];
		const combinedKernel = arguments[arguments.length - 1];
		if (this.mode === 'cpu') return combinedKernel;

		const canvas = arguments[0].canvas;
		let webGl = arguments[0].webGl;

		for (let i = 0; i < arguments.length - 1; i++) {
			arguments[i]
				.setCanvas(canvas)
				.setWebGl(webGl)
				.setOutputToTexture(true);
		}

		return function() {
			combinedKernel.apply(null, arguments);
			const texSize = lastKernel.texSize;
			const gl = lastKernel.webGl;
			const threadDim = lastKernel.threadDim;
			let result;
			if (lastKernel.floatOutput) {
				result = new Float32Array(texSize[0] * texSize[1] * 4);
				gl.readPixels(0, 0, texSize[0], texSize[1], gl.RGBA, gl.FLOAT, result);
			} else {
				const bytes = new Uint8Array(texSize[0] * texSize[1] * 4);
				gl.readPixels(0, 0, texSize[0], texSize[1], gl.RGBA, gl.UNSIGNED_BYTE, bytes);
				result = Float32Array.prototype.slice.call(new Float32Array(bytes.buffer));
			}

			result = result.subarray(0, threadDim[0] * threadDim[1] * threadDim[2]);

			if (lastKernel.dimensions.length === 1) {
				return result;
			} else if (lastKernel.dimensions.length === 2) {
				return utils.splitArray(result, lastKernel.dimensions[0]);
			} else if (lastKernel.dimensions.length === 3) {
				const cube = utils.splitArray(result, lastKernel.dimensions[0] * lastKernel.dimensions[1]);
				return cube.map(function(x) {
					return utils.splitArray(x, lastKernel.dimensions[0]);
				});
			}
		};
	}

	///
	/// Function: addFunction
	///
	/// Adds additional functions, that the kernel may call.
	///
	/// Parameters:
	/// 	fn              - {Function|String}  JS Function to do conversion
	/// 	paramTypes      - {[String,...]|{variableName: Type,...}} Parameter type array, assumes all parameters are 'float' if null
	/// 	returnType      - {String}       The return type, assumes 'float' if null
	///
	/// Returns:
	/// 	{GPU} returns itself
	///
	addFunction(fn, paramTypes, returnType) {
		this._runner.functionBuilder.addFunction(null, fn, paramTypes, returnType);
		return this;
	}

	///
	/// Function: get mode()
	///
	/// [GETTER] Return the current mode in which gpu.js is executing.
	///
	/// Returns:
	/// 	{String} The current mode, "cpu", "webgl", etc.
	///
	get mode() {
		return this._runner.mode;
	}

	///
	/// Function: get isWebGlSupported()
	///
	/// [GETTER] Return TRUE, if browser supports WebGl AND Canvas
	///
	/// Note: This function can also be called directly `GPU.isWebGlSupported()`
	///
	/// Returns:
	/// 	{Boolean} TRUE if browser supports webGl
	///
	get isWebGlSupported() {
		return utils.isWebGlSupported;
	}

	///
	/// Function: get canvas()
	///
	/// [GETTER] Return the canvas object bound to this gpu instance.
	///
	/// Returns:
	/// 	{Object} Canvas object if present
	///
	get canvas() {
		return this._canvas;
	}

	///
	/// Function: get webGl()
	///
	/// [GETTER] Return the webGl object bound to this gpu instance.
	///
	/// Returns:
	/// 	{Object} WebGl object if present
	///
	get webGl() {
		return this._webGl;
	}
};<commit_msg>pass settings to the runner instance<commit_after>const utils = require('./utils');
const WebGLRunner = require('./backend/web-gl/runner');
const CPURunner = require('./backend/cpu/runner');
const WebGLValidatorKernel = require('./backend/web-gl/validator-kernel');

///
/// Class: GPU
///
/// Initialises the GPU.js library class which manages the WebGL context for the created functions.
///
module.exports = class GPU {
	constructor(settings) {
		settings = settings || {};
		this._canvas = settings.canvas || null;
		this._webGl = settings.webGl || null;
		let mode = settings.mode || 'webgl';
		if (!utils.isWebGlSupported) {
			console.warn('Warning: gpu not supported, falling back to cpu support');
			mode = 'cpu';
		}

		this.kernels = [];

		const runnerSettings = {
			canvas: this._canvas,
			webGl: this._webGl
		};

		if (mode) {
			switch (mode.toLowerCase()) {
				case 'cpu':
					this._runner = new CPURunner(runnerSettings);
					break;
				case 'gpu':
				case 'webgl':
					this._runner = new WebGLRunner(runnerSettings);
					break;
				case 'webgl-validator':
					this._runner = new WebGLRunner(runnerSettings);
					this._runner.Kernel = WebGLValidatorKernel;
					break;
				default:
					throw new Error(`"${mode}" mode is not defined`);
			}
		}
	}
	///
	/// Function: createKernel
	///
	/// This creates a callable function object to call the kernel function with the argument parameter set
	///
	/// The parameter object contains the following sub parameters
	///
	/// |---------------|---------------|---------------------------------------------------------------------------|
	/// | Name          | Default value | Description                                                               |
	/// |---------------|---------------|---------------------------------------------------------------------------|
	/// | dimensions    | [1024]        | Thread dimension array                                                    |
	/// | mode          | null          | CPU / GPU configuration mode, 'auto' / null. Has the following modes.     |
	/// |               |               |     + null / 'auto' : Attempts to build GPU mode, else fallbacks          |
	/// |               |               |     + 'gpu' : Attempts to build GPU mode, else fallbacks                  |
	/// |               |               |     + 'cpu' : Forces JS fallback mode only                                |
	/// |---------------|---------------|---------------------------------------------------------------------------|
	///
	/// Parameters:
	/// 	inputFunction   {JS Function} The calling to perform the conversion
	/// 	settings        {Object}      The parameter configuration object (see above)
	///
	/// Returns:
	/// 	{Function} callable function to run
	///
	createKernel(fn, settings) {
		//
		// basic parameters safety checks
		//
		if (typeof fn === 'undefined') {
			throw 'Missing fn parameter';
		}
		if (!utils.isFunction(fn)) {
			throw 'fn parameter not a function';
		}

		const kernel = this._runner.buildKernel(fn, settings || {});

		//if canvas didn't come from this, propagate from kernel
		if (!this._canvas) {
			this._canvas = kernel.canvas;
		}
		if (!this._runner.canvas) {
			this._runner.canvas = kernel.canvas;
		}

		this.kernels.push(kernel);

		return kernel;
	}

	///
	///
	/// Function: createKernels
	///
	/// Create a super kernel which executes sub kernels
	/// and saves their output to be used with the next sub kernel.
	/// This can be useful if we want to save the output on one kernel,
	///	and then use it as an input to another kernel. *Machine Learning*
	///
	/// Example:
	/// (start code)
	///	 		const megaKernel = gpu.createKernels({
	///				addResult: function add(a, b) {
	///	  				return a[this.thread.x] + b[this.thread.x];
	///				},
	///				multiplyResult: function multiply(a, b) {
	///					return a[this.thread.x] * b[this.thread.x];
	///				},
	///			  }, function(a, b, c) {
	///				return multiply(add(a, b), c);
	///			});
	///
	///			megaKernel(a, b, c);
	/// (end code)
	///
	/// *Note:* You can also define subKernels as an array of functions.
	/// > [add, multiply]
	///
	/// Parameters:
	///      subKernels - {Object|Array}  Sub kernels for this kernel
	///		 rootKernel - {Function}  	  Root kernel
	///
	/// Returns:
	/// 	{Function} callable kernel function
	///
	createKernels() {
		let fn;
		let settings;
		if (typeof arguments[arguments.length - 2] === 'function') {
			fn = arguments[arguments.length - 2];
			settings = arguments[arguments.length - 1];
		} else {
			fn = arguments[arguments.length - 1];
		}

		if (!utils.isWebGlDrawBuffersSupported) {
			this._runner = new CPURunner(settings);
		}

		const kernel = this.createKernel(fn, settings);
		if (Array.isArray(arguments[0])) {
			const functions = arguments[0];
			for (let i = 0; i < functions.length; i++) {
				kernel.addSubKernel(functions[i]);
			}
		} else {
			const functions = arguments[0];
			for (let p in functions) {
				if (!functions.hasOwnProperty(p)) continue;
				kernel.addSubKernelProperty(p, functions[p]);
			}
		}

		return kernel;
	}

	///
	/// Function: combineKernels
	///
	/// Combine different kernels into one super Kernel,
	/// useful to perform multiple operations inside one
	/// kernel without the penalty of data transfer between
	/// cpu and gpu.
	///
	/// The number of kernel functions sent to this method can be variable.
	/// You can send in one, two, etc.
	///
	/// Example:
	/// >	combineKernels(add, multiply, function(a,b,c){
	///	>	 	return add(multiply(a,b), c)
	///	>	})
	///
	/// Parameters:
	///      subKernels - {Function}  Kernel function(s) to combine.
	///		 rootKernel - {Function}  Root kernel to combine kernels into
	///
	/// Returns:
	/// 	{Function} callable kernel function
	///
	combineKernels() {
		const lastKernel = arguments[arguments.length - 2];
		const combinedKernel = arguments[arguments.length - 1];
		if (this.mode === 'cpu') return combinedKernel;

		const canvas = arguments[0].canvas;
		let webGl = arguments[0].webGl;

		for (let i = 0; i < arguments.length - 1; i++) {
			arguments[i]
				.setCanvas(canvas)
				.setWebGl(webGl)
				.setOutputToTexture(true);
		}

		return function() {
			combinedKernel.apply(null, arguments);
			const texSize = lastKernel.texSize;
			const gl = lastKernel.webGl;
			const threadDim = lastKernel.threadDim;
			let result;
			if (lastKernel.floatOutput) {
				result = new Float32Array(texSize[0] * texSize[1] * 4);
				gl.readPixels(0, 0, texSize[0], texSize[1], gl.RGBA, gl.FLOAT, result);
			} else {
				const bytes = new Uint8Array(texSize[0] * texSize[1] * 4);
				gl.readPixels(0, 0, texSize[0], texSize[1], gl.RGBA, gl.UNSIGNED_BYTE, bytes);
				result = Float32Array.prototype.slice.call(new Float32Array(bytes.buffer));
			}

			result = result.subarray(0, threadDim[0] * threadDim[1] * threadDim[2]);

			if (lastKernel.dimensions.length === 1) {
				return result;
			} else if (lastKernel.dimensions.length === 2) {
				return utils.splitArray(result, lastKernel.dimensions[0]);
			} else if (lastKernel.dimensions.length === 3) {
				const cube = utils.splitArray(result, lastKernel.dimensions[0] * lastKernel.dimensions[1]);
				return cube.map(function(x) {
					return utils.splitArray(x, lastKernel.dimensions[0]);
				});
			}
		};
	}

	///
	/// Function: addFunction
	///
	/// Adds additional functions, that the kernel may call.
	///
	/// Parameters:
	/// 	fn              - {Function|String}  JS Function to do conversion
	/// 	paramTypes      - {[String,...]|{variableName: Type,...}} Parameter type array, assumes all parameters are 'float' if null
	/// 	returnType      - {String}       The return type, assumes 'float' if null
	///
	/// Returns:
	/// 	{GPU} returns itself
	///
	addFunction(fn, paramTypes, returnType) {
		this._runner.functionBuilder.addFunction(null, fn, paramTypes, returnType);
		return this;
	}

	///
	/// Function: get mode()
	///
	/// [GETTER] Return the current mode in which gpu.js is executing.
	///
	/// Returns:
	/// 	{String} The current mode, "cpu", "webgl", etc.
	///
	get mode() {
		return this._runner.mode;
	}

	///
	/// Function: get isWebGlSupported()
	///
	/// [GETTER] Return TRUE, if browser supports WebGl AND Canvas
	///
	/// Note: This function can also be called directly `GPU.isWebGlSupported()`
	///
	/// Returns:
	/// 	{Boolean} TRUE if browser supports webGl
	///
	get isWebGlSupported() {
		return utils.isWebGlSupported;
	}

	///
	/// Function: get canvas()
	///
	/// [GETTER] Return the canvas object bound to this gpu instance.
	///
	/// Returns:
	/// 	{Object} Canvas object if present
	///
	get canvas() {
		return this._canvas;
	}

	///
	/// Function: get webGl()
	///
	/// [GETTER] Return the webGl object bound to this gpu instance.
	///
	/// Returns:
	/// 	{Object} WebGl object if present
	///
	get webGl() {
		return this._webGl;
	}
};<|endoftext|>


<commit_before>var check = [/</g,/>/g,/&/g,/ /g,/"/g];
exports = function (str) {
	str = str.replace(check[0], "<");
	str = str.replace(check[1], ">");
	str = str.replace(check[2], "&");
	str = str.replace(check[3], " ");
	str = str.replace(check[4], """);
	return str;
};<commit_msg>add unEscape<commit_after>var check = [/</g,/>/g,/&/g,/"/g,/</g,/>/g,/&/g,/"/g];
exports.escape = function (str) {
	str = str.replace(check[0], "<");
	str = str.replace(check[1], ">");
	str = str.replace(check[2], "&");
	str = str.replace(check[3], """);
	return str;
};
exports.unEscape = function (str) {
	str = str.replace(check[4], "<");
	str = str.replace(check[5], ">");
	str = str.replace(check[6], "&");
	str = str.replace(check[7], '"');
	return str;
};<|endoftext|>