<commit_before>function array_filter (arr, func) {
  // http://kevin.vanzonneveld.net
  // +   original by: Brett Zamir (http://brett-zamir.me)
  // +   input by: max4ever
  // +   improved by: Brett Zamir (http://brett-zamir.me)
  // %        note 1: Takes a function as an argument, not a function's name
  // *     example 1: var odd = function (num) {return (num & 1);};
  // *     example 1: array_filter({"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}, odd);
  // *     returns 1: {"a": 1, "c": 3, "e": 5}
  // *     example 2: var even = function (num) {return (!(num & 1));}
  // *     example 2: array_filter([6, 7, 8, 9, 10, 11, 12], even);
  // *     returns 2: {0: 6, 2: 8, 4: 10, 6: 12}
  // *     example 3: var arr = array_filter({"a": 1, "b": false, "c": -1, "d": 0, "e": null, "f":'', "g":undefined});
  // *     returns 3: {"a":1, "c":-1};

  var retObj = {},
    k;

  func = func || function (v) {return v;};

  for (k in arr) {
    if (func(arr[k])) {
      retObj[k] = arr[k];
    }
  }

  return retObj;
}
<commit_msg>Update functions/array/array_filter.js<commit_after>function array_filter (arr, func) {
  // http://kevin.vanzonneveld.net
  // +   original by: Brett Zamir (http://brett-zamir.me)
  // +   input by: max4ever
  // +   improved by: Brett Zamir (http://brett-zamir.me)
  // %        note 1: Takes a function as an argument, not a function's name
  // *     example 1: var odd = function (num) {return (num & 1);};
  // *     example 1: array_filter({"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}, odd);
  // *     returns 1: {"a": 1, "c": 3, "e": 5}
  // *     example 2: var even = function (num) {return (!(num & 1));}
  // *     example 2: array_filter([6, 7, 8, 9, 10, 11, 12], even);
  // *     returns 2: {0: 6, 2: 8, 4: 10, 6: 12}
  // *     example 3: var arr = array_filter({"a": 1, "b": false, "c": -1, "d": 0, "e": null, "f":'', "g":undefined});
  // *     returns 3: {"a":1, "c":-1};

  var retObj = {},
    k;

  func = func || function (v) {return v;};

  // Fix: Issue #73
	if( Object.prototype.toString.call( arr ) === '[object Array]' ) {
		retObj = []
	}

  for (k in arr) {
    if (func(arr[k])) {
      retObj[k] = arr[k];
    }
  }

  return retObj;
}
<|endoftext|>


<commit_before>define(["dcl/dcl"], function(dcl){
	// module:
	//		dui/Stateful

	var apn = {};
	function propNames(name){
		// summary:
		//		Helper function to map "foo" --> "_setFooAttr" with caching to avoid recomputing strings.
		//		Note: in dojo/Stateful they are _fooGetter and _fooSetter.

		if(apn[name]){ return apn[name]; }
		var uc = name.replace(/^[a-z]|-[a-zA-Z]/g, function(c){ return c.charAt(c.length-1).toUpperCase(); });
		return (apn[name] = {
			p: "_" + name + "Attr",		// shadow property, since real property hidden by setter/getter
			s: "_set" + uc + "Attr",	// converts dashes to camel case, ex: accept-charset --> _setAcceptCharsetAttr
			g: "_get" + uc + "Attr"
		});
	}

	return dcl(null, {
		// summary:
		//		Base class for objects that provide named properties with optional getter/setter
		//		control and the ability to watch for property changes.
		//
		//		The class also provides the functionality to auto-magically manage getters
		//		and setters for class attributes/properties.  Note though that expando properties
		//		(i.e. properties added to an instance but not in the prototype) are not supported.
		//
		//		Getters and Setters should follow the format of _setXxxAttr or _getXxxAttr where
		//		the xxx is a name of the attribute to handle.  So an attribute of "foo"
		//		would have a custom getter of _getFooAttr and a custom setter of _setFooAttr.
		//		Setters must save and announce the new property value by calling this._set("foo", val),
		//		and getters should access the property value as this._fooAttr.
		//
		// example:
		//	|	var MyClass = dcl(Stateful, {});
		//	|	var obj = new MyClass();
		//	|	obj.watch("foo", function(){
		//	|		console.log("foo changed to " + this.foo);
		//	|	});
		//	|	obj.foo = bar;

		_introspect: function(){
			// summary:
			//		Sets up ES5 getters/setters for each class property, except for functions and privates.

			var ctor = this.constructor,
				proto = ctor.prototype;

			for(var name in proto){
				// TODO: If this class extends HTMLElement, then generally shouldn't setup custom getters/setters
				// for DOMNode attributes like dir, since it blocks the ability to ever set that param on the dom node.
				if(typeof proto[name] == "function" || /^_/.test(name)){ continue; }
				var names = propNames(name);

				// Setup ES5 getter and setter for this property, if not already setup by a superclass.
				// For a property named foo, saves raw value in _fooAttr.
				// ES5 setter intentionally does late checking for this[names.s] in case a subclass sets up a
				// _setFooAttr method.
				if(!(names.p in proto)){
					(function(prop, shadowProp, getter, setter){
						// TODO: this set enumerable:false on prototype.shadowProp, but not on instance.shadowProp
						// (instance.shadowProp is set when the instance changes the value)... so, useless?
						Object.defineProperty(proto, shadowProp, {value: proto[prop], enumerable: false, writable: true});
						Object.defineProperty(proto, prop, {
							set: function(x){
								setter in this ? this[setter](x) : this._set(prop, x);
							},
							get: function(){
								return getter in proto ? this[getter]() : this[shadowProp];
							}
						});
					})(name, names.p, names.g, names.s);	// save value of name etc. in this loop iteration
				}
			}
		},

		constructor: dcl.advise({
			before: function(){
				// First time this class is instantiated, introspect it.
				if(!this.constructor._introspected){	// note: checking if this class was introspected, not a superclass
					this._introspect();
					this.constructor._introspected = true;
				}
			},

			after: function(args){
				// Automatic setting of params during construction.
				// In after() advice so that it runs after all the subclass constructor methods.
				if (args.length){ this.set(args[0]); }
			}
		}),

		set: function(/*Object*/ hash){
			// summary:
			//		Set a hash of properties on a Stateful instance
			//	|	myObj.set({
			//	|		foo: "Howdy",
			//	|		bar: 3
			//	|	})

			for(var x in hash){
				if(hash.hasOwnProperty(x) && x != "_watchCallbacks"){
					this[x] = hash[x];
				}
			}
		},

		_set: function(name, value){		// note: called _changeAttrValue() in dojo/Stateful
			// summary:
			//		Internal helper for directly changing an attribute value.
			// name: String
			//		The property to set.
			// value: Mixed
			//		The value to set in the property.
			// description:
			//		Directly change the value of an attribute on an object, bypassing any
			//		accessor setter.  Also notifies callbacks registered via watch().
			//		It is designed to be used by descendant class when there are two values
			//		of attributes that are linked, but calling .set() is not appropriate.

			var shadowPropName = propNames(name).p;
			var oldValue = this[shadowPropName];
			this[shadowPropName] = value;
			if(this._watchCallbacks){
				this._watchCallbacks(name, oldValue, value);
			}
		},

		watch: function(/*String?*/ name, /*Function*/ callback){
			// summary:
			//		Watches a property for changes
			// name:
			//		Indicates the property to watch. This is optional (the callback may be the
			//		only parameter), and if omitted, all the properties will be watched
			// returns:
			//		An object handle for the watch. The unwatch method of this object
			//		can be used to discontinue watching this property:
			//		|	var watchHandle = obj.watch("foo", callback);
			//		|	watchHandle.unwatch(); // callback won't be called now
			// callback:
			//		The function to execute when the property changes. This will be called after
			//		the property has been changed. The callback will be called with the |this|
			//		set to the instance, the first argument as the name of the property, the
			//		second argument as the old value and the third argument as the new value.

			var callbacks = this._watchCallbacks;
			if(!callbacks){
				var self = this;
				callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
					var notify = function(propertyCallbacks){
						if(propertyCallbacks){
							propertyCallbacks = propertyCallbacks.slice();
							for(var i = 0, l = propertyCallbacks.length; i < l; i++){
								propertyCallbacks[i].call(self, name, oldValue, value);
							}
						}
					};
					notify(callbacks['_' + name]);
					if(!ignoreCatchall){
						notify(callbacks["*"]); // the catch-all
					}
				}; // we use a function instead of an object so it will be ignored by JSON conversion
			}
			if(!callback && typeof name === "function"){
				callback = name;
				name = "*";
			}else{
				// prepend with dash to prevent name conflicts with function (like "name" property)
				name = '_' + name;
			}
			var propertyCallbacks = callbacks[name];
			if(typeof propertyCallbacks !== "object"){
				propertyCallbacks = callbacks[name] = [];
			}
			propertyCallbacks.push(callback);

			return {
				remove: function(){
					var index = propertyCallbacks.indexOf(callback);
					if(index > -1){
						propertyCallbacks.splice(index, 1);
					}
				}
			}; //Object
		}

	});
});
<commit_msg>in some cases we need to get the value bypassing the customer getter<commit_after>define(["dcl/dcl"], function(dcl){
	// module:
	//		dui/Stateful

	var apn = {};
	function propNames(name){
		// summary:
		//		Helper function to map "foo" --> "_setFooAttr" with caching to avoid recomputing strings.
		//		Note: in dojo/Stateful they are _fooGetter and _fooSetter.

		if(apn[name]){ return apn[name]; }
		var uc = name.replace(/^[a-z]|-[a-zA-Z]/g, function(c){ return c.charAt(c.length-1).toUpperCase(); });
		return (apn[name] = {
			p: "_" + name + "Attr",		// shadow property, since real property hidden by setter/getter
			s: "_set" + uc + "Attr",	// converts dashes to camel case, ex: accept-charset --> _setAcceptCharsetAttr
			g: "_get" + uc + "Attr"
		});
	}

	return dcl(null, {
		// summary:
		//		Base class for objects that provide named properties with optional getter/setter
		//		control and the ability to watch for property changes.
		//
		//		The class also provides the functionality to auto-magically manage getters
		//		and setters for class attributes/properties.  Note though that expando properties
		//		(i.e. properties added to an instance but not in the prototype) are not supported.
		//
		//		Getters and Setters should follow the format of _setXxxAttr or _getXxxAttr where
		//		the xxx is a name of the attribute to handle.  So an attribute of "foo"
		//		would have a custom getter of _getFooAttr and a custom setter of _setFooAttr.
		//		Setters must save and announce the new property value by calling this._set("foo", val),
		//		and getters should access the property value as this._fooAttr.
		//
		// example:
		//	|	var MyClass = dcl(Stateful, {});
		//	|	var obj = new MyClass();
		//	|	obj.watch("foo", function(){
		//	|		console.log("foo changed to " + this.foo);
		//	|	});
		//	|	obj.foo = bar;

		_introspect: function(){
			// summary:
			//		Sets up ES5 getters/setters for each class property, except for functions and privates.

			var ctor = this.constructor,
				proto = ctor.prototype;

			for(var name in proto){
				// TODO: If this class extends HTMLElement, then generally shouldn't setup custom getters/setters
				// for DOMNode attributes like dir, since it blocks the ability to ever set that param on the dom node.
				if(typeof proto[name] == "function" || /^_/.test(name)){ continue; }
				var names = propNames(name);

				// Setup ES5 getter and setter for this property, if not already setup by a superclass.
				// For a property named foo, saves raw value in _fooAttr.
				// ES5 setter intentionally does late checking for this[names.s] in case a subclass sets up a
				// _setFooAttr method.
				if(!(names.p in proto)){
					(function(prop, shadowProp, getter, setter){
						// TODO: this set enumerable:false on prototype.shadowProp, but not on instance.shadowProp
						// (instance.shadowProp is set when the instance changes the value)... so, useless?
						Object.defineProperty(proto, shadowProp, {value: proto[prop], enumerable: false, writable: true});
						Object.defineProperty(proto, prop, {
							set: function(x){
								setter in this ? this[setter](x) : this._set(prop, x);
							},
							get: function(){
								return getter in proto ? this[getter]() : this[shadowProp];
							}
						});
					})(name, names.p, names.g, names.s);	// save value of name etc. in this loop iteration
				}
			}
		},

		constructor: dcl.advise({
			before: function(){
				// First time this class is instantiated, introspect it.
				if(!this.constructor._introspected){	// note: checking if this class was introspected, not a superclass
					this._introspect();
					this.constructor._introspected = true;
				}
			},

			after: function(args){
				// Automatic setting of params during construction.
				// In after() advice so that it runs after all the subclass constructor methods.
				if (args.length){ this.set(args[0]); }
			}
		}),

		set: function(/*Object*/ hash){
			// summary:
			//		Set a hash of properties on a Stateful instance
			//	|	myObj.set({
			//	|		foo: "Howdy",
			//	|		bar: 3
			//	|	})

			for(var x in hash){
				if(hash.hasOwnProperty(x) && x != "_watchCallbacks"){
					this[x] = hash[x];
				}
			}
		},

		_set: function(name, value){		// note: called _changeAttrValue() in dojo/Stateful
			// summary:
			//		Internal helper for directly changing an attribute value.
			// name: String
			//		The property to set.
			// value: Mixed
			//		The value to set in the property.
			// description:
			//		Directly change the value of an attribute on an object, bypassing any
			//		accessor setter.  Also notifies callbacks registered via watch().
			//		It is designed to be used by descendant class when there are two values
			//		of attributes that are linked, but calling .set() is not appropriate.

			var shadowPropName = propNames(name).p;
			var oldValue = this[shadowPropName];
			this[shadowPropName] = value;
			if(this._watchCallbacks){
				this._watchCallbacks(name, oldValue, value);
			}
		},

		_get: function(name){
			// summary:
			//		Internal helper for directly accessing an attribute value.
			// name: String
			//		The property to get.
			// description:
			//		Directly get the value of an attribute on an object, bypassing any
			//		accessor getter.
			//		It is designed to be used by descendant class if they want in their custom getter to access the value
			//		before returning it.

			return this[propNames(name).p];
		},

		watch: function(/*String?*/ name, /*Function*/ callback){
			// summary:
			//		Watches a property for changes
			// name:
			//		Indicates the property to watch. This is optional (the callback may be the
			//		only parameter), and if omitted, all the properties will be watched
			// returns:
			//		An object handle for the watch. The unwatch method of this object
			//		can be used to discontinue watching this property:
			//		|	var watchHandle = obj.watch("foo", callback);
			//		|	watchHandle.unwatch(); // callback won't be called now
			// callback:
			//		The function to execute when the property changes. This will be called after
			//		the property has been changed. The callback will be called with the |this|
			//		set to the instance, the first argument as the name of the property, the
			//		second argument as the old value and the third argument as the new value.

			var callbacks = this._watchCallbacks;
			if(!callbacks){
				var self = this;
				callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
					var notify = function(propertyCallbacks){
						if(propertyCallbacks){
							propertyCallbacks = propertyCallbacks.slice();
							for(var i = 0, l = propertyCallbacks.length; i < l; i++){
								propertyCallbacks[i].call(self, name, oldValue, value);
							}
						}
					};
					notify(callbacks['_' + name]);
					if(!ignoreCatchall){
						notify(callbacks["*"]); // the catch-all
					}
				}; // we use a function instead of an object so it will be ignored by JSON conversion
			}
			if(!callback && typeof name === "function"){
				callback = name;
				name = "*";
			}else{
				// prepend with dash to prevent name conflicts with function (like "name" property)
				name = '_' + name;
			}
			var propertyCallbacks = callbacks[name];
			if(typeof propertyCallbacks !== "object"){
				propertyCallbacks = callbacks[name] = [];
			}
			propertyCallbacks.push(callback);

			return {
				remove: function(){
					var index = propertyCallbacks.indexOf(callback);
					if(index > -1){
						propertyCallbacks.splice(index, 1);
					}
				}
			}; //Object
		}

	});
});
<|endoftext|>


<commit_before>module.exports = {
  rules: {
    // enforces no braces where they can be omitted
    'arrow-body-style': [2, 'as-needed'],
    // require parens in arrow function arguments
    'arrow-parens': [2, 'as-needed'],
    // suggest using arrow functions as callbacks
    'prefer-arrow-callback': 2,
    // allow file with no default export
    'import/prefer-default-export': 0,
    // ignore references to root directory
    'import/no-extraneous-dependencies': 0,
  }
}
<commit_msg>Disallow console statements<commit_after>module.exports = {
  rules: {
    // enforces no braces where they can be omitted
    'arrow-body-style': [2, 'as-needed'],
    // require parens in arrow function arguments
    'arrow-parens': [2, 'as-needed'],
    // suggest using arrow functions as callbacks
    'prefer-arrow-callback': 2,
    // allow file with no default export
    'import/prefer-default-export': 0,
    // ignore references to root directory
    'import/no-extraneous-dependencies': 0,
    // no console!
    'no-console': 'error'
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import Immutable from 'immutable'
import {oxford, pluralize} from 'humanize-plus'

import AutosizeInput from 'react-input-autosize'

import studentActions from '../flux/studentActions'

let goodGraduationMessage = "It looks like you'll make it! Just follow the plan, and go over my output with your advisor a few times."
let badGraduationMessage = "You haven't planned everything out yet. Ask your advisor if you need help fitting everything in."

class StudentSummary extends React.Component {
	shouldComponentUpdate(nextProps) {
		return nextProps.student !== this.props.student || nextProps.graduatability !== this.props.graduatability
	}

	render() {
		// console.log('StudentSummary#render')
		let canGraduate = this.props.graduatability
		let student = this.props.student
		let studies = student.studies

		let name = student.name
		let studentId = this.props.student.id
		let NameEl = <AutosizeInput className='autosize-input'
			value={name}
			onChange={(ev) => studentActions.updateName(studentId, ev.target.value.trim())} />

		let has = studies
			.groupBy(s => s.type)
			.map(s => s.size)
			.toObject()

		let degrees = studies.filter(s => s.type === 'degree')
		let majors = studies.filter(s => s.type === 'major')
		let concentrations = studies.filter(s => s.type === 'concentration')
		let emphases = studies.filter(s => s.type === 'emphasis')

		let degreeTitles = oxford(degrees.map(s => s.title).toArray())
		let majorTitles = oxford(majors.map(s => s.title).toArray())
		let concentrationTitles = oxford(concentrations.map(s => s.title).toArray())
		let emphasisTitles = oxford(emphases.map(s => s.title).toArray())

		let degreeWords = pluralize(degrees.size, 'degree')
		let majorWords = pluralize(majors.size, 'major')
		let concentrationWords = pluralize(concentrations.size, 'concentration')
		let emphasisWords = pluralize(emphases.size, 'emphasis', 'emphases')

		let degreeEmphasizer = has.degree === 1 ? 'a ' : ''
		let majorEmphasizer = has.major === 1 ? 'a ' : ''
		let concentrationEmphasizer = has.concentration === 1 ? 'a ' : ''
		let emphasisEmphasizer = has.emphasis === 1 ? 'an ' : ''

		let degreeEl = {degreeTitles}
		let majorEl = {majorTitles}
		let concentrationEl = {concentrationTitles}
		let emphasisEl = {emphasisTitles}

		console.log(student.graduation, student.matriculation)

		const graduationEl = <AutosizeInput
			className='autosize-input'
			value={String(student.graduation)}
			onChange={(ev) => studentActions.changeGraduation(studentId, parseInt(ev.target.value))} />

		const sinceMatriculationEl = <AutosizeInput
			className='autosize-input'
			value={String(student.graduation - student.matriculation)}
			onChange={(ev) => studentActions.changeMatriculation(studentId, student.graduation - parseInt(ev.target.value))} />

		/*eslint-disable comma-spacing */
		return

{name.length ? name[0] : ''}

Hi, {NameEl}

					You are planning on graduating in {graduationEl}, {sinceMatriculationEl} years
					after matriculating, with {degreeEmphasizer} {degreeEl} {degreeWords}
					{(has.major > 0) ? [', with ', majorEmphasizer, majorWords, ' in ', majorEl] : null}
					{(has.concentration > 0) ? [', and ' + concentrationEmphasizer, concentrationWords, ' in ', concentrationEl] : null}
					{(has.emphasis > 0) ? [', not to mention ', emphasisEmphasizer, emphasisWords, ' in ', emphasisEl] : null}.

					{canGraduate ? goodGraduationMessage : badGraduationMessage}

		/*eslint-enable comma-spacing */
	}
}

StudentSummary.propTypes = {
	student: React.PropTypes.instanceOf(Immutable.Record).isRequired,
	graduatability: React.PropTypes.bool.isRequired,
}

export default StudentSummary
<commit_msg>Finally figure out how to remove the comma-spacing message<commit_after>import React from 'react'
import Immutable from 'immutable'
import {oxford, pluralize} from 'humanize-plus'

import AutosizeInput from 'react-input-autosize'

import studentActions from '../flux/studentActions'

let goodGraduationMessage = "It looks like you'll make it! Just follow the plan, and go over my output with your advisor a few times."
let badGraduationMessage = "You haven't planned everything out yet. Ask your advisor if you need help fitting everything in."

class StudentSummary extends React.Component {
	shouldComponentUpdate(nextProps) {
		return nextProps.student !== this.props.student || nextProps.graduatability !== this.props.graduatability
	}

	render() {
		// console.log('StudentSummary#render')
		let canGraduate = this.props.graduatability
		let student = this.props.student
		let studies = student.studies

		let name = student.name
		let studentId = this.props.student.id
		let NameEl = <AutosizeInput className='autosize-input'
			value={name}
			onChange={(ev) => studentActions.updateName(studentId, ev.target.value.trim())} />

		let has = studies
			.groupBy(s => s.type)
			.map(s => s.size)
			.toObject()

		let degrees = studies.filter(s => s.type === 'degree')
		let majors = studies.filter(s => s.type === 'major')
		let concentrations = studies.filter(s => s.type === 'concentration')
		let emphases = studies.filter(s => s.type === 'emphasis')

		let degreeTitles = oxford(degrees.map(s => s.title).toArray())
		let majorTitles = oxford(majors.map(s => s.title).toArray())
		let concentrationTitles = oxford(concentrations.map(s => s.title).toArray())
		let emphasisTitles = oxford(emphases.map(s => s.title).toArray())

		let degreeWords = pluralize(degrees.size, 'degree')
		let majorWords = pluralize(majors.size, 'major')
		let concentrationWords = pluralize(concentrations.size, 'concentration')
		let emphasisWords = pluralize(emphases.size, 'emphasis', 'emphases')

		let degreeEmphasizer = has.degree === 1 ? 'a ' : ''
		let majorEmphasizer = has.major === 1 ? 'a ' : ''
		let concentrationEmphasizer = has.concentration === 1 ? 'a ' : ''
		let emphasisEmphasizer = has.emphasis === 1 ? 'an ' : ''

		let degreeEl = {degreeTitles}
		let majorEl = {majorTitles}
		let concentrationEl = {concentrationTitles}
		let emphasisEl = {emphasisTitles}

		console.log(student.graduation, student.matriculation)

		const graduationEl = <AutosizeInput
			className='autosize-input'
			value={String(student.graduation)}
			onChange={(ev) => studentActions.changeGraduation(studentId, parseInt(ev.target.value))} />

		const sinceMatriculationEl = <AutosizeInput
			className='autosize-input'
			value={String(student.graduation - student.matriculation)}
			onChange={(ev) => studentActions.changeMatriculation(studentId, student.graduation - parseInt(ev.target.value))} />

		return

{name.length ? name[0] : ''}

Hi, {NameEl}

					{"You are planning on graduating in"} {graduationEl}{","} {sinceMatriculationEl}{" "}
					{"years after matriculating, with"} {degreeEmphasizer} {degreeEl} {degreeWords}
					{(has.major > 0) ? [', with ', majorEmphasizer, majorWords, ' in ', majorEl] : null}
					{(has.concentration > 0) ? [', and ' + concentrationEmphasizer, concentrationWords, ' in ', concentrationEl] : null}
					{(has.emphasis > 0) ? [', not to mention ', emphasisEmphasizer, emphasisWords, ' in ', emphasisEl] : null}.

					{canGraduate ? goodGraduationMessage : badGraduationMessage}

	}
}

StudentSummary.propTypes = {
	student: React.PropTypes.instanceOf(Immutable.Record).isRequired,
	graduatability: React.PropTypes.bool.isRequired,
}

export default StudentSummary
<|endoftext|>


<commit_before>'use strict'

const should          = require('should'),
      events          = require('../lib/server-code/events'),
      invoke          = require('./helpers/invoke-task'),
      ServerCode      = require('../lib/server-code/api'),
      executor        = require('../lib/server-code/runners/tasks/executor'),
      executionResult = require('../lib/server-code/runners/tasks/util/result-wrapper').executionResult,
      argsUtil        = require('../lib/server-code/runners/tasks/util/args'),
      Backendless     = require('backendless'),
      PERSISTENCE     = events.providers.PERSISTENCE,
      BEFORE_CREATE   = PERSISTENCE.events.beforeCreate,
      AFTER_CREATE    = PERSISTENCE.events.afterCreate,
      CUSTOM_EVENT    = events.providers.CUSTOM.events.execute

require('mocha')

function modelStub(handlerFn, classMappings) {
  return {
    getHandler   : () => ({ invoke: handlerFn }),
    classMappings: classMappings
  }
}

function createTask(event, args, async) {
  return {
    ___jsonclass : executor.RMI,
    eventId      : event.id,
    async        : !!async,
    initAppData  : {},
    applicationId: '',
    relativePath : '',
    arguments    : argsUtil.encode(args || [])
  }
}

describe('[invoke-handler] task executor', function() {
  it('should fill [request] params', function() {
    const context = { userId: 'userId', userToken: 'userToken', userRoles: ['RestUser'] }
    const item = { name: 'John' }

    const task = createTask(BEFORE_CREATE, [context, item])

    function handler(req) {
      should.exist(req.item)
      should.exist(req.context)

      req.item.should.be.eql(item)
      req.context.should.be.eql(context)
    }

    return invoke(task, modelStub(handler))
  })

  it('should respect task execution timeout', function() {
    function handler() {
      return new Promise(() => undefined)
    }

    return invoke(Object.assign(createTask(BEFORE_CREATE), { timeout: 1000 }), modelStub(handler)).then(res => {
      should.exist(res.exception)
      res.exception.exceptionMessage.should.equal('Task execution is aborted due to timeout')
    })
  })

  it('should initialise Backendless with user-token from the request context', function() {
    const userToken = 'wddeupxnpjncbykrlpegexyiunuixxqfckrr'
    const task = createTask(BEFORE_CREATE, [{ userToken: userToken }])
    let handlerInvoked = false

    function handler() {
      handlerInvoked = true

      should.equal(Backendless.LocalCache.get('user-token'), userToken)
    }

    return invoke(task, modelStub(handler)).then(res => {
      handlerInvoked.should.be.true()
      should.not.exists(res.exception)
    })
  })

  describe('should perform class mapping', function() {
    it('for persistence items', function() {
      class Foo {
      }

      class Bar {
      }

      class Baz {
      }

      let handlerInvoked

      function handler(req, res) {
        handlerInvoked = true

        req.item.should.be.instanceof(Foo)
        should.equal(req.item.a, 'a')

        req.item.bar.should.be.instanceof(Bar)
        should.equal(req.item.bar.b, 'b')

        res.result[0].should.be.instanceof(Baz)
        res.result[1].should.be.instanceof(Baz)
      }

      const item = { a: 'a', bar: { ___class: 'Bar', b: 'b' }, ___class: 'Foo' }
      const result = executionResult(null, [{ ___class: 'Baz' }, { ___class: 'Baz' }])

      return invoke(createTask(AFTER_CREATE, [{}, item, result]), modelStub(handler, {
        Foo,
        Bar,
        Baz
      }))
        .then((res) => {
          should.equal(handlerInvoked, true)

          should.not.exists(res.exception)

          should.equal(res.arguments[1].___class, 'Foo')
          should.equal(res.arguments[1].bar.___class, 'Bar')
          should.equal(res.arguments[2].result[0].___class, 'Baz')
          should.equal(res.arguments[2].result[1].___class, 'Baz')
        })
    })
  })

  describe('should handle', function() {
    it('unsupported event error', function() {
      return invoke(createTask({ id: -1 }), { handlers: [] }).then(res => {
        should.exist(res.exception)
        res.exception.exceptionMessage.should.startWith('Integrity violation')
      })
    })

    it('non string error', function() {
      function handler() {
        throw ['Error']
      }

      return invoke(createTask(BEFORE_CREATE), modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.exceptionMessage.should.equal('["Error"]')
      })
    })

    it('errors raised in the event handler', function() {
      function handler() {
        throw new Error('Error')
      }

      return invoke(createTask(BEFORE_CREATE), modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.exceptionMessage.should.equal('Error')
      })
    })

    it('custom errors', function() {
      function handler() {
        throw new ServerCode.Error(10, 'My Custom Error')
      }

      return invoke(createTask(BEFORE_CREATE), modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.code.should.equal(10)
        res.exception.exceptionMessage.should.equal('My Custom Error')
      })
    })

    it('and escape string error code', function() {
      function handler() {
        const err = new Error('StreamError')
        err.code = 'ENOTFOUND'

        throw err
      }

      return invoke(createTask(BEFORE_CREATE), modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.code.should.equal(0)
        res.exception.exceptionMessage.should.equal('StreamError')
      })
    })

    it('async errors raised in the event handler behind the promise', function() {
      function handler() {
        process.nextTick(() => {
          throw new Error('Async Error')
        }, 0)

        //never resolved promise
        return new Promise(() => {
        })
      }

      return invoke(createTask(BEFORE_CREATE), modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.exceptionMessage.should.equal('Async Error')
      })
    })

    it('handler execution timeout', function() {
      const task = createTask(BEFORE_CREATE)
      task.timeout = 1

      function handler() {
        return new Promise((resolve) => {
          setTimeout(() => resolve('buba'), 20)
        })
      }

      return invoke(task, modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.exceptionMessage.should.equal('Task execution is aborted due to timeout')
      })
    })
  })

  describe('in [before] event phase', function() {
    it('should allow input parameters modifying', function() {
      const task = createTask(BEFORE_CREATE, [{}, { name: 'John' }])

      function handler(req) {
        req.item = { name: 'Dou' }
      }

      return invoke(task, modelStub(handler)).then(res => {
        res.arguments[1].should.be.eql({ name: 'Dou' })
      })
    })

    it('should allow short circuit', function() {
      const task = createTask(BEFORE_CREATE, [{}, {}, { name: 'John', id: 1 }])

      function handler() {
        return { name: 'Dou', id: 2 }
      }

      return invoke(task, modelStub(handler)).then(res => {
        should.not.exists(res.exception)

        res.arguments[0].prematureResult.should.be.eql({ name: 'Dou', id: 2 })
      })
    })
  })

  describe('in [after] event phase', function() {
    it('should provide succeeded server result in {response} handler argument', function() {
      const result = { name: 'John', id: 1 }
      const wrappedResult = executionResult(null, result)
      const task = createTask(AFTER_CREATE, [{}, {}, wrappedResult])

      function handler(req, res) {
        should.not.exist(res.error)
        should.exist(res.result)
        res.result.should.be.eql(result)
      }

      return invoke(task, modelStub(handler)).then(res => {
        should.not.exists(res.exception)

        res.arguments[2].should.be.eql(wrappedResult)
      })
    })

    it('should provide erred server result in {response} handler argument', function() {
      const error = 'error'
      const erredResult = executionResult(error)
      const task = createTask(AFTER_CREATE, [{}, {}, erredResult])

      function handler(req, res) {
        should.not.exist(res.result)
        should.exist(res.error)
        res.error.exceptionMessage.should.be.eql(error)

        throw new Error(error)
      }

      return invoke(task, modelStub(handler)).then(res => {
        res.arguments.should.be.empty()
        res.exception.exceptionMessage.should.be.eql(error)
      })
    })

    describe('should allow server result modifying', function() {
      it('by returning a value from handler', function() {
        const task = createTask(AFTER_CREATE, [{}, {}, executionResult(null, {
          name: 'John',
          id  : 1
        })])

        function handler() {
          return { name: 'Dou', id: 2 }
        }

        return invoke(task, modelStub(handler)).then(res => {
          res.arguments[2].result.should.be.eql({ name: 'Dou', id: 2 })
        })
      })

      it('by changing {res.result}', function() {
        const task = createTask(AFTER_CREATE, [{}, {}, executionResult(null, { name: 'John', id: 1 })])

        function handler(req, res) {
          res.result.name = 'John Dou'
        }

        return invoke(task, modelStub(handler)).then(res => {
          res.arguments[2].result.should.be.eql({ name: 'John Dou', id: 1 })
        })
      })

      it('by changing {res.error}', function() {
        const task = createTask(AFTER_CREATE, [{}, {}, executionResult('Error')])

        function handler(req, res) {
          res.error.code = 1
        }

        return invoke(task, modelStub(handler)).then(res => {
          should.exists(res.arguments[2].exception)

          res.arguments[2].exception.code.should.equal(1)
          res.arguments[2].exception.exceptionMessage.should.equal('Error')
        })
      })

      it('by replacing {res.result} and {res.error}', function() {
        const task = createTask(AFTER_CREATE, [{}, {}, executionResult(null, null)])

        function handler(req, res) {
          res.result = { name: 'Dou', id: 2 }
          res.error = {
            code            : 4,
            exceptionMessage: 'Error',
            exceptionClass  : 'java.lang.RuntimeException'
          }
        }

        return invoke(task, modelStub(handler)).then(res => {
          should.exists(res.arguments[2].result)
          should.exists(res.arguments[2].exception)

          res.arguments[2].result.should.be.eql({ name: 'Dou', id: 2 })
          res.arguments[2].exception.code.should.equal(4)
          res.arguments[2].exception.exceptionMessage.should.equal('Error')
        })
      })
    })
  })

  describe('for async events', function() {
    const task = createTask(AFTER_CREATE, [], true)
    task.timeout = 3

    it('should wait for handler`s promise', function() {
      let handlerFinished = false

      function handler() {
        return new Promise(resolve => {
          setTimeout(() => {
            handlerFinished = true
            resolve()
          }, 2)
        })
      }

      return invoke(task, modelStub(handler))
        .then(() => {
          handlerFinished.should.be.true()
        })
    })

    it('should not return any result', function() {
      function handler() {
        return {}
      }

      return invoke(task, modelStub(handler)).should.be.fulfilledWith(undefined)
    })
  })

  describe('for custom events', function() {
    it('should wrap numeric value to object', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => 1)).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql({ result: 1 })
      })
    })

    it('should wrap string value to object', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => 'abc')).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql({ result: 'abc' })
      })
    })

    it('should wrap boolean value to object', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => true)).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql({ result: true })
      })
    })

    it('should wrap date value to object', function() {
      const date = new Date()

      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => date)).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql({ result: date })
      })
    })

    it('should wrap null', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => null)).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql({ result: null })
      })
    })

    it('should not wrap complex object', function() {
      const task = createTask(CUSTOM_EVENT, [])
      const result = { a: 'b' }

      function handler() {
        return result
      }

      return invoke(task, modelStub(handler)).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql(result)
      })
    })

    it('should nullify undefined', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => undefined)).then(res => {
        res.arguments[2].should.be.eql({})
      })
    })

    it('should nullify function', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => function() {
      })).then(res => {
        res.arguments[2].should.be.eql({})
      })
    })

    it('should wrap error', function() {
      function handler() {
        throw new Error('Error')
      }

      return invoke(createTask(CUSTOM_EVENT, []), modelStub(handler)).then(res => {
        should.equal(res.exception.exceptionMessage, 'Error')
      })
    })
  })
})<commit_msg>fix (tests) increase not enough timeout for async test<commit_after>'use strict'

const should          = require('should'),
      events          = require('../lib/server-code/events'),
      invoke          = require('./helpers/invoke-task'),
      ServerCode      = require('../lib/server-code/api'),
      executor        = require('../lib/server-code/runners/tasks/executor'),
      executionResult = require('../lib/server-code/runners/tasks/util/result-wrapper').executionResult,
      argsUtil        = require('../lib/server-code/runners/tasks/util/args'),
      Backendless     = require('backendless'),
      PERSISTENCE     = events.providers.PERSISTENCE,
      BEFORE_CREATE   = PERSISTENCE.events.beforeCreate,
      AFTER_CREATE    = PERSISTENCE.events.afterCreate,
      CUSTOM_EVENT    = events.providers.CUSTOM.events.execute

require('mocha')

function modelStub(handlerFn, classMappings) {
  return {
    getHandler   : () => ({ invoke: handlerFn }),
    classMappings: classMappings
  }
}

function createTask(event, args, async) {
  return {
    ___jsonclass : executor.RMI,
    eventId      : event.id,
    async        : !!async,
    initAppData  : {},
    applicationId: '',
    relativePath : '',
    arguments    : argsUtil.encode(args || [])
  }
}

describe('[invoke-handler] task executor', function() {
  it('should fill [request] params', function() {
    const context = { userId: 'userId', userToken: 'userToken', userRoles: ['RestUser'] }
    const item = { name: 'John' }

    const task = createTask(BEFORE_CREATE, [context, item])

    function handler(req) {
      should.exist(req.item)
      should.exist(req.context)

      req.item.should.be.eql(item)
      req.context.should.be.eql(context)
    }

    return invoke(task, modelStub(handler))
  })

  it('should respect task execution timeout', function() {
    function handler() {
      return new Promise(() => undefined)
    }

    return invoke(Object.assign(createTask(BEFORE_CREATE), { timeout: 1000 }), modelStub(handler)).then(res => {
      should.exist(res.exception)
      res.exception.exceptionMessage.should.equal('Task execution is aborted due to timeout')
    })
  })

  it('should initialise Backendless with user-token from the request context', function() {
    const userToken = 'wddeupxnpjncbykrlpegexyiunuixxqfckrr'
    const task = createTask(BEFORE_CREATE, [{ userToken: userToken }])
    let handlerInvoked = false

    function handler() {
      handlerInvoked = true

      should.equal(Backendless.LocalCache.get('user-token'), userToken)
    }

    return invoke(task, modelStub(handler)).then(res => {
      handlerInvoked.should.be.true()
      should.not.exists(res.exception)
    })
  })

  describe('should perform class mapping', function() {
    it('for persistence items', function() {
      class Foo {
      }

      class Bar {
      }

      class Baz {
      }

      let handlerInvoked

      function handler(req, res) {
        handlerInvoked = true

        req.item.should.be.instanceof(Foo)
        should.equal(req.item.a, 'a')

        req.item.bar.should.be.instanceof(Bar)
        should.equal(req.item.bar.b, 'b')

        res.result[0].should.be.instanceof(Baz)
        res.result[1].should.be.instanceof(Baz)
      }

      const item = { a: 'a', bar: { ___class: 'Bar', b: 'b' }, ___class: 'Foo' }
      const result = executionResult(null, [{ ___class: 'Baz' }, { ___class: 'Baz' }])

      return invoke(createTask(AFTER_CREATE, [{}, item, result]), modelStub(handler, {
        Foo,
        Bar,
        Baz
      }))
        .then((res) => {
          should.equal(handlerInvoked, true)

          should.not.exists(res.exception)

          should.equal(res.arguments[1].___class, 'Foo')
          should.equal(res.arguments[1].bar.___class, 'Bar')
          should.equal(res.arguments[2].result[0].___class, 'Baz')
          should.equal(res.arguments[2].result[1].___class, 'Baz')
        })
    })
  })

  describe('should handle', function() {
    it('unsupported event error', function() {
      return invoke(createTask({ id: -1 }), { handlers: [] }).then(res => {
        should.exist(res.exception)
        res.exception.exceptionMessage.should.startWith('Integrity violation')
      })
    })

    it('non string error', function() {
      function handler() {
        throw ['Error']
      }

      return invoke(createTask(BEFORE_CREATE), modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.exceptionMessage.should.equal('["Error"]')
      })
    })

    it('errors raised in the event handler', function() {
      function handler() {
        throw new Error('Error')
      }

      return invoke(createTask(BEFORE_CREATE), modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.exceptionMessage.should.equal('Error')
      })
    })

    it('custom errors', function() {
      function handler() {
        throw new ServerCode.Error(10, 'My Custom Error')
      }

      return invoke(createTask(BEFORE_CREATE), modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.code.should.equal(10)
        res.exception.exceptionMessage.should.equal('My Custom Error')
      })
    })

    it('and escape string error code', function() {
      function handler() {
        const err = new Error('StreamError')
        err.code = 'ENOTFOUND'

        throw err
      }

      return invoke(createTask(BEFORE_CREATE), modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.code.should.equal(0)
        res.exception.exceptionMessage.should.equal('StreamError')
      })
    })

    it('async errors raised in the event handler behind the promise', function() {
      function handler() {
        process.nextTick(() => {
          throw new Error('Async Error')
        }, 0)

        //never resolved promise
        return new Promise(() => {
        })
      }

      return invoke(createTask(BEFORE_CREATE), modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.exceptionMessage.should.equal('Async Error')
      })
    })

    it('handler execution timeout', function() {
      const task = createTask(BEFORE_CREATE)
      task.timeout = 1

      function handler() {
        return new Promise((resolve) => {
          setTimeout(() => resolve('buba'), 20)
        })
      }

      return invoke(task, modelStub(handler)).then(res => {
        should.exist(res.exception)
        res.exception.exceptionMessage.should.equal('Task execution is aborted due to timeout')
      })
    })
  })

  describe('in [before] event phase', function() {
    it('should allow input parameters modifying', function() {
      const task = createTask(BEFORE_CREATE, [{}, { name: 'John' }])

      function handler(req) {
        req.item = { name: 'Dou' }
      }

      return invoke(task, modelStub(handler)).then(res => {
        res.arguments[1].should.be.eql({ name: 'Dou' })
      })
    })

    it('should allow short circuit', function() {
      const task = createTask(BEFORE_CREATE, [{}, {}, { name: 'John', id: 1 }])

      function handler() {
        return { name: 'Dou', id: 2 }
      }

      return invoke(task, modelStub(handler)).then(res => {
        should.not.exists(res.exception)

        res.arguments[0].prematureResult.should.be.eql({ name: 'Dou', id: 2 })
      })
    })
  })

  describe('in [after] event phase', function() {
    it('should provide succeeded server result in {response} handler argument', function() {
      const result = { name: 'John', id: 1 }
      const wrappedResult = executionResult(null, result)
      const task = createTask(AFTER_CREATE, [{}, {}, wrappedResult])

      function handler(req, res) {
        should.not.exist(res.error)
        should.exist(res.result)
        res.result.should.be.eql(result)
      }

      return invoke(task, modelStub(handler)).then(res => {
        should.not.exists(res.exception)

        res.arguments[2].should.be.eql(wrappedResult)
      })
    })

    it('should provide erred server result in {response} handler argument', function() {
      const error = 'error'
      const erredResult = executionResult(error)
      const task = createTask(AFTER_CREATE, [{}, {}, erredResult])

      function handler(req, res) {
        should.not.exist(res.result)
        should.exist(res.error)
        res.error.exceptionMessage.should.be.eql(error)

        throw new Error(error)
      }

      return invoke(task, modelStub(handler)).then(res => {
        res.arguments.should.be.empty()
        res.exception.exceptionMessage.should.be.eql(error)
      })
    })

    describe('should allow server result modifying', function() {
      it('by returning a value from handler', function() {
        const task = createTask(AFTER_CREATE, [{}, {}, executionResult(null, {
          name: 'John',
          id  : 1
        })])

        function handler() {
          return { name: 'Dou', id: 2 }
        }

        return invoke(task, modelStub(handler)).then(res => {
          res.arguments[2].result.should.be.eql({ name: 'Dou', id: 2 })
        })
      })

      it('by changing {res.result}', function() {
        const task = createTask(AFTER_CREATE, [{}, {}, executionResult(null, { name: 'John', id: 1 })])

        function handler(req, res) {
          res.result.name = 'John Dou'
        }

        return invoke(task, modelStub(handler)).then(res => {
          res.arguments[2].result.should.be.eql({ name: 'John Dou', id: 1 })
        })
      })

      it('by changing {res.error}', function() {
        const task = createTask(AFTER_CREATE, [{}, {}, executionResult('Error')])

        function handler(req, res) {
          res.error.code = 1
        }

        return invoke(task, modelStub(handler)).then(res => {
          should.exists(res.arguments[2].exception)

          res.arguments[2].exception.code.should.equal(1)
          res.arguments[2].exception.exceptionMessage.should.equal('Error')
        })
      })

      it('by replacing {res.result} and {res.error}', function() {
        const task = createTask(AFTER_CREATE, [{}, {}, executionResult(null, null)])

        function handler(req, res) {
          res.result = { name: 'Dou', id: 2 }
          res.error = {
            code            : 4,
            exceptionMessage: 'Error',
            exceptionClass  : 'java.lang.RuntimeException'
          }
        }

        return invoke(task, modelStub(handler)).then(res => {
          should.exists(res.arguments[2].result)
          should.exists(res.arguments[2].exception)

          res.arguments[2].result.should.be.eql({ name: 'Dou', id: 2 })
          res.arguments[2].exception.code.should.equal(4)
          res.arguments[2].exception.exceptionMessage.should.equal('Error')
        })
      })
    })
  })

  describe('for async events', function() {
    const task = createTask(AFTER_CREATE, [], true)
    task.timeout = 20

    it('should wait for handler`s promise', function() {
      let handlerFinished = false

      function handler() {
        return new Promise(resolve => {
          setTimeout(() => {
            handlerFinished = true
            resolve()
          }, 10)
        })
      }

      return invoke(task, modelStub(handler))
        .then(() => {
          handlerFinished.should.be.true()
        })
    })

    it('should not return any result', function() {
      function handler() {
        return {}
      }

      return invoke(task, modelStub(handler)).should.be.fulfilledWith(undefined)
    })
  })

  describe('for custom events', function() {
    it('should wrap numeric value to object', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => 1)).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql({ result: 1 })
      })
    })

    it('should wrap string value to object', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => 'abc')).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql({ result: 'abc' })
      })
    })

    it('should wrap boolean value to object', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => true)).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql({ result: true })
      })
    })

    it('should wrap date value to object', function() {
      const date = new Date()

      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => date)).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql({ result: date })
      })
    })

    it('should wrap null', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => null)).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql({ result: null })
      })
    })

    it('should not wrap complex object', function() {
      const task = createTask(CUSTOM_EVENT, [])
      const result = { a: 'b' }

      function handler() {
        return result
      }

      return invoke(task, modelStub(handler)).then(res => {
        should.exists(res.arguments[2])
        res.arguments[2].should.be.eql(result)
      })
    })

    it('should nullify undefined', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => undefined)).then(res => {
        res.arguments[2].should.be.eql({})
      })
    })

    it('should nullify function', function() {
      return invoke(createTask(CUSTOM_EVENT, []), modelStub(() => function() {
      })).then(res => {
        res.arguments[2].should.be.eql({})
      })
    })

    it('should wrap error', function() {
      function handler() {
        throw new Error('Error')
      }

      return invoke(createTask(CUSTOM_EVENT, []), modelStub(handler)).then(res => {
        should.equal(res.exception.exceptionMessage, 'Error')
      })
    })
  })
})<|endoftext|>


<commit_before>
module.exports = function(grunt) {

	var _ = require('underscore');

	// Load required NPM tasks.
	// You must first run `npm install` in the project's root directory to get these dependencies.
	grunt.loadNpmTasks('grunt-contrib-concat');
	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-compress');
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-jscs-checker');
	grunt.loadNpmTasks('grunt-karma');
	grunt.loadNpmTasks('grunt-bump');
	grunt.loadNpmTasks('lumbar');

	// This will eventually get passed to grunt.initConfig()
	// Initialize multitasks...
	var config = {
		concat: {},
		uglify: {},
		copy: {},
		compress: {},
		clean: {
			temp: 'build/temp'
		}
	};

	// for the "meta" template variable (<%= meta.whatever %>)
	config.meta = grunt.file.readJSON('fullcalendar.jquery.json');

	// The "grunt" command with no arguments
	grunt.registerTask('default', 'archive');

	// Bare minimum for debugging
	grunt.registerTask('dev', [
		'lumbar:build',
		'languages'
	]);

	// Builds a clean dist directory, for a new release possibly
	grunt.registerTask('dist', [
		'clean',
		'modules',
		'languages',
		'karma:continuous'
	]);

	/* FullCalendar Modules
	----------------------------------------------------------------------------------------------------*/

	grunt.registerTask('modules', 'Build the FullCalendar modules', [
		'jscs:srcModules',
		'clean:modules',
		'lumbar:build',
		'concat:moduleVariables',
		'jshint:builtModules',
		'uglify:modules'
	]);

	// assemble modules
	config.lumbar = {
		build: {
			build: 'build/lumbar.json',
			output: 'dist' // a directory. lumbar doesn't like trailing slash
		}
	};

	// replace template variables (<%= %>), IN PLACE
	config.concat.moduleVariables = {
		options: {
			process: true // replace
		},
		expand: true,
		cwd: 'dist/',
		src: [ '*.js', '*.css' ],
		dest: 'dist/'
	};

	// create minified versions (*.min.js)
	config.uglify.modules = {
		options: {
			preserveComments: 'some' // keep comments starting with /*!
		},
		expand: true,
		src: 'dist/fullcalendar.js', // only do it for fullcalendar.js
		ext: '.min.js'
	};

	config.clean.modules = [
		'dist/*.{js,css,map}', // maps created by lumbar sourceMap
		'dist/src' // created by lumbar sourceMap
	];

	/* Languages
	----------------------------------------------------------------------------------------------------*/

	grunt.registerTask('languages', [
		'jscs:srcLanguages',
		'jshint:srcLanguages',
		'clean:languages',
		'generateLanguages',
		'uglify:languages',
		'uglify:languagesAll'
	]);

	config.generateLanguages = {
		moment: 'lib/moment/lang/',
		datepicker: 'lib/jquery-ui/ui/i18n/',
		fullCalendar: 'lang/',
		dest: 'build/temp/lang/',
		allDest: 'build/temp/lang-all.js'
	};

	config.uglify.languages = {
		expand: true,
		cwd: 'build/temp/lang/',
		src: '*.js',
		dest: 'dist/lang/'
	};

	config.uglify.languagesAll = {
		src: 'build/temp/lang-all.js',
		dest: 'dist/lang-all.js'
	};

	config.clean.languages = [
		'build/temp/lang',
		'build/temp/lang-all.js',
		'dist/lang',
		'dist/lang-all.js'
	];

	/* Automated Tests
	----------------------------------------------------------------------------------------------------*/

	config.karma = {
		options: {
			configFile: 'build/karma.conf.js'
		},
		url: {}, // you'll have to visit a URL in a browser
		headless: { browsers: [ 'PhantomJS' ] },
		continuous: { browsers: [ 'PhantomJS' ], singleRun: true } // "continuous integration" mode
	};

	/* Archive
	----------------------------------------------------------------------------------------------------*/

	grunt.registerTask('archive', 'Create a distributable ZIP archive', [
		'clean:archive',
		'modules',
		'languages',
		'karma:continuous',
		'copy:archiveModules',
		'copy:archiveLanguages',
		'copy:archiveLanguagesAll',
		'copy:archiveMoment',
		'copy:archiveJQuery',
		'concat:archiveJQueryUI',
		'copy:archiveDemos',
		'copy:archiveDemoTheme',
		'copy:archiveMisc',
		'compress:archive'
	]);

	// copy FullCalendar modules into ./fullcalendar/ directory
	config.copy.archiveModules = {
		expand: true,
		cwd: 'dist/',
		src: [ '*.js', '*.css' ],
		dest: 'build/temp/archive/'
	};

	config.copy.archiveLanguages = {
		expand: true,
		cwd: 'dist/lang/',
		src: '*.js',
		dest: 'build/temp/archive/lang/'
	};

	config.copy.archiveLanguagesAll = {
		src: 'dist/lang-all.js',
		dest: 'build/temp/archive/lang-all.js'
	};

	config.copy.archiveMoment = {
		src: 'lib/moment/min/moment.min.js',
		dest: 'build/temp/archive/lib/moment.min.js'
	};

	config.copy.archiveJQuery = {
		src: 'lib/jquery/jquery.min.js',
		dest: 'build/temp/archive/lib/jquery.min.js'
	};

	config.concat.archiveJQueryUI = {
		src: [
			'lib/jquery-ui/ui/minified/jquery.ui.core.min.js',
			'lib/jquery-ui/ui/minified/jquery.ui.widget.min.js',
			'lib/jquery-ui/ui/minified/jquery.ui.mouse.min.js',
			'lib/jquery-ui/ui/minified/jquery.ui.draggable.min.js',
			'lib/jquery-ui/ui/minified/jquery.ui.resizable.min.js'
		],
		dest: 'build/temp/archive/lib/jquery-ui.custom.min.js'
	};

	// copy demo files into ./demos/ directory
	config.copy.archiveDemos = {
		options: {
			processContent: function(content) {
				content = content.replace(/((?:src|href)=['"])([^'"]*)(['"])/g, function(m0, m1, m2, m3) {
					return m1 + transformDemoPath(m2) + m3;
				});
				return content;
			}
		},
		src: 'demos/**',
		dest: 'build/temp/archive/'
	};

	// copy the "cupertino" jquery-ui theme into the demo directory (for demos/theme.html)
	config.copy.archiveDemoTheme = {
		expand: true,
		cwd: 'lib/jquery-ui/themes/cupertino/',
		src: [ 'jquery-ui.min.css', 'images/*' ],
		dest: 'build/temp/archive/lib/cupertino/'
	};

	// in demo HTML, rewrites paths to work in the archive
	function transformDemoPath(path) {
		path = path.replace('../lib/moment/moment.js', '../lib/moment.min.js');
		path = path.replace('../lib/jquery/jquery.js', '../lib/jquery.min.js');
		path = path.replace('../lib/jquery-ui/ui/jquery-ui.js', '../lib/jquery-ui.custom.min.js');
		path = path.replace('../lib/jquery-ui/themes/cupertino/', '../lib/cupertino/');
		path = path.replace('../dist/', '../');
		path = path.replace('/fullcalendar.js', '/fullcalendar.min.js');
		return path;
	}

	// copy license and changelog
	config.copy.archiveMisc = {
		files: {
			'build/temp/archive/license.txt': 'license.txt',
			'build/temp/archive/changelog.txt': 'changelog.md'
		}
	};

	// create the ZIP
	config.compress.archive = {
		options: {
			archive: 'dist/<%= meta.name %>-<%= meta.version %>.zip'
		},
		expand: true,
		cwd: 'build/temp/archive/',
		src: '**',
		dest: '<%= meta.name %>-<%= meta.version %>/' // have a top-level directory in the ZIP file
	};

	config.clean.archive = [
		'build/temp/archive',
		'dist/*.zip'
	];

	/* Release Utilities
	----------------------------------------------------------------------------------------------------*/

	config.bump = { // changes the version number in the configs
		options: {
			files: '*.json',
			commit: false,
			createTag: false,
			push: false
		}
	};

	/* CDNJS (http://cdnjs.com/)
	----------------------------------------------------------------------------------------------------*/

	grunt.registerTask('cdnjs', 'Build files for CDNJS\'s hosted version of FullCalendar', [
		'clean:cdnjs',
		'modules',
		'languages',
		'karma:continuous',
		'copy:cdnjsModules',
		'copy:cdnjsLanguages',
		'copy:cdnjsLanguagesAll',
		'cdnjsConfig'
	]);

	config.copy.cdnjsModules = {
		expand: true,
		cwd: 'dist/',
		src: [ '*.js', '*.css' ],
		dest: 'dist/cdnjs/<%= meta.version %>/'
	};

	config.copy.cdnjsLanguages = {
		expand: true,
		cwd: 'dist/lang/',
		src: '*.js',
		dest: 'dist/cdnjs/<%= meta.version %>/lang/'
	};

	config.copy.cdnjsLanguagesAll = {
		src: 'dist/lang-all.js',
		dest: 'dist/cdnjs/<%= meta.version %>/lang-all.js'
	};

	grunt.registerTask('cdnjsConfig', function() {
		var jqueryConfig = grunt.file.readJSON('fullcalendar.jquery.json');
		var cdnjsConfig = grunt.file.readJSON('build/cdnjs.json');
		grunt.file.write(
			'dist/cdnjs/package.json',
			JSON.stringify(
				_.extend({}, jqueryConfig, cdnjsConfig), // combine 2 configs
				null, // replace
				2 // indent
			)
		);
	});

	config.clean.cdnjs = 'dist/cdnjs';

	/* Linting and Code Style Checking
	----------------------------------------------------------------------------------------------------*/

	grunt.registerTask('check', 'Lint and check code style', [
		'jscs',
		'jshint:srcModules', // so we can fix most quality errors in their original files
		'lumbar:build',
		'jshint' // will run srcModules again but oh well
	]);

	// configs located elsewhere
	config.jshint = require('./build/jshint.conf');
	config.jscs = require('./build/jscs.conf');

	// finally, give grunt the config object...
	grunt.initConfig(config);

	grunt.loadTasks('./build/tasks/');
};
<commit_msg>`grunt dist` builds archive and cdnjs now<commit_after>
module.exports = function(grunt) {

	var _ = require('underscore');

	// Load required NPM tasks.
	// You must first run `npm install` in the project's root directory to get these dependencies.
	grunt.loadNpmTasks('grunt-contrib-concat');
	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-compress');
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-jscs-checker');
	grunt.loadNpmTasks('grunt-karma');
	grunt.loadNpmTasks('grunt-bump');
	grunt.loadNpmTasks('lumbar');

	// This will eventually get passed to grunt.initConfig()
	// Initialize multitasks...
	var config = {
		concat: {},
		uglify: {},
		copy: {},
		compress: {},
		clean: {
			temp: 'build/temp'
		}
	};

	// for the "meta" template variable (<%= meta.whatever %>)
	config.meta = grunt.file.readJSON('fullcalendar.jquery.json');

	// The "grunt" command with no arguments
	grunt.registerTask('default', 'dist');

	// Builds all distributable files, for a new release possibly
	grunt.registerTask('dist', [
		'clean',
		'modules',
		'languages',
		'karma:continuous',
		'archiveDist',
		'cdnjsDist'
	]);

	// Bare minimum for debugging
	grunt.registerTask('dev', [
		'lumbar:build',
		'languages'
	]);

	/* FullCalendar Modules
	----------------------------------------------------------------------------------------------------*/

	grunt.registerTask('modules', 'Build the FullCalendar modules', [
		'jscs:srcModules',
		'clean:modules',
		'lumbar:build',
		'concat:moduleVariables',
		'jshint:builtModules',
		'uglify:modules'
	]);

	// assemble modules
	config.lumbar = {
		build: {
			build: 'build/lumbar.json',
			output: 'dist' // a directory. lumbar doesn't like trailing slash
		}
	};

	// replace template variables (<%= %>), IN PLACE
	config.concat.moduleVariables = {
		options: {
			process: true // replace
		},
		expand: true,
		cwd: 'dist/',
		src: [ '*.js', '*.css' ],
		dest: 'dist/'
	};

	// create minified versions (*.min.js)
	config.uglify.modules = {
		options: {
			preserveComments: 'some' // keep comments starting with /*!
		},
		expand: true,
		src: 'dist/fullcalendar.js', // only do it for fullcalendar.js
		ext: '.min.js'
	};

	config.clean.modules = [
		'dist/*.{js,css,map}', // maps created by lumbar sourceMap
		'dist/src' // created by lumbar sourceMap
	];

	/* Languages
	----------------------------------------------------------------------------------------------------*/

	grunt.registerTask('languages', [
		'jscs:srcLanguages',
		'jshint:srcLanguages',
		'clean:languages',
		'generateLanguages',
		'uglify:languages',
		'uglify:languagesAll'
	]);

	config.generateLanguages = {
		moment: 'lib/moment/lang/',
		datepicker: 'lib/jquery-ui/ui/i18n/',
		fullCalendar: 'lang/',
		dest: 'build/temp/lang/',
		allDest: 'build/temp/lang-all.js'
	};

	config.uglify.languages = {
		expand: true,
		cwd: 'build/temp/lang/',
		src: '*.js',
		dest: 'dist/lang/'
	};

	config.uglify.languagesAll = {
		src: 'build/temp/lang-all.js',
		dest: 'dist/lang-all.js'
	};

	config.clean.languages = [
		'build/temp/lang',
		'build/temp/lang-all.js',
		'dist/lang',
		'dist/lang-all.js'
	];

	/* Automated Tests
	----------------------------------------------------------------------------------------------------*/

	config.karma = {
		options: {
			configFile: 'build/karma.conf.js'
		},
		url: {}, // you'll have to visit a URL in a browser
		headless: { browsers: [ 'PhantomJS' ] },
		continuous: { browsers: [ 'PhantomJS' ], singleRun: true } // "continuous integration" mode
	};

	/* Archive
	----------------------------------------------------------------------------------------------------*/

	grunt.registerTask('archive', 'Create a distributable ZIP archive', [
		'modules',
		'languages',
		'karma:continuous',
		'archiveDist'
	]);

	grunt.registerTask('archiveDist', [
		'clean:archive',
		'copy:archiveModules',
		'copy:archiveLanguages',
		'copy:archiveLanguagesAll',
		'copy:archiveMoment',
		'copy:archiveJQuery',
		'concat:archiveJQueryUI',
		'copy:archiveDemos',
		'copy:archiveDemoTheme',
		'copy:archiveMisc',
		'compress:archive'
	]);

	// copy FullCalendar modules into ./fullcalendar/ directory
	config.copy.archiveModules = {
		expand: true,
		cwd: 'dist/',
		src: [ '*.js', '*.css' ],
		dest: 'build/temp/archive/'
	};

	config.copy.archiveLanguages = {
		expand: true,
		cwd: 'dist/lang/',
		src: '*.js',
		dest: 'build/temp/archive/lang/'
	};

	config.copy.archiveLanguagesAll = {
		src: 'dist/lang-all.js',
		dest: 'build/temp/archive/lang-all.js'
	};

	config.copy.archiveMoment = {
		src: 'lib/moment/min/moment.min.js',
		dest: 'build/temp/archive/lib/moment.min.js'
	};

	config.copy.archiveJQuery = {
		src: 'lib/jquery/jquery.min.js',
		dest: 'build/temp/archive/lib/jquery.min.js'
	};

	config.concat.archiveJQueryUI = {
		src: [
			'lib/jquery-ui/ui/minified/jquery.ui.core.min.js',
			'lib/jquery-ui/ui/minified/jquery.ui.widget.min.js',
			'lib/jquery-ui/ui/minified/jquery.ui.mouse.min.js',
			'lib/jquery-ui/ui/minified/jquery.ui.draggable.min.js',
			'lib/jquery-ui/ui/minified/jquery.ui.resizable.min.js'
		],
		dest: 'build/temp/archive/lib/jquery-ui.custom.min.js'
	};

	// copy demo files into ./demos/ directory
	config.copy.archiveDemos = {
		options: {
			processContent: function(content) {
				content = content.replace(/((?:src|href)=['"])([^'"]*)(['"])/g, function(m0, m1, m2, m3) {
					return m1 + transformDemoPath(m2) + m3;
				});
				return content;
			}
		},
		src: 'demos/**',
		dest: 'build/temp/archive/'
	};

	// copy the "cupertino" jquery-ui theme into the demo directory (for demos/theme.html)
	config.copy.archiveDemoTheme = {
		expand: true,
		cwd: 'lib/jquery-ui/themes/cupertino/',
		src: [ 'jquery-ui.min.css', 'images/*' ],
		dest: 'build/temp/archive/lib/cupertino/'
	};

	// in demo HTML, rewrites paths to work in the archive
	function transformDemoPath(path) {
		path = path.replace('../lib/moment/moment.js', '../lib/moment.min.js');
		path = path.replace('../lib/jquery/jquery.js', '../lib/jquery.min.js');
		path = path.replace('../lib/jquery-ui/ui/jquery-ui.js', '../lib/jquery-ui.custom.min.js');
		path = path.replace('../lib/jquery-ui/themes/cupertino/', '../lib/cupertino/');
		path = path.replace('../dist/', '../');
		path = path.replace('/fullcalendar.js', '/fullcalendar.min.js');
		return path;
	}

	// copy license and changelog
	config.copy.archiveMisc = {
		files: {
			'build/temp/archive/license.txt': 'license.txt',
			'build/temp/archive/changelog.txt': 'changelog.md'
		}
	};

	// create the ZIP
	config.compress.archive = {
		options: {
			archive: 'dist/<%= meta.name %>-<%= meta.version %>.zip'
		},
		expand: true,
		cwd: 'build/temp/archive/',
		src: '**',
		dest: '<%= meta.name %>-<%= meta.version %>/' // have a top-level directory in the ZIP file
	};

	config.clean.archive = [
		'build/temp/archive',
		'dist/*.zip'
	];

	/* Release Utilities
	----------------------------------------------------------------------------------------------------*/

	config.bump = { // changes the version number in the configs
		options: {
			files: '*.json',
			commit: false,
			createTag: false,
			push: false
		}
	};

	/* CDNJS (http://cdnjs.com/)
	----------------------------------------------------------------------------------------------------*/

	grunt.registerTask('cdnjs', 'Build files for CDNJS\'s hosted version of FullCalendar', [
		'modules',
		'languages',
		'karma:continuous',
		'cdnjsDist'
	]);

	grunt.registerTask('cdnjsDist', [
		'clean:cdnjs',
		'copy:cdnjsModules',
		'copy:cdnjsLanguages',
		'copy:cdnjsLanguagesAll',
		'cdnjsConfig'
	]);

	config.copy.cdnjsModules = {
		expand: true,
		cwd: 'dist/',
		src: [ '*.js', '*.css' ],
		dest: 'dist/cdnjs/<%= meta.version %>/'
	};

	config.copy.cdnjsLanguages = {
		expand: true,
		cwd: 'dist/lang/',
		src: '*.js',
		dest: 'dist/cdnjs/<%= meta.version %>/lang/'
	};

	config.copy.cdnjsLanguagesAll = {
		src: 'dist/lang-all.js',
		dest: 'dist/cdnjs/<%= meta.version %>/lang-all.js'
	};

	grunt.registerTask('cdnjsConfig', function() {
		var jqueryConfig = grunt.file.readJSON('fullcalendar.jquery.json');
		var cdnjsConfig = grunt.file.readJSON('build/cdnjs.json');
		grunt.file.write(
			'dist/cdnjs/package.json',
			JSON.stringify(
				_.extend({}, jqueryConfig, cdnjsConfig), // combine 2 configs
				null, // replace
				2 // indent
			)
		);
	});

	config.clean.cdnjs = 'dist/cdnjs';

	/* Linting and Code Style Checking
	----------------------------------------------------------------------------------------------------*/

	grunt.registerTask('check', 'Lint and check code style', [
		'jscs',
		'jshint:srcModules', // so we can fix most quality errors in their original files
		'lumbar:build',
		'jshint' // will run srcModules again but oh well
	]);

	// configs located elsewhere
	config.jshint = require('./build/jshint.conf');
	config.jscs = require('./build/jscs.conf');

	// finally, give grunt the config object...
	grunt.initConfig(config);

	grunt.loadTasks('./build/tasks/');
};
<|endoftext|>


<commit_before>$(document).ready(function () {
    $('.coordinates_modal').each(function (event) {
        let gps_input = $(this).prev().find('input')
        let gps_value = $(gps_input).attr("value").length > 0 ? $(gps_input).attr("value") : $(gps_input).attr("default_coordinates")
        $(this).on('shown.bs.modal', function () {
            $(this).find(".modal-body").append('

')
            drawMap("map", gps_value)
        })
        $(this).on('hidden.bs.modal', function () {
            $('#map').remove();
        })
        $(this).find("button.save_gps").on('click', function () {
            let coordinates = $('#map').parent().prev().find(".modal_gps_value").text();
            $(gps_input).val(coordinates)
        })
    })
})
<commit_msg>Check value length only if value is defined (task #15152)<commit_after>$(document).ready(function () {
    $('.coordinates_modal').each(function (event) {
        let gps_input = $(this).prev().find('input')
        let gps_value = $(gps_input).attr("value") && $(gps_input).attr("value").length > 0 ?
            $(gps_input).attr("value") :
            $(gps_input).attr("default_coordinates")
        $(this).on('shown.bs.modal', function () {
            $(this).find(".modal-body").append('

')
            drawMap("map", gps_value)
        })
        $(this).on('hidden.bs.modal', function () {
            $('#map').remove();
        })
        $(this).find("button.save_gps").on('click', function () {
            let coordinates = $('#map').parent().prev().find(".modal_gps_value").text();
            $(gps_input).val(coordinates)
        })
    })
})
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var DomElement = new function() {
	function cumulate(el, name, parent, positioned) {
		var left = name + 'Left',
			top = name + 'Top',
			x = 0,
			y = 0;
			// If we're asked to calculate positioned offset, stop at any
			// parent element that has relative or absolute position.
			while (el && (!positioned
					|| !/^(relative|absolute)$/.test(el.style.position))) {
			x += el[left] || 0;
			y += el[top] || 0;
			el = el[parent];
		}
		return Point.create(x, y);
	}

	return {
		getOffset: function(el, positioned, scroll) {
			var point = cumulate(el, 'offset', 'offsetParent', positioned);
			return scroll
				? point.subtract(cumulate(el, 'scroll', 'parentNode'))
				: point;
		},

		getSize: function(el) {
			return Size.create(el.offsetWidth, el.offsetHeight);
		},

		getBounds: function(el, positioned, scroll) {
			return new Rectangle(DomElement.getOffset(el, positioned, scroll),
					DomElement.getSize(el));
		},

		getWindowSize: function() {
			var doc = document.getElementsByTagName(
					document.compatMode === 'CSS1Compat' ? 'html' : 'body')[0];
			return Size.create(
				window.innerWidth || doc.clientWidth,
				window.innerHeight || doc.clientHeight
			);
		},

		/**
		 * Checks if element is invisibile (display: none, ...)
		 */
		isInvisible: function(el) {
			return DomElement.getSize(el).equals([0, 0]);
		},

		/**
		 * Checks if element is visibile in current viewport
		 */
		isVisible: function(el) {
			// See if the scrolled bounds intersect with the windows rectangle
			// which always starts at 0, 0
			return !DomElement.isInvisible(el)
					&& new Rectangle([0, 0], DomElement.getWindowSize())
						.intersects(DomElement.getBounds(el, false, true));
		}
	};
};
<commit_msg>Define DomElement.getComputedStyle()<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var DomElement = new function() {
	function cumulate(el, name, parent, positioned) {
		var left = name + 'Left',
			top = name + 'Top',
			x = 0,
			y = 0;
			// If we're asked to calculate positioned offset, stop at any
			// parent element that has relative or absolute position.
			while (el && (!positioned
					|| !/^(relative|absolute)$/.test(el.style.position))) {
			x += el[left] || 0;
			y += el[top] || 0;
			el = el[parent];
		}
		return Point.create(x, y);
	}

	return {
		getWindow: function(doc) {
			return doc.defaultView || doc.parentWindow;
		},

		getComputedStyle: function(el, name) {
			if (el.currentStyle)
				return el.currentStyle[Base.camelize(name)];
			var style = DomElement.getWindow(el.ownerDocument).getComputedStyle(
					el, null);
			return style ? style.getPropertyValue(Base.hyphenate(name)) : null;
		},

		getOffset: function(el, positioned, scroll) {
			var point = cumulate(el, 'offset', 'offsetParent', positioned);
			return scroll
				? point.subtract(cumulate(el, 'scroll', 'parentNode'))
				: point;
		},

		getSize: function(el) {
			return Size.create(el.offsetWidth, el.offsetHeight);
		},

		getBounds: function(el, positioned, scroll) {
			return new Rectangle(DomElement.getOffset(el, positioned, scroll),
					DomElement.getSize(el));
		},

		getWindowSize: function() {
			var doc = document.getElementsByTagName(
					document.compatMode === 'CSS1Compat' ? 'html' : 'body')[0];
			return Size.create(
				window.innerWidth || doc.clientWidth,
				window.innerHeight || doc.clientHeight
			);
		},

		/**
		 * Checks if element is invisibile (display: none, ...)
		 */
		isInvisible: function(el) {
			return DomElement.getSize(el).equals([0, 0]);
		},

		/**
		 * Checks if element is visibile in current viewport
		 */
		isVisible: function(el) {
			// See if the scrolled bounds intersect with the windows rectangle
			// which always starts at 0, 0
			return !DomElement.isInvisible(el)
					&& new Rectangle([0, 0], DomElement.getWindowSize())
						.intersects(DomElement.getBounds(el, false, true));
		}
	};
};
<|endoftext|>


<commit_before>'use babel'
const adb = require('adbkit');
const _ = require('lodash');
export default class DeviceTracker {
  constructor(){
    this.trackerInstance=undefined;
    this.listenersMap={};
  }
  startTracking(name){
    if(this.trackerInstance){
      this.trackerInstance.stop();
    }
    this._createTrackerForPlatform(name);
  }
  _createTrackerForPlatform(platform){
    if(platform === "android"){
       this._createAndroidTrackerAdapter();
    }else if(platform === "ios"){
       this._createiOSTrackerAdapter()
    }
  }

  _createAndroidTrackerAdapter(){
    const client = adb.createClient();
    client.trackDevices()
    .then((tracker) => {

        tracker.on('add', (device) => {
            console.log('Device was plugged in:', device);
            this._fireCallback("DEVICE_LIST_CHANGE",device);
        });
        tracker.on('remove', (device) => {
            console.log('Device was unplugged: ', device.id)
            this._fireCallback("DEVICE_LIST_CHANGE",device);
        });
        tracker.on('end', () => {
            console.log('Tracking stopped')
            this._fireCallback("DEVICE_STOP_TRACKING");
        });

        this.trackerInstance={
          stop:function(){
            tracker.end();
          }
        }
    })
    .catch((err) => {
        console.error('Something went wrong:', err.stack);
        this.trackerInstance = undefined;
    });
  }

  _createiOSTrackerAdapter(){
    const iosDevice = require('node-ios-device');
    const handler = iosDevice.trackDevices()
       .on('devices', (devices) => {
         console.log("ios tracker devices: ",devices);
         this.fireCallback('DEVICE_LIST_CHANGE',devices);
        })
       .on("error",(err) => {
           console.error('Something went wrong:', err);
           this.trackerInstance = undefined;
       });
    this.trackerInstance= {
      stop:function(){
        handler.stop();
      }
    }
  }

  _fireCallback(topic,data){
    if(!this.listenersMap[topic]){
      return;
    }
    _.forEach(this.listenersMap[topic],function(callback){
      callback(data);
    });
  }

  on(topic,callback){
    if(!this.listenersMap[topic]){
      this.listenersMap[topic]=[callback];
    }else{
      this.listenersMap[topic].push(callback);
    }
  }

  off(topic,callback){
    if(!this.listenersMap[topic]){
      return;
    }
    _.remove(this.listenersMap[topic],function(item){
      item === callback;
    });
  }

  offAllTopic(){
    this.listenersMap={};
  }
  isTrackingEnabled(){
    return this.trackerInstance != undefined;
  }

  stopTracking(){
    if(this.trackerInstance){
      this.trackerInstance.stop();
    }
    this.trackerInstance=undefined;
  }

}
<commit_msg>Removed node-ios-device dependency for Windows copatibility<commit_after>'use babel'
const adb = require('adbkit');
const _ = require('lodash');
export default class DeviceTracker {
  constructor(){
    this.trackerInstance=undefined;
    this.listenersMap={};
  }
  startTracking(name){
    if(this.trackerInstance){
      this.trackerInstance.stop();
    }
    this._createTrackerForPlatform(name);
  }
  _createTrackerForPlatform(platform){
    if(platform === "android"){
       this._createAndroidTrackerAdapter();
    }else if(platform === "ios"){
       //this._createiOSTrackerAdapter()
    }
  }

  _createAndroidTrackerAdapter(){
    const client = adb.createClient();
    client.trackDevices()
    .then((tracker) => {

        tracker.on('add', (device) => {
            console.log('Device was plugged in:', device);
            this._fireCallback("DEVICE_LIST_CHANGE",device);
        });
        tracker.on('remove', (device) => {
            console.log('Device was unplugged: ', device.id)
            this._fireCallback("DEVICE_LIST_CHANGE",device);
        });
        tracker.on('end', () => {
            console.log('Tracking stopped')
            this._fireCallback("DEVICE_STOP_TRACKING");
        });

        this.trackerInstance={
          stop:function(){
            tracker.end();
          }
        }
    })
    .catch((err) => {
        console.error('Something went wrong:', err.stack);
        this.trackerInstance = undefined;
    });
  }

  _createiOSTrackerAdapter(){
    // const iosDevice = require('node-ios-device');
    // const handler = iosDevice.trackDevices()
    //    .on('devices', (devices) => {
    //      console.log("ios tracker devices: ",devices);
    //      this.fireCallback('DEVICE_LIST_CHANGE',devices);
    //     })
    //    .on("error",(err) => {
    //        console.error('Something went wrong:', err);
    //        this.trackerInstance = undefined;
    //    });
    // this.trackerInstance= {
    //   stop:function(){
    //     handler.stop();
    //   }
    // }
  }

  _fireCallback(topic,data){
    if(!this.listenersMap[topic]){
      return;
    }
    _.forEach(this.listenersMap[topic],function(callback){
      callback(data);
    });
  }

  on(topic,callback){
    if(!this.listenersMap[topic]){
      this.listenersMap[topic]=[callback];
    }else{
      this.listenersMap[topic].push(callback);
    }
  }

  off(topic,callback){
    if(!this.listenersMap[topic]){
      return;
    }
    _.remove(this.listenersMap[topic],function(item){
      item === callback;
    });
  }

  offAllTopic(){
    this.listenersMap={};
  }
  isTrackingEnabled(){
    return this.trackerInstance != undefined;
  }

  stopTracking(){
    if(this.trackerInstance){
      this.trackerInstance.stop();
    }
    this.trackerInstance=undefined;
  }

}
<|endoftext|>


<commit_before>/* Bridge for Rinna using Twitter
*
*
* Contributed by Capuccino
*/

const Twitter = require('twitter');
const RinnaBridge = new Twitter({
    consumer_key: '',
    consumer_secret: '',
    access_token_key: '',
    access_token_secret: ''
});

<commit_msg>libify RinnaBridge<commit_after>/* Bridge for Rinna using Twitter
*
*
* Contributed by Capuccino
*/

const Twitter = require('twitter');

/**
 * Initializes a new Twitter Client.
 * @prop {string} __consumerkey your consumer key for twitter.
 * @prop {string} __consumersecret your consumer secret for twitter.
 */

class RinnaClient extends Twitter {
    super(options)
    constructor(__consumerKey,__consumerSecret, __accessKey, __accessSecret) {
        this.__consumerkey = __consumerKey;
        this.__consumersecret = __consumerSecret;
        this.__accessKey = __accessKey;
        this.__accessSecret = __accessSecret;
    }

    /**
     * sends a message through DM
     * @prop {string} message message to send
     */
    createMessage(message) {
        this.post()
    }

}
<|endoftext|>


<commit_before>'use strict';
var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
var mountFolder = function (connect, dir) {
  return connect.static(require('path').resolve(dir));
};

module.exports = function (grunt) {
  // load all grunt tasks
  require('matchdep').filterDev('grunt-*').concat(['gruntacular']).forEach(grunt.loadNpmTasks);

  // configurable paths
  var yeomanConfig = {
    app: 'app',
    dist: 'dist'
  };

  try {
    yeomanConfig.app = require('./component.json').appPath || yeomanConfig.app;
  } catch (e) {}

  grunt.initConfig({
    yeoman: yeomanConfig,
    watch: {
      coffee: {
        files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'],
        tasks: ['coffee:dist']
      },
      coffeeTest: {
        files: ['test/spec/{,*/}*.coffee'],
        tasks: ['coffee:test']
      },
      compass: {
        files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
        tasks: ['compass']
      },
      livereload: {
        files: [
          '<%= yeoman.app %>/{,*/}*.html',
          '{.tmp,<%= yeoman.app %>}/styles/{,*/}*.css',
          '{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg}'
        ],
        tasks: ['livereload']
      }
    },
    connect: {
      livereload: {
        options: {
          port: 9000,
          // Change this to '0.0.0.0' to access the server from outside.
          hostname: 'localhost',
          middleware: function (connect) {
            return [
              lrSnippet,
              mountFolder(connect, '.tmp'),
              mountFolder(connect, yeomanConfig.app)
            ];
          }
        }
      },
      test: {
        options: {
          port: 9000,
          middleware: function (connect) {
            return [
              mountFolder(connect, '.tmp'),
              mountFolder(connect, 'test')
            ];
          }
        }
      }
    },
    open: {
      server: {
        url: 'http://localhost:<%= connect.livereload.options.port %>'
      }
    },
    clean: {
      dist: ['.tmp', '<%= yeoman.dist %>/*'],
      server: '.tmp'
    },
    jshint: {
      options: {
        jshintrc: '.jshintrc'
      },
      all: [
        'Gruntfile.js',
        '<%= yeoman.app %>/scripts/{,*/}*.js'
      ]
    },
    testacular: {
      unit: {
        configFile: 'testacular.conf.js',
        singleRun: true
      }
    },
    coffee: {
      dist: {
        files: {
          '.tmp/scripts/coffee.js': '<%= yeoman.app %>/scripts/*.coffee'
        }
      },
      test: {
        files: [{
          expand: true,
          cwd: '.tmp/spec',
          src: '*.coffee',
          dest: 'test/spec'
        }]
      }
    },
    compass: {
      options: {
        sassDir: '<%= yeoman.app %>/styles',
        cssDir: '.tmp/styles',
        imagesDir: '<%= yeoman.app %>/images',
        javascriptsDir: '<%= yeoman.app %>/scripts',
        fontsDir: '<%= yeoman.app %>/styles/fonts',
        importPath: '<%= yeoman.app %>/components',
        relativeAssets: true
      },
      dist: {},
      server: {
        options: {
          debugInfo: true
        }
      }
    },
    concat: {
      dist: {
        files: {
          '<%= yeoman.dist %>/scripts/scripts.js': [
            '.tmp/scripts/*.js',
            '<%= yeoman.app %>/scripts/*.js'
          ]
        }
      }
    },
    useminPrepare: {
      html: '<%= yeoman.app %>/index.html',
      options: {
        dest: '<%= yeoman.dist %>'
      }
    },
    usemin: {
      html: ['<%= yeoman.dist %>/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
      options: {
        dirs: ['<%= yeoman.dist %>']
      }
    },
    imagemin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.{png,jpg,jpeg}',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },
    cssmin: {
      dist: {
        files: {
          '<%= yeoman.dist %>/styles/main.css': [
            '.tmp/styles/{,*/}*.css',
            '<%= yeoman.app %>/styles/{,*/}*.css'
          ]
        }
      }
    },
    htmlmin: {
      dist: {
        options: {
          /*removeCommentsFromCDATA: true,
          // https://github.com/yeoman/grunt-usemin/issues/44
          //collapseWhitespace: true,
          collapseBooleanAttributes: true,
          removeAttributeQuotes: true,
          removeRedundantAttributes: true,
          useShortDoctype: true,
          removeEmptyAttributes: true,
          removeOptionalTags: true*/
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>',
          src: ['*.html', 'views/*.html'],
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },
    ngmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>/scripts',
          src: '*.js',
          dest: '<%= yeoman.dist %>/scripts'
        }]
      }
    },
    uglify: {
      dist: {
        files: {
          '<%= yeoman.dist %>/scripts/scripts.js': [
            '<%= yeoman.dist %>/scripts/scripts.js'
          ],
        }
      }
    },
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          dest: '<%= yeoman.dist %>',
          src: [
            '*.{ico,txt}',
            '.htaccess',
            'components/**/*'
          ]
        }]
      }
    }
  });

  grunt.renameTask('regarde', 'watch');
  // remove when mincss task is renamed
  grunt.renameTask('mincss', 'cssmin');

  grunt.registerTask('server', [
    'clean:server',
    'coffee:dist',
    'compass:server',
    'livereload-start',
    'connect:livereload',
    'open',
    'watch'
  ]);

  grunt.registerTask('test', [
    'clean:server',
    'coffee',
    'compass',
    'connect:test',
    'testacular'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'jshint',
    'test',
    'coffee',
    'compass:dist',
    'useminPrepare',
    'imagemin',
    'cssmin',
    'htmlmin',
    'concat',
    'copy',
    'cdnify',
    'usemin',
    'ngmin',
    'uglify'
  ]);

  grunt.registerTask('default', ['build']);
};
<commit_msg>Removed Compass for now<commit_after>'use strict';
var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
var mountFolder = function (connect, dir) {
  return connect.static(require('path').resolve(dir));
};

module.exports = function (grunt) {
  // load all grunt tasks
  require('matchdep').filterDev('grunt-*').concat(['gruntacular']).forEach(grunt.loadNpmTasks);

  // configurable paths
  var yeomanConfig = {
    app: 'app',
    dist: 'dist'
  };

  try {
    yeomanConfig.app = require('./component.json').appPath || yeomanConfig.app;
  } catch (e) {}

  grunt.initConfig({
    yeoman: yeomanConfig,
    watch: {
      coffee: {
        files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'],
        tasks: ['coffee:dist']
      },
      coffeeTest: {
        files: ['test/spec/{,*/}*.coffee'],
        tasks: ['coffee:test']
      },
      compass: {
        files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
        tasks: ['compass']
      },
      livereload: {
        files: [
          '<%= yeoman.app %>/{,*/}*.html',
          '{.tmp,<%= yeoman.app %>}/styles/{,*/}*.css',
          '{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg}'
        ],
        tasks: ['livereload']
      }
    },
    connect: {
      livereload: {
        options: {
          port: 9000,
          // Change this to '0.0.0.0' to access the server from outside.
          hostname: 'localhost',
          middleware: function (connect) {
            return [
              lrSnippet,
              mountFolder(connect, '.tmp'),
              mountFolder(connect, yeomanConfig.app)
            ];
          }
        }
      },
      test: {
        options: {
          port: 9000,
          middleware: function (connect) {
            return [
              mountFolder(connect, '.tmp'),
              mountFolder(connect, 'test')
            ];
          }
        }
      }
    },
    open: {
      server: {
        url: 'http://localhost:<%= connect.livereload.options.port %>'
      }
    },
    clean: {
      dist: ['.tmp', '<%= yeoman.dist %>/*'],
      server: '.tmp'
    },
    jshint: {
      options: {
        jshintrc: '.jshintrc'
      },
      all: [
        'Gruntfile.js',
        '<%= yeoman.app %>/scripts/{,*/}*.js'
      ]
    },
    testacular: {
      unit: {
        configFile: 'testacular.conf.js',
        singleRun: true
      }
    },
    coffee: {
      dist: {
        files: {
          '.tmp/scripts/coffee.js': '<%= yeoman.app %>/scripts/*.coffee'
        }
      },
      test: {
        files: [{
          expand: true,
          cwd: '.tmp/spec',
          src: '*.coffee',
          dest: 'test/spec'
        }]
      }
    },
    compass: {
      options: {
        sassDir: '<%= yeoman.app %>/styles',
        cssDir: '.tmp/styles',
        imagesDir: '<%= yeoman.app %>/images',
        javascriptsDir: '<%= yeoman.app %>/scripts',
        fontsDir: '<%= yeoman.app %>/styles/fonts',
        importPath: '<%= yeoman.app %>/components',
        relativeAssets: true
      },
      dist: {},
      server: {
        options: {
          debugInfo: true
        }
      }
    },
    concat: {
      dist: {
        files: {
          '<%= yeoman.dist %>/scripts/scripts.js': [
            '.tmp/scripts/*.js',
            '<%= yeoman.app %>/scripts/*.js'
          ]
        }
      }
    },
    useminPrepare: {
      html: '<%= yeoman.app %>/index.html',
      options: {
        dest: '<%= yeoman.dist %>'
      }
    },
    usemin: {
      html: ['<%= yeoman.dist %>/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
      options: {
        dirs: ['<%= yeoman.dist %>']
      }
    },
    imagemin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.{png,jpg,jpeg}',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },
    cssmin: {
      dist: {
        files: {
          '<%= yeoman.dist %>/styles/main.css': [
            '.tmp/styles/{,*/}*.css',
            '<%= yeoman.app %>/styles/{,*/}*.css'
          ]
        }
      }
    },
    htmlmin: {
      dist: {
        options: {
          /*removeCommentsFromCDATA: true,
          // https://github.com/yeoman/grunt-usemin/issues/44
          //collapseWhitespace: true,
          collapseBooleanAttributes: true,
          removeAttributeQuotes: true,
          removeRedundantAttributes: true,
          useShortDoctype: true,
          removeEmptyAttributes: true,
          removeOptionalTags: true*/
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>',
          src: ['*.html', 'views/*.html'],
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },
    ngmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>/scripts',
          src: '*.js',
          dest: '<%= yeoman.dist %>/scripts'
        }]
      }
    },
    uglify: {
      dist: {
        files: {
          '<%= yeoman.dist %>/scripts/scripts.js': [
            '<%= yeoman.dist %>/scripts/scripts.js'
          ],
        }
      }
    },
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          dest: '<%= yeoman.dist %>',
          src: [
            '*.{ico,txt}',
            '.htaccess',
            'components/**/*'
          ]
        }]
      }
    }
  });

  grunt.renameTask('regarde', 'watch');
  // remove when mincss task is renamed
  grunt.renameTask('mincss', 'cssmin');

  grunt.registerTask('server', [
    'clean:server',
    'coffee:dist',
    'compass:server',
    'livereload-start',
    'connect:livereload',
    'open',
    'watch'
  ]);

  grunt.registerTask('test', [
    'clean:server',
    'coffee',
    'connect:test',
    'testacular'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'jshint',
    'test',
    'coffee',
    'useminPrepare',
    'imagemin',
    'cssmin',
    'htmlmin',
    'concat',
    'copy',
    'cdnify',
    'usemin',
    'ngmin',
    'uglify'
  ]);

  grunt.registerTask('default', ['build']);
};
<|endoftext|>