<commit_before>// Official roles GET controllers

'use strict';

var aFrom               = require('es5-ext/array/from')
  , flatten             = require('es5-ext/array/#/flatten')
  , remove              = require('es5-ext/array/#/remove')
  , uniq                = require('es5-ext/array/#/uniq')
  , constant            = require('es5-ext/function/constant')
  , isNaturalNumber     = require('es5-ext/number/is-natural')
  , toNaturalNumber     = require('es5-ext/number/to-pos-integer')
  , normalizeOptions    = require('es5-ext/object/normalize-options')
  , toArray             = require('es5-ext/object/to-array')
  , ensureCallable      = require('es5-ext/object/valid-callable')
  , ensureObject        = require('es5-ext/object/valid-object')
  , ensureString        = require('es5-ext/object/validate-stringifiable-value')
  , includes            = require('es5-ext/string/#/contains')
  , uncapitalize        = require('es5-ext/string/#/uncapitalize')
  , d                   = require('d')
  , ensureSet           = require('es6-set/valid-set')
  , deferred            = require('deferred')
  , memoize             = require('memoizee')
  , serializeValue      = require('dbjs/_setup/serialize/value')
  , unserializeValue    = require('dbjs/_setup/unserialize/value')
  , ObservableSet       = require('observable-set/primitive')
  , mano                = require('mano')
  , roleNameMap         = require('mano/lib/server/user-role-name-map')
  , QueryHandler        = require('../../utils/query-handler')
  , defaultItemsPerPage = require('../../conf/objects-list-items-per-page')
  , getDbSet            = require('../utils/get-db-set')
  , getDbArray          = require('../utils/get-db-array')
  , getIndexMap         = require('../utils/get-db-sort-index-map')

  , hasBadWs = RegExp.prototype.test.bind(/\s{2,}/)
  , compareStamps = function (a, b) { return a.stamp - b.stamp; }
  , isArray = Array.isArray, slice = Array.prototype.slice, push = Array.prototype.push
  , ceil = Math.ceil, create = Object.create
  , defineProperty = Object.defineProperty, stringify = JSON.stringify;

var compareIndexMeta = function (meta1, meta2) {
	return meta1.name.localeCompare(meta2.name) || meta1.value.localeCompare(meta2.value);
};

// Business processes table query handler
var getTableQueryHandler = function (statusMap) {
	var queryHandler = new QueryHandler(exports.tableQueryConf);
	queryHandler._statusMap = statusMap;
	return queryHandler;
};

// Single business process full data query handler
var getBusinessProcessQueryHandler = function (indexName) {
	return new QueryHandler([
		{
			name: 'id',
			ensure: function (value) {
				if (!value) throw new Error("Missing id");
				return mano.dbDriver.getComputed(value + '/' + indexName)(function (data) {
					if (!data || (data.value !== '11')) return null;
					return value;
				});
			}
		}
	]);
};

var getFilteredSet = memoize(function (baseSet, filterString) {
	var set = new ObservableSet(), baseSetListener, indexListener
	  , def = deferred(), count = 0, isInitialized = false;
	var filter = function (ownerId, data) {
		var value = unserializeValue(data.value);
		if (value && includes.call(value, filterString)) set.add(ownerId);
		else set.delete(ownerId);
	};
	var findAndFilter = function (ownerId) {
		return mano.dbDriver.getComputed(ownerId + '/searchString').aside(function (data) {
			if (!baseSet.has(ownerId)) return;
			if (!data) return;
			filter(ownerId, data);
		});
	};
	baseSet.on('change', baseSetListener = function (event) {
		if (event.type === 'add') findAndFilter(event.value).done();
		else set.delete(event.value);
	});
	mano.dbDriver.on('key:searchString', indexListener = function (event) {
		if (!baseSet.has(event.ownerId)) return;
		filter(event.ownerId, event.data);
	});
	baseSet.forEach(function (ownerId) {
		++count;
		findAndFilter(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(set);
		});
	});
	isInitialized = true;
	if (!count) def.resolve(set);
	defineProperty(set, '_dispose', d(function () {
		baseSet.off(baseSetListener);
		mano.dbDriver.off('key:searchString', indexListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (set) { set._dispose(); } });

var getDbArrayLru = memoize(function (set, sortIndexName) {
	var arr = [], itemsMap = getIndexMap(sortIndexName)
	  , count = 0, isInitialized = false, def = deferred(), setListener, itemsListener;
	var add = function (ownerId) {
		return deferred(itemsMap[ownerId] || mano.dbDriver.getComputed(ownerId + '/' + sortIndexName))
			.aside(function (data) {
				if (!set.has(ownerId)) return;
				if (!itemsMap[ownerId]) itemsMap[ownerId] = { id: ownerId, stamp: data.stamp };
				arr.push(itemsMap[ownerId]);
				if (def.resolved) arr.sort(compareStamps);
			});
	};
	set.on('change', setListener = function (event) {
		if (event.type === 'add') add(event.value).done();
		else remove.call(arr, itemsMap[event.value]);
	});
	itemsMap.on('update', itemsListener = function (event) {
		if (!set.has(event.ownerId)) return;
		if (def.resolved) arr.sort(compareStamps);
	});
	set.forEach(function (ownerId) {
		++count;
		add(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(arr.sort(compareStamps));
		});
	});
	isInitialized = true;
	if (!count) def.resolve(arr.sort(compareStamps));
	defineProperty(set, '_dispose', d(function () {
		set.off(setListener);
		itemsMap.off(itemsListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (arr) { arr._dispose(); } });

var initializeHandler = function (conf) {
	conf = normalizeOptions(ensureObject(conf));
	var roleName = ensureString(conf.roleName)
	  , statusIndexName = ensureString(conf.statusIndexName)
	  , allIndexName = ensureString(conf.allIndexName)
	  , bpListProps = ensureSet(conf.listProperties)
	  , bpListComputedProps = conf.listComputedProperties && aFrom(conf.listComputedProperties)
	  , tableQueryHandler = getTableQueryHandler(ensureObject(conf.statusMap))
	  , businessProcessQueryHandler = getBusinessProcessQueryHandler(conf.allIndexName)
	  , itemsPerPage = toNaturalNumber(conf.itemsPerPage) || defaultItemsPerPage
	  , indexes;

	if (conf.resolveCollectionMeta != null) ensureCallable(conf.resolveCollectionMeta);

	if (bpListComputedProps) {
		indexes = [];
		deferred.map(bpListComputedProps, function (keyPath) {
			return mano.dbDriver.indexKeyPath(keyPath)(function (map) {
				indexes.push({ keyPath: keyPath, map: map });
			});
		});
	}

	var getTableData = memoize(function (query) {
		var indexMeta = exports.getIndexMeta(query, conf), promise;
		if (isArray(indexMeta)) {
			promise = deferred.map(indexMeta.sort(compareIndexMeta), function (indexMeta) {
				return getDbSet('computed', indexMeta.name, indexMeta.value);
			})(function (sets) {
				return aFrom(sets).reduce(function (set1, set2) { return set1.and(set2); });
			});
		} else {
			promise = getDbSet('computed', indexMeta.name, indexMeta.value);
		}
		return promise(function (baseSet) {
			if (!query.search) return getDbArray(baseSet, 'computed', allIndexName);
			return deferred.map(query.search.split(/\s+/).sort(), function (value) {
				return getFilteredSet(baseSet, value)(function (set) {
					return getDbArrayLru(set, allIndexName);
				});
			})(function (arrays) {
				if (arrays.length === 1) return arrays[0];
				return uniq.call(arrays.reduce(function (current, next, index) {
					if (index === 1) current = aFrom(current);
					push.apply(current, next);
					return current;
				})).sort(compareStamps);
			});
		})(function (arr) {
			var size = arr.length, pageCount, offset, computedEvents, directEvents, statuses, statusMap;
			if (!size) return { size: size };
			pageCount = ceil(size / itemsPerPage);
			if (query.page > pageCount) return { size: size };

			// Pagination
			offset = (query.page - 1) * itemsPerPage;
			arr = slice.call(arr, offset, offset + itemsPerPage);
			if (bpListComputedProps) {
				computedEvents = deferred.map(arr, function (data) {
					var objId = data.id;
					return deferred.map(bpListComputedProps, function (keyPath) {
						return mano.dbDriver.getComputed(objId + '/' + keyPath)(function (data) {
							if (isArray(data.value)) {
								return data.value.map(function (data) {
									var key = data.key ? '*' + data.key : '';
									return data.stamp + '.' + objId + '/' + keyPath + key + '.' + data.value;
								});
							}
							return data.stamp + '.' + objId + '/' + keyPath + '.' + data.value;
						});
					});
				});
			} else {
				computedEvents = [];
			}
			directEvents = deferred.map(arr, function (data) {
				return mano.dbDriver.getObject(data.id, { keyPaths: bpListProps })(function (datas) {
					return datas.map(function (data) {
						return data.data.stamp + '.' + data.id + '.' + data.data.value;
					});
				});
			});
			if (!query.status) {
				statusMap = create(null);
				statuses = deferred.map(arr, function (data) {
					return mano.dbDriver.getComputed(data.id + '/' + statusIndexName)
						.aside(function (record) {
							statusMap[data.id] = record ? unserializeValue(record.value) : null;
						});
				})(statusMap);
			}
			return deferred(directEvents, computedEvents, statuses)
				.spread(function (directEvents, computedEvents, statusMap) {
					return {
						view: arr.map(function (data) { return data.stamp + '.' + data.id; }).join('\n'),
						size: size,
						data: flatten.call([directEvents, computedEvents]),
						statusMap: statusMap
					};
				});
		});
	}, {
		normalizer: function (args) { return String(toArray(args[0], null, null, true)); },
		maxAge: 10 * 1000
	});

	return {
		tableQueryHandler: tableQueryHandler,
		getTableData: getTableData,
		businessProcessQueryHandler: businessProcessQueryHandler,
		roleName: roleName
	};
};

module.exports = exports = function (mainConf) {
	var resolveHandler;
	if (isArray(mainConf)) {
		resolveHandler = (function () {
			var map = mainConf.reduce(function (map, conf) {
				map[conf.roleName] = initializeHandler(conf);
				return map;
			}, create(null));
			return function (userId) {
				return roleNameMap.get(userId)(function (roleName) {
					var handler;
					if (roleName) {
						roleName = uncapitalize.call(roleName.slice('official'.length));
						handler = map[roleName];
					}
					if (!handler) {
						throw new Error("Cannot resolve conf for role name: " +  stringify(roleName));
					}
					return handler;
				});
			};
		}());
	} else {
		resolveHandler = constant(deferred(initializeHandler(mainConf)));
	}
	return {
		'get-business-processes-view': function (query) {
			return resolveHandler(this.req.$user)(function (handler) {
				// Get snapshot of business processes table page
				return handler.tableQueryHandler.resolve(query)(function (query) {
					return handler.getTableData(query);
				});
			});
		},
		'get-business-process-data': function (query) {
			return resolveHandler(this.req.$user)(function (handler) {
				// Get full data of one of the business processeses
				return handler.businessProcessQueryHandler.resolve(query)(function (query) {
					var recordId;
					if (!query.id) return { passed: false };
					recordId = this.req.$user + '/recentlyVisited/businessProcesses/' +
						handler.roleName + '*7' + query.id;
					return mano.dbDriver.store(recordId, '11')({ passed: true });
				}.bind(this));
			}.bind(this));
		}
	};
};

exports.getIndexMeta = function (query, conf) {
	var meta;
	if (query.status) {
		if (conf.resolveCollectionMeta) {
			meta = conf.resolveCollectionMeta(query.status);
			return { name: meta.name, value: serializeValue(meta.value) };
		}
		return { name: conf.statusIndexName, value: serializeValue(query.status) };
	}
	return { name: conf.allIndexName, value: '11' };
};

exports.tableQueryConf = [{
	name: 'status',
	ensure: function (value) {
		if (!value) return;
		if (!this._statusMap[value]) {
			throw new Error("Unreconized status value " + stringify(value));
		}
		if (value === 'all') throw new Error("Unexpected default key status");
		return value;
	}
}, {
	name: 'search',
	ensure: function (value) {
		if (!value) return;
		if (value.toLowerCase() !== value) throw new Error("Unexpected search value");
		if (hasBadWs(value)) throw new Error("Unexpected search value");
		if (value !== uniq.call(value.split(/\s/)).join(' ')) {
			throw new Error("Unexpected search value");
		}
		return value;
	}
}, {
	name: 'page',
	ensure: function (value) {
		var num;
		if (isNaN(value)) throw new Error("Unrecognized page value " + stringify(value));
		num = Number(value);
		if (!isNaturalNumber(num)) throw new Error("Unreconized page value " + stringify(value));
		if (!num) throw new Error("Unexpected page value " + stringify(value));
		return value;
	}
}];
<commit_msg>Remove obsolete indexes gathering<commit_after>// Official roles GET controllers

'use strict';

var aFrom               = require('es5-ext/array/from')
  , flatten             = require('es5-ext/array/#/flatten')
  , remove              = require('es5-ext/array/#/remove')
  , uniq                = require('es5-ext/array/#/uniq')
  , constant            = require('es5-ext/function/constant')
  , isNaturalNumber     = require('es5-ext/number/is-natural')
  , toNaturalNumber     = require('es5-ext/number/to-pos-integer')
  , normalizeOptions    = require('es5-ext/object/normalize-options')
  , toArray             = require('es5-ext/object/to-array')
  , ensureCallable      = require('es5-ext/object/valid-callable')
  , ensureObject        = require('es5-ext/object/valid-object')
  , ensureString        = require('es5-ext/object/validate-stringifiable-value')
  , includes            = require('es5-ext/string/#/contains')
  , uncapitalize        = require('es5-ext/string/#/uncapitalize')
  , d                   = require('d')
  , ensureSet           = require('es6-set/valid-set')
  , deferred            = require('deferred')
  , memoize             = require('memoizee')
  , serializeValue      = require('dbjs/_setup/serialize/value')
  , unserializeValue    = require('dbjs/_setup/unserialize/value')
  , ObservableSet       = require('observable-set/primitive')
  , mano                = require('mano')
  , roleNameMap         = require('mano/lib/server/user-role-name-map')
  , QueryHandler        = require('../../utils/query-handler')
  , defaultItemsPerPage = require('../../conf/objects-list-items-per-page')
  , getDbSet            = require('../utils/get-db-set')
  , getDbArray          = require('../utils/get-db-array')
  , getIndexMap         = require('../utils/get-db-sort-index-map')

  , hasBadWs = RegExp.prototype.test.bind(/\s{2,}/)
  , compareStamps = function (a, b) { return a.stamp - b.stamp; }
  , isArray = Array.isArray, slice = Array.prototype.slice, push = Array.prototype.push
  , ceil = Math.ceil, create = Object.create
  , defineProperty = Object.defineProperty, stringify = JSON.stringify;

var compareIndexMeta = function (meta1, meta2) {
	return meta1.name.localeCompare(meta2.name) || meta1.value.localeCompare(meta2.value);
};

// Business processes table query handler
var getTableQueryHandler = function (statusMap) {
	var queryHandler = new QueryHandler(exports.tableQueryConf);
	queryHandler._statusMap = statusMap;
	return queryHandler;
};

// Single business process full data query handler
var getBusinessProcessQueryHandler = function (indexName) {
	return new QueryHandler([
		{
			name: 'id',
			ensure: function (value) {
				if (!value) throw new Error("Missing id");
				return mano.dbDriver.getComputed(value + '/' + indexName)(function (data) {
					if (!data || (data.value !== '11')) return null;
					return value;
				});
			}
		}
	]);
};

var getFilteredSet = memoize(function (baseSet, filterString) {
	var set = new ObservableSet(), baseSetListener, indexListener
	  , def = deferred(), count = 0, isInitialized = false;
	var filter = function (ownerId, data) {
		var value = unserializeValue(data.value);
		if (value && includes.call(value, filterString)) set.add(ownerId);
		else set.delete(ownerId);
	};
	var findAndFilter = function (ownerId) {
		return mano.dbDriver.getComputed(ownerId + '/searchString').aside(function (data) {
			if (!baseSet.has(ownerId)) return;
			if (!data) return;
			filter(ownerId, data);
		});
	};
	baseSet.on('change', baseSetListener = function (event) {
		if (event.type === 'add') findAndFilter(event.value).done();
		else set.delete(event.value);
	});
	mano.dbDriver.on('key:searchString', indexListener = function (event) {
		if (!baseSet.has(event.ownerId)) return;
		filter(event.ownerId, event.data);
	});
	baseSet.forEach(function (ownerId) {
		++count;
		findAndFilter(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(set);
		});
	});
	isInitialized = true;
	if (!count) def.resolve(set);
	defineProperty(set, '_dispose', d(function () {
		baseSet.off(baseSetListener);
		mano.dbDriver.off('key:searchString', indexListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (set) { set._dispose(); } });

var getDbArrayLru = memoize(function (set, sortIndexName) {
	var arr = [], itemsMap = getIndexMap(sortIndexName)
	  , count = 0, isInitialized = false, def = deferred(), setListener, itemsListener;
	var add = function (ownerId) {
		return deferred(itemsMap[ownerId] || mano.dbDriver.getComputed(ownerId + '/' + sortIndexName))
			.aside(function (data) {
				if (!set.has(ownerId)) return;
				if (!itemsMap[ownerId]) itemsMap[ownerId] = { id: ownerId, stamp: data.stamp };
				arr.push(itemsMap[ownerId]);
				if (def.resolved) arr.sort(compareStamps);
			});
	};
	set.on('change', setListener = function (event) {
		if (event.type === 'add') add(event.value).done();
		else remove.call(arr, itemsMap[event.value]);
	});
	itemsMap.on('update', itemsListener = function (event) {
		if (!set.has(event.ownerId)) return;
		if (def.resolved) arr.sort(compareStamps);
	});
	set.forEach(function (ownerId) {
		++count;
		add(ownerId).done(function () {
			if (!--count && isInitialized) def.resolve(arr.sort(compareStamps));
		});
	});
	isInitialized = true;
	if (!count) def.resolve(arr.sort(compareStamps));
	defineProperty(set, '_dispose', d(function () {
		set.off(setListener);
		itemsMap.off(itemsListener);
	}));
	return def.promise;
}, { max: 1000, dispose: function (arr) { arr._dispose(); } });

var initializeHandler = function (conf) {
	conf = normalizeOptions(ensureObject(conf));
	var roleName = ensureString(conf.roleName)
	  , statusIndexName = ensureString(conf.statusIndexName)
	  , allIndexName = ensureString(conf.allIndexName)
	  , bpListProps = ensureSet(conf.listProperties)
	  , bpListComputedProps = conf.listComputedProperties && aFrom(conf.listComputedProperties)
	  , tableQueryHandler = getTableQueryHandler(ensureObject(conf.statusMap))
	  , businessProcessQueryHandler = getBusinessProcessQueryHandler(conf.allIndexName)
	  , itemsPerPage = toNaturalNumber(conf.itemsPerPage) || defaultItemsPerPage;

	if (conf.resolveCollectionMeta != null) ensureCallable(conf.resolveCollectionMeta);

	var getTableData = memoize(function (query) {
		var indexMeta = exports.getIndexMeta(query, conf), promise;
		if (isArray(indexMeta)) {
			promise = deferred.map(indexMeta.sort(compareIndexMeta), function (indexMeta) {
				return getDbSet('computed', indexMeta.name, indexMeta.value);
			})(function (sets) {
				return aFrom(sets).reduce(function (set1, set2) { return set1.and(set2); });
			});
		} else {
			promise = getDbSet('computed', indexMeta.name, indexMeta.value);
		}
		return promise(function (baseSet) {
			if (!query.search) return getDbArray(baseSet, 'computed', allIndexName);
			return deferred.map(query.search.split(/\s+/).sort(), function (value) {
				return getFilteredSet(baseSet, value)(function (set) {
					return getDbArrayLru(set, allIndexName);
				});
			})(function (arrays) {
				if (arrays.length === 1) return arrays[0];
				return uniq.call(arrays.reduce(function (current, next, index) {
					if (index === 1) current = aFrom(current);
					push.apply(current, next);
					return current;
				})).sort(compareStamps);
			});
		})(function (arr) {
			var size = arr.length, pageCount, offset, computedEvents, directEvents, statuses, statusMap;
			if (!size) return { size: size };
			pageCount = ceil(size / itemsPerPage);
			if (query.page > pageCount) return { size: size };

			// Pagination
			offset = (query.page - 1) * itemsPerPage;
			arr = slice.call(arr, offset, offset + itemsPerPage);
			if (bpListComputedProps) {
				computedEvents = deferred.map(arr, function (data) {
					var objId = data.id;
					return deferred.map(bpListComputedProps, function (keyPath) {
						return mano.dbDriver.getComputed(objId + '/' + keyPath)(function (data) {
							if (isArray(data.value)) {
								return data.value.map(function (data) {
									var key = data.key ? '*' + data.key : '';
									return data.stamp + '.' + objId + '/' + keyPath + key + '.' + data.value;
								});
							}
							return data.stamp + '.' + objId + '/' + keyPath + '.' + data.value;
						});
					});
				});
			} else {
				computedEvents = [];
			}
			directEvents = deferred.map(arr, function (data) {
				return mano.dbDriver.getObject(data.id, { keyPaths: bpListProps })(function (datas) {
					return datas.map(function (data) {
						return data.data.stamp + '.' + data.id + '.' + data.data.value;
					});
				});
			});
			if (!query.status) {
				statusMap = create(null);
				statuses = deferred.map(arr, function (data) {
					return mano.dbDriver.getComputed(data.id + '/' + statusIndexName)
						.aside(function (record) {
							statusMap[data.id] = record ? unserializeValue(record.value) : null;
						});
				})(statusMap);
			}
			return deferred(directEvents, computedEvents, statuses)
				.spread(function (directEvents, computedEvents, statusMap) {
					return {
						view: arr.map(function (data) { return data.stamp + '.' + data.id; }).join('\n'),
						size: size,
						data: flatten.call([directEvents, computedEvents]),
						statusMap: statusMap
					};
				});
		});
	}, {
		normalizer: function (args) { return String(toArray(args[0], null, null, true)); },
		maxAge: 10 * 1000
	});

	return {
		tableQueryHandler: tableQueryHandler,
		getTableData: getTableData,
		businessProcessQueryHandler: businessProcessQueryHandler,
		roleName: roleName
	};
};

module.exports = exports = function (mainConf) {
	var resolveHandler;
	if (isArray(mainConf)) {
		resolveHandler = (function () {
			var map = mainConf.reduce(function (map, conf) {
				map[conf.roleName] = initializeHandler(conf);
				return map;
			}, create(null));
			return function (userId) {
				return roleNameMap.get(userId)(function (roleName) {
					var handler;
					if (roleName) {
						roleName = uncapitalize.call(roleName.slice('official'.length));
						handler = map[roleName];
					}
					if (!handler) {
						throw new Error("Cannot resolve conf for role name: " +  stringify(roleName));
					}
					return handler;
				});
			};
		}());
	} else {
		resolveHandler = constant(deferred(initializeHandler(mainConf)));
	}
	return {
		'get-business-processes-view': function (query) {
			return resolveHandler(this.req.$user)(function (handler) {
				// Get snapshot of business processes table page
				return handler.tableQueryHandler.resolve(query)(function (query) {
					return handler.getTableData(query);
				});
			});
		},
		'get-business-process-data': function (query) {
			return resolveHandler(this.req.$user)(function (handler) {
				// Get full data of one of the business processeses
				return handler.businessProcessQueryHandler.resolve(query)(function (query) {
					var recordId;
					if (!query.id) return { passed: false };
					recordId = this.req.$user + '/recentlyVisited/businessProcesses/' +
						handler.roleName + '*7' + query.id;
					return mano.dbDriver.store(recordId, '11')({ passed: true });
				}.bind(this));
			}.bind(this));
		}
	};
};

exports.getIndexMeta = function (query, conf) {
	var meta;
	if (query.status) {
		if (conf.resolveCollectionMeta) {
			meta = conf.resolveCollectionMeta(query.status);
			return { name: meta.name, value: serializeValue(meta.value) };
		}
		return { name: conf.statusIndexName, value: serializeValue(query.status) };
	}
	return { name: conf.allIndexName, value: '11' };
};

exports.tableQueryConf = [{
	name: 'status',
	ensure: function (value) {
		if (!value) return;
		if (!this._statusMap[value]) {
			throw new Error("Unreconized status value " + stringify(value));
		}
		if (value === 'all') throw new Error("Unexpected default key status");
		return value;
	}
}, {
	name: 'search',
	ensure: function (value) {
		if (!value) return;
		if (value.toLowerCase() !== value) throw new Error("Unexpected search value");
		if (hasBadWs(value)) throw new Error("Unexpected search value");
		if (value !== uniq.call(value.split(/\s/)).join(' ')) {
			throw new Error("Unexpected search value");
		}
		return value;
	}
}, {
	name: 'page',
	ensure: function (value) {
		var num;
		if (isNaN(value)) throw new Error("Unrecognized page value " + stringify(value));
		num = Number(value);
		if (!isNaturalNumber(num)) throw new Error("Unreconized page value " + stringify(value));
		if (!num) throw new Error("Unexpected page value " + stringify(value));
		return value;
	}
}];
<|endoftext|>


<commit_before>var fs = require('fs'),
  _ = require('lodash'),
  parser = require('./parser');

var CACHE = {},
  defaultOptions = {
    varControls: ['{{', '}}'],
    tagControls: ['{%', '%}'],
    cmtControls: ['{#', '#}'],
    locals: {},
    tags: require('./tags'),
    cache: 'memory'
  },
  defaultInstance;

function validateOptions(options) {
  if (!options) {
    return;
  }

  _.each(['varControls', 'tagControls', 'cmtControls'], function (key) {
    if (!options.hasOwnProperty(key)) {
      return;
    }
    if (!_.isArray(options[key]) || options[key].length !== 2) {
      throw new Error('Option "' + key + '" must be an array containing 2 different control strings.');
    }
    if (options[key][0] === options[key][1]) {
      throw new Error('Option "' + key + '" open and close controls must not be the same.');
    }
    _.each(options[key], function (a, i) {
      if (a.length < 2) {
        throw new Error('Option "' + key + '" ' + ((i) ? 'open ' : 'close ') + 'control must be at least 2 characters. Saw "' + a + '" instead.');
      }
    });
  });

  if (options.hasOwnProperty('cache')) {
    if (options.cache && options.cache !== 'memory') {
      if (!options.cache.get || !options.cache.set) {
        throw new Error('Invalid cache option ' + JSON.stringify(options.cache) + ' found. Expected "memory" or { get: function (key) { ... }, set: function (key, value) { ... } }.');
      }
    }
  }
}

exports.setDefaults = function (options) {
  validateOptions(options);

  var locals = _.extend({}, defaultOptions.locals, options.locals || {});

  _.extend(defaultOptions, options);
  defaultOptions.locals = locals;

  defaultInstance.options = _.extend(defaultInstance.options, options);
};

exports.Swig = function (opts) {
  validateOptions(opts);
  this.options = _.defaults(opts || {}, defaultOptions);
  this.cache = {};
  var self = this;

  function getLocals(options) {
    if (!options || !options.locals) {
      return self.options.locals;
    }

    return _.extend({}, self.options.locals, options.locals);
  }

  function cacheGet(key) {
    if (!self.options.cache) {
      return;
    }

    if (self.options.cache === 'memory') {
      return self.cache[key];
    }

    return self.options.cache.get(key);
  }

  function cacheSet(key, val) {
    if (!self.options.cache) {
      return;
    }

    if (self.options.cache === 'memory') {
      self.cache[key] = val;
      return;
    }

    self.options.cache.set(key, val);
  }

  this.invalidateCache = function () {
    if (self.options.cache === 'memory') {
      self.cache = {};
    }
  };

  this.parse = function (source, options) {
    validateOptions(options);

    var locals = getLocals(options);

    options = _.extend({}, self.options, _.omit(options, 'locals'));
    options.locals = locals;

    return parser.parse(source, options);
  };

  this.compile = function (source, options) {
    var key = options ? options.filename : null,
      tokens = exports.parse(source, options),
      code = parser.compile(tokens),
      locals = getLocals(options),
      cached = key ? cacheGet(key) : null;

    if (cached) {
      return cached;
    }

    function compiled(context) {
      var tpl = new Function('_ctx', [
        'with (_ctx) {',
        '  var _output = "";',
        code,
        '  return _output;',
        '}'
      ].join('\n  '));

      return tpl(_.extend({}, locals, context || {}));
    }

    if (key) {
      cacheSet(key, compiled);
    }

    return compiled;
  };

  this.render = function (source, options) {
    var locals = getLocals(options);
    return exports.compile(source, options)(locals);
  };

  this.renderFile = function (path, options) {
    var src = fs.readFileSync(path, 'utf8');
    return self.render(src, options);
  };
};

defaultInstance = new exports.Swig();
exports.parse = defaultInstance.parse;
exports.compile = defaultInstance.compile;
exports.render = defaultInstance.render;
exports.invalidateCache = defaultInstance.invalidateCache;
<commit_msg>ensure cache is actually used<commit_after>var fs = require('fs'),
  _ = require('lodash'),
  parser = require('./parser');

var CACHE = {},
  defaultOptions = {
    varControls: ['{{', '}}'],
    tagControls: ['{%', '%}'],
    cmtControls: ['{#', '#}'],
    locals: {},
    tags: require('./tags'),
    cache: 'memory'
  },
  defaultInstance;

function validateOptions(options) {
  if (!options) {
    return;
  }

  _.each(['varControls', 'tagControls', 'cmtControls'], function (key) {
    if (!options.hasOwnProperty(key)) {
      return;
    }
    if (!_.isArray(options[key]) || options[key].length !== 2) {
      throw new Error('Option "' + key + '" must be an array containing 2 different control strings.');
    }
    if (options[key][0] === options[key][1]) {
      throw new Error('Option "' + key + '" open and close controls must not be the same.');
    }
    _.each(options[key], function (a, i) {
      if (a.length < 2) {
        throw new Error('Option "' + key + '" ' + ((i) ? 'open ' : 'close ') + 'control must be at least 2 characters. Saw "' + a + '" instead.');
      }
    });
  });

  if (options.hasOwnProperty('cache')) {
    if (options.cache && options.cache !== 'memory') {
      if (!options.cache.get || !options.cache.set) {
        throw new Error('Invalid cache option ' + JSON.stringify(options.cache) + ' found. Expected "memory" or { get: function (key) { ... }, set: function (key, value) { ... } }.');
      }
    }
  }
}

exports.setDefaults = function (options) {
  validateOptions(options);

  var locals = _.extend({}, defaultOptions.locals, options.locals || {});

  _.extend(defaultOptions, options);
  defaultOptions.locals = locals;

  defaultInstance.options = _.extend(defaultInstance.options, options);
};

exports.Swig = function (opts) {
  validateOptions(opts);
  this.options = _.defaults(opts || {}, defaultOptions);
  this.cache = {};
  var self = this;

  function getLocals(options) {
    if (!options || !options.locals) {
      return self.options.locals;
    }

    return _.extend({}, self.options.locals, options.locals);
  }

  function cacheGet(key) {
    if (!self.options.cache) {
      return;
    }

    if (self.options.cache === 'memory') {
      return self.cache[key];
    }

    return self.options.cache.get(key);
  }

  function cacheSet(key, val) {
    if (!self.options.cache) {
      return;
    }

    if (self.options.cache === 'memory') {
      self.cache[key] = val;
      return;
    }

    self.options.cache.set(key, val);
  }

  this.invalidateCache = function () {
    if (self.options.cache === 'memory') {
      self.cache = {};
    }
  };

  this.parse = function (source, options) {
    validateOptions(options);

    var locals = getLocals(options);

    options = _.extend({}, self.options, _.omit(options, 'locals'));
    options.locals = locals;

    return parser.parse(source, options);
  };

  this.compile = function (source, options) {
    var key = options ? options.filename : null,
      locals = getLocals(options),
      cached = key ? cacheGet(key) : null,
      tpl,
      code;

    if (cached) {
      return cached;
    }

    tpl = exports.parse(source, options);
    code = parser.compile(tpl);

    function compiled(context) {
      var tpl = new Function('_ctx', [
        'with (_ctx) {',
        '  var _output = "";',
        code,
        '  return _output;',
        '}'
      ].join('\n  '));

      return tpl(_.extend({}, locals, context || {}));
    }

    _.extend(compiled, tpl);

    if (key) {
      cacheSet(key, compiled);
    }

    return compiled;
  };

  this.compileFile = function (path, options) {
    var src = fs.readFileSync(path, 'utf8');
    return self.compile(src, options);
  };

  this.render = function (source, options) {
    var locals = getLocals(options);
    return exports.compile(source, options)(locals);
  };

  this.renderFile = function (path, options) {
    var src = fs.readFileSync(path, 'utf8');
    return self.render(src, options);
  };
};

defaultInstance = new exports.Swig();
exports.parse = defaultInstance.parse;
exports.compile = defaultInstance.compile;
exports.render = defaultInstance.render;
exports.invalidateCache = defaultInstance.invalidateCache;
<|endoftext|>


<commit_before>var FaceApp = function(desktop) {
  this.drawEye = function(eyeX, eyeY, radius) {
    var eyeDy = this.faceWindow.y + eyeY - desktop.workspace().cursorY;
    var eyeDx = this.faceWindow.x + eyeX - desktop.workspace().cursorX;
    var eyeAngle = Math.atan2(eyeDy, eyeDx);

    var eyePupilX = eyeX - Math.cos(eyeAngle) * radius / 2;
    var eyePupilY = eyeY - Math.sin(eyeAngle) * radius / 2;

    this.context.beginPath();
    this.context.arc(eyeX, eyeY, radius, 0, Math.PI * 2);
    this.context.closePath();
    this.context.stroke();
    this.context.beginPath();
    this.context.arc(eyePupilX, eyePupilY, radius / 2, 0, Math.PI * 2);
    this.context.closePath();
    this.context.fill();
  };

  this.desktop = desktop;
  this.faceWindow = desktop.createWindow(this, {
    width: 200,
    height: 200,
    title: ":)",
    resizeOpts: {
      square: true
    }
  });
  this.canvas = document.createElement("canvas");
  this.context = this.canvas.getContext("2d");

  this.canvas.width = 200;
  this.canvas.height = 200;

  this.faceWindow.body.appendChild(this.canvas);

  /* called every frame to try for 60 fps via requestAnimationFrame */
  this.on("tick", function() {
    this.faceWindow.setTitle(":)");
    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

    // draw the smile
    this.context.beginPath();
    if(this.faceWindow.resizing) {
      this.context.arc(this.canvas.width / 2, this.canvas.height / 2 + this.canvas.height / 3,
          this.canvas.width / 4,
          - Math.PI * 7/8, -Math.PI / 8);
    }
    else if(this.faceWindow.dragging) {
      this.context.arc(this.canvas.width / 2, this.canvas.height * 5/8,
          this.canvas.width / 8,
          0, Math.PI * 2);
    }
    else {
      this.context.arc(this.canvas.width / 2, this.canvas.height / 2,
          this.canvas.width / 4,
          Math.PI / 8, Math.PI * 7/8);
    }
    this.context.closePath();
    this.context.stroke();

    // draw the eyes
    var radius = this.canvas.height / 10;
    if(this.faceWindow.resizing) {
      this.faceWindow.setTitle(":(");
    }
    if(this.faceWindow.dragging) {
      this.faceWindow.setTitle(":O");
    }
    this.drawEye(this.canvas.width / 4, this.canvas.height / 4, radius);
    this.drawEye(this.canvas.width * 3/4, this.canvas.height / 4, radius);

  });
  /* interact.js resizemove event */
  this.faceWindow.resizeInteraction.on("resizemove", function(event) {
    this.canvas.width = this.faceWindow.body.clientWidth;
    this.canvas.height = this.faceWindow.body.clientWidth;
  }.bind(this));
};
FaceApp.shortname = "face";
FaceApp.fullname = "Expressive Face";
FaceApp.description = "A face that reacts to user actions";

module.exports = FaceApp;
<commit_msg>Switch to window events rather than interact event<commit_after>var FaceApp = function(desktop) {
  this.drawEye = function(eyeX, eyeY, radius) {
    var eyeDy = this.faceWindow.y + eyeY - desktop.workspace().cursorY;
    var eyeDx = this.faceWindow.x + eyeX - desktop.workspace().cursorX;
    var eyeAngle = Math.atan2(eyeDy, eyeDx);

    var eyePupilX = eyeX - Math.cos(eyeAngle) * radius / 2;
    var eyePupilY = eyeY - Math.sin(eyeAngle) * radius / 2;

    this.context.beginPath();
    this.context.arc(eyeX, eyeY, radius, 0, Math.PI * 2);
    this.context.closePath();
    this.context.stroke();
    this.context.beginPath();
    this.context.arc(eyePupilX, eyePupilY, radius / 2, 0, Math.PI * 2);
    this.context.closePath();
    this.context.fill();
  };

  this.desktop = desktop;
  this.faceWindow = desktop.createWindow(this, {
    width: 200,
    height: 200,
    title: ":)",
    resizeOpts: {
      square: true
    }
  });
  this.canvas = document.createElement("canvas");
  this.context = this.canvas.getContext("2d");

  this.canvas.width = 200;
  this.canvas.height = 200;

  this.faceWindow.body.appendChild(this.canvas);

  /* called every frame to try for 60 fps via requestAnimationFrame */
  this.on("tick", function() {
    this.faceWindow.setTitle(":)");
    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

    // draw the smile
    this.context.beginPath();
    if(this.faceWindow.resizing) {
      this.context.arc(this.canvas.width / 2, this.canvas.height / 2 + this.canvas.height / 3,
          this.canvas.width / 4,
          - Math.PI * 7/8, -Math.PI / 8);
    }
    else if(this.faceWindow.dragging) {
      this.context.arc(this.canvas.width / 2, this.canvas.height * 5/8,
          this.canvas.width / 8,
          0, Math.PI * 2);
    }
    else {
      this.context.arc(this.canvas.width / 2, this.canvas.height / 2,
          this.canvas.width / 4,
          Math.PI / 8, Math.PI * 7/8);
    }
    this.context.closePath();
    this.context.stroke();

    // draw the eyes
    var radius = this.canvas.height / 10;
    if(this.faceWindow.resizing) {
      this.faceWindow.setTitle(":(");
    }
    if(this.faceWindow.dragging) {
      this.faceWindow.setTitle(":O");
    }
    this.drawEye(this.canvas.width / 4, this.canvas.height / 4, radius);
    this.drawEye(this.canvas.width * 3/4, this.canvas.height / 4, radius);

  });
  /* interact.js resizemove event */
  this.faceWindow.on("resizemove", function(event) {
    this.canvas.width = this.faceWindow.body.clientWidth;
    this.canvas.height = this.faceWindow.body.clientWidth;
  }.bind(this));
};
FaceApp.shortname = "face";
FaceApp.fullname = "Expressive Face";
FaceApp.description = "A face that reacts to user actions";

module.exports = FaceApp;
<|endoftext|>


<commit_before>/*jshint expr:true*/
var chai = require('chai');
var assert = chai.assert;
var expect = chai.expect;

// var blanket = require("blanket")({
//     // options are passed as an argument object to the require statement
//    "pattern": "../lib/"
//  });

const config = require('../lib/config.js'),
  raccoon = require('../lib/raccoon.js');

describe('basic likes, dislikes, unlikes, and undislikes', function(){
  beforeEach(function(done){
    client.flushdbAsync().then(() => {
      return raccoon.liked('chris', 'batman');
    }).then(() => {
      return raccoon.liked('larry', 'batman');
    }).then(() => {
      return raccoon.disliked('greg', 'batman');
    }).then(() => {
      return raccoon.liked('mai', 'superman');
    }).then(() => {
      return raccoon.unliked('mai', 'superman');
    }).then(() => {
      return raccoon.disliked('jesse', 'superman');
    }).then(() => {
      return raccoon.undisliked('jesse', 'superman');
    }).then(() => {
      done();
    });
  });
  describe('basic like', function(){
    it('should validate a user has been added after a rating', function(done){
      client.smembersAsync('movie:user:chris:liked').then((results) => {
        assert.equal(results[0],'batman');
        done();
      });
    });
  });
  describe('basic dislike', function(){
    it('should validate a user has been added after a rating', function(done){
      client.smembersAsync('movie:user:greg:disliked').then((results) => {
        assert.equal(results[0],'batman');
        done();
      });
    });
  });
  describe('basic unlike', function(){
    it('should validate a user has been removed after an unlike', function(done){
      client.smembersAsync('movie:user:mai:liked').then((results) => {
        assert.equal(results[0],undefined);
        done();
      });
    });
  });
  describe('basic undislike', function(){
    it('should validate a user has been removed after an undislike', function(done){
      client.smembersAsync('movie:user:jesse:disliked').then((results) => {
        assert.equal(results[0],undefined);
        done();
      });
    });
  });
});

describe('callbacks', function(){
  it('should fire the input callback after a like is added', function(done){
    raccoon.liked('hao', 'superman').then(() => {
      done();
    });
  });
  it('should fire the input callback after a disliked is added', function(done){
    raccoon.liked('hao', 'superman').then(() => {
      done();
    });
  });
});

describe('accurate recommendations', function(){
  before(function(done){
    client.flushdbAsync().then(() => {
      return raccoon.liked('ChristianB', 'Typical');
    }).then(() => {
      return raccoon.liked('ChristianB', 'Value7');
    }).then(() => {
      return raccoon.liked('malbery', 'Typical');
    }).then(() => {
      return raccoon.liked('malbery', 'Value1');
    }).then(() => {
      return raccoon.liked('malbery', 'Value2');
    }).then(() => {
      return raccoon.liked('malbery', 'Value3');
    }).then(() => {
      return raccoon.liked('malbery', 'Value4');
    }).then(() => {
      return raccoon.liked('malbery', 'Value5');
    }).then(() => {
      return raccoon.liked('malbery', 'Value6');
    }).then(() => {
      return raccoon.liked('malbery', 'Value7');
    }).then(() => {
      done();
    });
  });
  it('should not have recommendations for malbery', function(done){
    raccoon.recommendFor('malbery', 5).then((recs) => {
      assert.equal(recs[0], undefined);
      done();
    });
  });
});

describe('recommendations', function(){
  before(function(done){
    client.flushdbAsync().then(() => {
      return raccoon.liked('chris', 'batman');
    }).then(() => {
      return raccoon.liked('chris', 'superman');
    }).then(() => {
      return raccoon.disliked('chris', 'chipmunks');
    }).then(() => {
      return raccoon.liked('max', 'batman');
    }).then(() => {
      return raccoon.disliked('max', 'chipmunks');
    }).then(() => {
      return raccoon.liked('greg', 'batman');
    }).then(() => {
      return raccoon.liked('greg', 'superman');
    }).then(() => {
      return raccoon.liked('larry', 'batman');
    }).then(() => {
      return raccoon.liked('larry', 'iceage');
    }).then(() => {
      return raccoon.disliked('tuhin', 'batman');
    }).then(() => {
      return raccoon.disliked('tuhin', 'superman');
    }).then(() => {
      return raccoon.disliked('tuhin', 'chipmunks');
    }).then(() => {
      return raccoon.disliked('kristina', 'batman');
    }).then(() => {
      return raccoon.disliked('kristina', 'superman');
    }).then(() => {
      return raccoon.disliked('andre', 'superman');
    }).then(() => {
      return raccoon.disliked('guy', 'superman', { updateRecs: false });
    }).then(() => {
      done();
    });
  });
  it('should recommend a movie if a similar user liked it', function(done){
    raccoon.recommendFor('andre', 5).then((recs) => {
      assert.equal(recs[0], 'batman');
      done();
    });
  });
  it('should not recommend a movie if updateRecs was false', function(done){
    raccoon.recommendFor('guy', 5).then((recs) => {
      assert.equal(recs[0], undefined);
      done();
    });
  });
  // it('should not recommend a movie that people opposite liked', function(done){
  //   raccoon.recommendFor('andre', 5, function(recs){
  //     assert.notEqualequal(recs[0], 'chipmunks');
  //     done();
  //   });
  // });
});

describe('stats1', function(){
  before(function(done){
    client.flushdbAsync().then(() => {
      return raccoon.liked('chris', 'batman');
    }).then(() => {
      return raccoon.liked('chris', 'superman');
    }).then(() => {
      return raccoon.disliked('chris', 'chipmunks');
    }).then(() => {
      return raccoon.liked('max', 'batman');
    }).then(() => {
      return raccoon.disliked('max', 'chipmunks');
    }).then(() => {
      return raccoon.liked('greg', 'batman');
    }).then(() => {
      return raccoon.liked('greg', 'superman');
    }).then(() => {
      return raccoon.liked('larry', 'batman');
    }).then(() => {
      return raccoon.liked('larry', 'iceage');
    }).then(() => {
      return raccoon.disliked('tuhin', 'batman');
    }).then(() => {
      return raccoon.disliked('tuhin', 'superman');
    }).then(() => {
      return raccoon.disliked('tuhin', 'chipmunks');
    }).then(() => {
      for (var i = 0; i < 25; i++){
        raccoon.liked('user'+i, 'batman');
      }
      done();
    });
  });
  it('should have batman as the bestRated even though iceage has only likes', function(done){
    raccoon.bestRated().then((bestRated) => {
      assert.equal(bestRated[0], 'batman');
      done();
    });
  });
  it('should have chipmunks as the worst rated', function(done){
    raccoon.worstRated().then((worstRated) => {
      assert.equal(worstRated[0], 'chipmunks');
      done();
    });
  });
  it('should have batman as the most liked and superman as second', function(done){
    raccoon.mostLiked().then((mostLiked) => {
      assert.equal(mostLiked[0], 'batman');
      assert.equal(mostLiked[1], 'superman');
      done();
    });
  });
  it('should have chipmunks as the most disliked', function(done){
    raccoon.mostDisliked().then((mostDisliked) => {
      assert.equal(mostDisliked[0], 'chipmunks');
      done();
    });
  });
  it('should have an accurate list of users who liked an item', function(done){
    raccoon.likedBy('superman').then((listOfUsers) => {
      assert.include(listOfUsers, 'chris');
      assert.include(listOfUsers, 'greg');
      done();
    });
  });
  it('should have an accurate number of users who liked an item', function(done){
    raccoon.likedCount('batman').then((numUsers) => {
      assert.equal(numUsers, 29);
      done();
    });
  });
  it('should have an accurate list of users who disliked an item', function(done){
    raccoon.dislikedBy('chipmunks').then((listOfUsers) => {
      expect(listOfUsers).to.include('chris');
      expect(listOfUsers).to.include('max');
      expect(listOfUsers).to.include('tuhin');
      done();
    });
  });
  it('should have an accurate number of users who disliked an item', function(done){
    raccoon.dislikedCount('superman').then((numUsers) => {
      assert.equal(numUsers, 1);
      done();
    });
  });
  it('should list all a users likes', function(done){
    raccoon.allLikedFor('greg').then((itemList) => {
      expect(itemList).to.include('batman');
      expect(itemList).to.include('superman');
      done();
    });
  });
  it('should list all a users dislikes', function(done){
    raccoon.allDislikedFor('tuhin').then((itemList) => {
      expect(itemList).to.include('batman');
      expect(itemList).to.include('superman');
      expect(itemList).to.include('chipmunks');
      done();
    });
  });
  it('should list all a users rated items', function(done){
    raccoon.allWatchedFor('max').then((itemList) => {
      expect(itemList).to.include('batman');
      expect(itemList).to.include('chipmunks');
      done();
    });
  });
  it('should not have similar users before updating', function(done){
    raccoon.mostSimilarUsers('chris').then((similarUsers) => {
      assert.equal(similarUsers[0], undefined);
      done();
    });
  });
  it('should not have dissimilar users before updating', function(done){
    raccoon.leastSimilarUsers('chris').then((leastSimilarUsers) => {
      assert.equal(leastSimilarUsers[0], undefined);
      done();
    });
  });
});

// describe('db connections', function(){
//   it('should connect to a remove db successfully', function(done){
//     client.flushdb();
//     client.end();
//     client.quit();
//     config.localSetup = false;
//     config.remoteRedisPort = 6379;
//     config.remoteRedisURL = '127.0.0.1';
//     config.remoteRedisAuth = 1111;
//     raccoon.liked('chris', 'batman', function(){
//       raccoon.allLikedFor('chris', function(itemList){
//         expect(itemList).to.include('batman');
//         client.flushdb();
//         client.end();
//         config.localSetup = true;
//         done();
//       });
//     });
//   });
// });
<commit_msg>Fixed test with similar users<commit_after>/*jshint expr:true*/
var chai = require('chai');
var assert = chai.assert;
var expect = chai.expect;

// var blanket = require("blanket")({
//     // options are passed as an argument object to the require statement
//    "pattern": "../lib/"
//  });

const config = require('../lib/config.js'),
  raccoon = require('../lib/raccoon.js');

describe('basic likes, dislikes, unlikes, and undislikes', function(){
  beforeEach(function(done){
    client.flushdbAsync().then(() => {
      return raccoon.liked('chris', 'batman');
    }).then(() => {
      return raccoon.liked('larry', 'batman');
    }).then(() => {
      return raccoon.disliked('greg', 'batman');
    }).then(() => {
      return raccoon.liked('mai', 'superman');
    }).then(() => {
      return raccoon.unliked('mai', 'superman');
    }).then(() => {
      return raccoon.disliked('jesse', 'superman');
    }).then(() => {
      return raccoon.undisliked('jesse', 'superman');
    }).then(() => {
      done();
    });
  });
  describe('basic like', function(){
    it('should validate a user has been added after a rating', function(done){
      client.smembersAsync('movie:user:chris:liked').then((results) => {
        assert.equal(results[0],'batman');
        done();
      });
    });
  });
  describe('basic dislike', function(){
    it('should validate a user has been added after a rating', function(done){
      client.smembersAsync('movie:user:greg:disliked').then((results) => {
        assert.equal(results[0],'batman');
        done();
      });
    });
  });
  describe('basic unlike', function(){
    it('should validate a user has been removed after an unlike', function(done){
      client.smembersAsync('movie:user:mai:liked').then((results) => {
        assert.equal(results[0],undefined);
        done();
      });
    });
  });
  describe('basic undislike', function(){
    it('should validate a user has been removed after an undislike', function(done){
      client.smembersAsync('movie:user:jesse:disliked').then((results) => {
        assert.equal(results[0],undefined);
        done();
      });
    });
  });
});

describe('callbacks', function(){
  it('should fire the input callback after a like is added', function(done){
    raccoon.liked('hao', 'superman').then(() => {
      done();
    });
  });
  it('should fire the input callback after a disliked is added', function(done){
    raccoon.liked('hao', 'superman').then(() => {
      done();
    });
  });
});

describe('accurate recommendations', function(){
  before(function(done){
    client.flushdbAsync().then(() => {
      return raccoon.liked('ChristianB', 'Typical');
    }).then(() => {
      return raccoon.liked('ChristianB', 'Value7');
    }).then(() => {
      return raccoon.liked('malbery', 'Typical');
    }).then(() => {
      return raccoon.liked('malbery', 'Value1');
    }).then(() => {
      return raccoon.liked('malbery', 'Value2');
    }).then(() => {
      return raccoon.liked('malbery', 'Value3');
    }).then(() => {
      return raccoon.liked('malbery', 'Value4');
    }).then(() => {
      return raccoon.liked('malbery', 'Value5');
    }).then(() => {
      return raccoon.liked('malbery', 'Value6');
    }).then(() => {
      return raccoon.liked('malbery', 'Value7');
    }).then(() => {
      done();
    });
  });
  it('should not have recommendations for malbery', function(done){
    raccoon.recommendFor('malbery', 5).then((recs) => {
      assert.equal(recs[0], undefined);
      done();
    });
  });
});

describe('recommendations', function(){
  before(function(done){
    client.flushdbAsync().then(() => {
      return raccoon.liked('chris', 'batman');
    }).then(() => {
      return raccoon.liked('chris', 'superman');
    }).then(() => {
      return raccoon.disliked('chris', 'chipmunks');
    }).then(() => {
      return raccoon.liked('max', 'batman');
    }).then(() => {
      return raccoon.disliked('max', 'chipmunks');
    }).then(() => {
      return raccoon.liked('greg', 'batman');
    }).then(() => {
      return raccoon.liked('greg', 'superman');
    }).then(() => {
      return raccoon.liked('larry', 'batman');
    }).then(() => {
      return raccoon.liked('larry', 'iceage');
    }).then(() => {
      return raccoon.disliked('tuhin', 'batman');
    }).then(() => {
      return raccoon.disliked('tuhin', 'superman');
    }).then(() => {
      return raccoon.disliked('tuhin', 'chipmunks');
    }).then(() => {
      return raccoon.disliked('kristina', 'batman');
    }).then(() => {
      return raccoon.disliked('kristina', 'superman');
    }).then(() => {
      return raccoon.disliked('andre', 'superman');
    }).then(() => {
      return raccoon.disliked('andre', 'chipmunks');
    }).then(() => {
      return raccoon.disliked('guy', 'superman', { updateRecs: false });
    }).then(() => {
      done();
    });
  });
  it('should recommend a movie if a similar user liked it', function(done){
    raccoon.recommendFor('andre', 5).then((recs) => {
      assert.equal(recs[0], 'batman');
      done();
    });
  });
  it('should not recommend a movie if updateRecs was false', function(done){
    raccoon.recommendFor('guy', 5).then((recs) => {
      assert.equal(recs[0], undefined);
      done();
    });
  });
  // it('should not recommend a movie that people opposite liked', function(done){
  //   raccoon.recommendFor('andre', 5, function(recs){
  //     assert.notEqualequal(recs[0], 'chipmunks');
  //     done();
  //   });
  // });
});

describe('stats1', function(){
  before(function(done){
    client.flushdbAsync().then(() => {
      return raccoon.liked('chris', 'batman');
    }).then(() => {
      return raccoon.liked('chris', 'superman');
    }).then(() => {
      return raccoon.disliked('chris', 'chipmunks');
    }).then(() => {
      return raccoon.liked('max', 'batman');
    }).then(() => {
      return raccoon.disliked('max', 'chipmunks');
    }).then(() => {
      return raccoon.liked('greg', 'batman');
    }).then(() => {
      return raccoon.liked('greg', 'superman');
    }).then(() => {
      return raccoon.liked('larry', 'batman');
    }).then(() => {
      return raccoon.liked('larry', 'iceage');
    }).then(() => {
      return raccoon.disliked('tuhin', 'batman');
    }).then(() => {
      return raccoon.disliked('tuhin', 'superman');
    }).then(() => {
      return raccoon.disliked('tuhin', 'chipmunks');
    }).then(() => {
      for (var i = 0; i < 25; i++){
        raccoon.liked('user'+i, 'batman');
      }
      done();
    });
  });
  it('should have batman as the bestRated even though iceage has only likes', function(done){
    raccoon.bestRated().then((bestRated) => {
      assert.equal(bestRated[0], 'batman');
      done();
    });
  });
  it('should have chipmunks as the worst rated', function(done){
    raccoon.worstRated().then((worstRated) => {
      assert.equal(worstRated[0], 'chipmunks');
      done();
    });
  });
  it('should have batman as the most liked and superman as second', function(done){
    raccoon.mostLiked().then((mostLiked) => {
      assert.equal(mostLiked[0], 'batman');
      assert.equal(mostLiked[1], 'superman');
      done();
    });
  });
  it('should have chipmunks as the most disliked', function(done){
    raccoon.mostDisliked().then((mostDisliked) => {
      assert.equal(mostDisliked[0], 'chipmunks');
      done();
    });
  });
  it('should have an accurate list of users who liked an item', function(done){
    raccoon.likedBy('superman').then((listOfUsers) => {
      assert.include(listOfUsers, 'chris');
      assert.include(listOfUsers, 'greg');
      done();
    });
  });
  it('should have an accurate number of users who liked an item', function(done){
    raccoon.likedCount('batman').then((numUsers) => {
      assert.equal(numUsers, 29);
      done();
    });
  });
  it('should have an accurate list of users who disliked an item', function(done){
    raccoon.dislikedBy('chipmunks').then((listOfUsers) => {
      expect(listOfUsers).to.include('chris');
      expect(listOfUsers).to.include('max');
      expect(listOfUsers).to.include('tuhin');
      done();
    });
  });
  it('should have an accurate number of users who disliked an item', function(done){
    raccoon.dislikedCount('superman').then((numUsers) => {
      assert.equal(numUsers, 1);
      done();
    });
  });
  it('should list all a users likes', function(done){
    raccoon.allLikedFor('greg').then((itemList) => {
      expect(itemList).to.include('batman');
      expect(itemList).to.include('superman');
      done();
    });
  });
  it('should list all a users dislikes', function(done){
    raccoon.allDislikedFor('tuhin').then((itemList) => {
      expect(itemList).to.include('batman');
      expect(itemList).to.include('superman');
      expect(itemList).to.include('chipmunks');
      done();
    });
  });
  it('should list all a users rated items', function(done){
    raccoon.allWatchedFor('max').then((itemList) => {
      expect(itemList).to.include('batman');
      expect(itemList).to.include('chipmunks');
      done();
    });
  });
  it('should not have similar users before updating', function(done){
    raccoon.mostSimilarUsers('chris').then((similarUsers) => {
      assert.equal(similarUsers[0], undefined);
      done();
    });
  });
  it('should not have dissimilar users before updating', function(done){
    raccoon.leastSimilarUsers('chris').then((leastSimilarUsers) => {
      assert.equal(leastSimilarUsers[0], undefined);
      done();
    });
  });
});

// describe('db connections', function(){
//   it('should connect to a remove db successfully', function(done){
//     client.flushdb();
//     client.end();
//     client.quit();
//     config.localSetup = false;
//     config.remoteRedisPort = 6379;
//     config.remoteRedisURL = '127.0.0.1';
//     config.remoteRedisAuth = 1111;
//     raccoon.liked('chris', 'batman', function(){
//       raccoon.allLikedFor('chris', function(itemList){
//         expect(itemList).to.include('batman');
//         client.flushdb();
//         client.end();
//         config.localSetup = true;
//         done();
//       });
//     });
//   });
// });
<|endoftext|>


<commit_before>/* jshint node:true, strict:false */
var request = require('request'),
      couch = require('config').couch,
    gameUrl = require('config').gameUrl,
     tokens = require('config').tokens;

module.exports = function (app) {
  app.post('/uploadMap/:token', saveMap);
  app.get('/map/:id', getMap);
};

var couchUrl = 'http://' + couch.host + ':' + couch.port + '/' + couch.db.maps;

// -+-+ Public Functions +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

function saveMap(req, res) {
  var token = req.params.token;

  if (!tokens[token]) {
    res.send({
      success: false,
      err: 'Invalid Token!!'
    });
    return;
  }

  var map = req.body.map;

  var err = validate(map);

  if (err) {
    res.send({
      success: false,
      data: JSON.stringify(req.body),
      err: err
    });
    return;
  }

  var report = genReport(map);

  if (report) {
    report = '
' + report + '
';
  }
  else {
    report = '
Congrats. Your map JSON is valid
';
  }

  map.created = new Date();
  map.group = tokens[token];

  saveMapToCouch(map, function (err, id) {
    if (err) {
      console.error(err);
      res.send({
        success: false,
        info: 'This was probably a CouchDB error. Tell the TA (dosmun@aggiemail.usu.edu)',
        err: err
      });
      return;
    }

    res.send({
      success: true,
      report: report,
      url: gameUrl + '?id=' + id
    });
  });
}

function getMap(req, res) {
  var id = req.params.id;

  getMapFromCouch(id, function (err, map) {
    if (err) {
      console.error(err);
      res.send({
        success: false,
        err: err
      });
      return;
    }

    map.last_played = new Date();
    map.play_count = map.play_count || 0;
    map.play_count++;

    updateMapInCouch(map);

    delete map._rev;

    res.send({
      success: true,
      map: map
    });
  });
}

// -+-+ Private Functions +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

function validate(map) {
  if (!map) {
    return 'You didn\'t post in the format: { map: YOURMAP }.';
  }

  if (!map.data) {
    return 'Your map didn\'t contain a data property.';
  }

  if (typeof map.data !== 'object') {
    return 'map.data should be an object.';
  }

  if (!map.data.bottom) {
    return 'Your map\'s data didn\'t contain a bottom property.';
  }

  // verify the contents of map.data.bottom

  return false;
}

function genReport(map) {
  var report = '';

  if (!map.title) {
    report += '
Your map doesn\'t have a title. Might be nice if you need to display stuff to a user.
';
  }
  else if (typeof map.title !== 'string') {
    report += '
map.title should be a string.
';
  }

  if (!map.author) {
    report += '
Your map doesn\'t have a author. Might be nice if you need to display stuff to a user.
';
  }
  else if (typeof map.author !== 'string') {
    report += '
map.author should be a string.
';
  }

  if (!map.width) {
    report += '
Your Map doesn\'t have a width. Not really important in Javascript, but it helps in other inferior languages ;).
';
  }
  else if (typeof map.width !== 'number') {
    report += '
map.width should be a number.
';
  }

  if (!map.height) {
    report += '
Your Map doesn\'t have a height. Not really important in Javascript, but it helps in other inferior languages ;).
';
  }
  else if (typeof map.height !== 'number') {
    report += '
map.height should be a number.
';
  }

  if (!map.env) {
    report += '
Your Map doesn\'t have an env. Assuming Normal.
';
  }
  else if (typeof map.env !== 'string') {
    report += '
map.env should be a string.
';
  }

  if (!map.events) {
    report += '
Your Map doesn\'t have an events array. None will be loaded.
';
  }

  // verify the inside of events

  // verify data.middle and data.top too

  return report;
}

function saveMapToCouch(map, cb) {
  request.post({
    url: couchUrl,
    json: map
  }, function (err, resp, body) {
    if (err) {
      return cb(err);
    }
    if (!body) {
      return cb('body not found');
    }
    if (!body.ok) {
      return cb(body);
    }

    cb(null, body.id);
  });
}

function getMapFromCouch(id, cb) {
  request.get(couchUrl + '/' + id, function (err, resp, body) {
    if (err) {
      return cb(err);
    }
    if (!body) {
      return cb('body not found');
    }

    body = JSON.parse(body);

    if (body.error) {
      return cb(body);
    }

    cb(null, body);
  });
}

function updateMapInCouch(map) {
  request.put({
    url: couchUrl + '/' + map._id,
    json: map
  }, function (err, resp, body) {
    console.error(err);
    console.log(body);
  });
}
<commit_msg>added verification for map.data.bottom<commit_after>/* jshint node:true, strict:false */
var request = require('request'),
      couch = require('config').couch,
    gameUrl = require('config').gameUrl,
     tokens = require('config').tokens,
          _ = require('underscore');

module.exports = function (app) {
  app.post('/uploadMap/:token', saveMap);
  app.get('/map/:id', getMap);
};

var couchUrl = 'http://' + couch.host + ':' + couch.port + '/' + couch.db.maps;

// -+-+ Public Functions +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

function saveMap(req, res) {
  var token = req.params.token;

  if (!tokens[token]) {
    res.send({
      success: false,
      err: 'Invalid Token!!'
    });
    return;
  }

  var map = req.body.map;

  var err = validate(map);

  if (err) {
    res.send({
      success: false,
      data: JSON.stringify(req.body),
      err: err
    });
    return;
  }

  var report = genReport(map);

  if (report) {
    report = '
' + report + '
';
  }
  else {
    report = '
Congrats. Your map JSON is valid
';
  }

  map.created = new Date();
  map.group = tokens[token];
  map.debug = report;

  saveMapToCouch(map, function (err, id) {
    if (err) {
      console.error(err);
      res.send({
        success: false,
        info: 'This was probably a CouchDB error. Tell the TA (dosmun@aggiemail.usu.edu)',
        err: err
      });
      return;
    }

    res.send({
      success: true,
      report: report,
      url: gameUrl + '?id=' + id
    });
  });
}

function getMap(req, res) {
  var id = req.params.id;

  getMapFromCouch(id, function (err, map) {
    if (err) {
      console.error(err);
      res.send({
        success: false,
        err: err
      });
      return;
    }

    map.last_played = new Date();
    map.play_count = map.play_count || 0;
    map.play_count++;

    updateMapInCouch(map);

    delete map._rev;

    res.send({
      success: true,
      map: map
    });
  });
}

// -+-+ Private Functions +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

function validate(map) {
  if (!map) {
    return 'You didn\'t post in the format: { map: YOURMAP }.';
  }

  if (!map.data) {
    return 'Your map didn\'t contain a data property.';
  }

  if (!_.isObject(map.data)) {
    return 'map.data should be an object.';
  }

  if (!map.data.bottom) {
    return 'Your map\'s data didn\'t contain a bottom property.';
  }

  if (!_.isArray(map.data.bottom)) {
    return 'map.data.bottom should be an array.';
  }

  if (!map.data.bottom.length) {
    return 'map.data.bottom should have something in it.';
  }

  if (!_.isArray(map.data.bottom[0])) {
    return 'map.data.bottom[0] should be an array at the very least.';
  }

  var err = false;
  _.each(map.data.bottom, function (row, i) {
    if (err) return;

    if (!_.isArray(row)) {
      err = 'map.data.bottom[' + i + '] should be an array';
      return;
    }

    _.each(row, function (cell, j) {
      if (err) return;
      if (cell && !_.isNumber(cell)) {
        err = 'map.data.bottom[' + i + '][' + j + '] should be a number or null.';
        return;
      }
    });
  });

  return err;
}

function genReport(map) {
  var report = '';

  if (!map.title) {
    report += '
Your map doesn\'t have a title. Might be nice if you need to display stuff to a user.
';
  }
  else if (!_.isString(map.title)) {
    report += '
map.title should be a string.
';
  }

  if (!map.author) {
    report += '
Your map doesn\'t have a author. Might be nice if you need to display stuff to a user.
';
  }
  else if (!_.isString(map.author)) {
    report += '
map.author should be a string.
';
  }

  if (!map.width) {
    report += '
Your Map doesn\'t have a width. Not really important in Javascript, but it helps in other inferior languages ;).
';
  }
  else if (!_.isNumber(map.width)) {
    report += '
map.width should be a number.
';
  }

  if (!map.height) {
    report += '
Your Map doesn\'t have a height. Not really important in Javascript, but it helps in other inferior languages ;).
';
  }
  else if (!_.isNumber(map.height)) {
    report += '
map.height should be a number.
';
  }

  if (!map.x) {
    report += '
Your Map doesn\'t have an x property. Player will start at column 0.
';
  }
  else if (!_.isNumber(map.x)) {
    report += '
map.x should be a number.
';
  }

  if (!map.y) {
    report += '
Your Map doesn\'t have a y property. Player will start at row 0.
';
  }
  else if (!_.isNumber(map.y)) {
    report += '
map.y should be a number.
';
  }

  if (!map.env) {
    report += '
Your Map doesn\'t have an env. Assuming Normal.
';
  }
  else if (!_.isString(map.env)) {
    report += '
map.env should be a string.
';
  }

  if (!map.events) {
    report += '
Your Map doesn\'t have an events array. None will be loaded.
';
  }
  else {
    // verify the inside of events
  }

  // verify data.middle and data.top too

  return report;
}

function saveMapToCouch(map, cb) {
  request.post({
    url: couchUrl,
    json: map
  }, function (err, resp, body) {
    if (err) {
      return cb(err);
    }
    if (!body) {
      return cb('body not found');
    }
    if (!body.ok) {
      return cb(body);
    }

    cb(null, body.id);
  });
}

function getMapFromCouch(id, cb) {
  request.get(couchUrl + '/' + id, function (err, resp, body) {
    if (err) {
      return cb(err);
    }
    if (!body) {
      return cb('body not found');
    }

    body = JSON.parse(body);

    if (body.error) {
      return cb(body);
    }

    cb(null, body);
  });
}

function updateMapInCouch(map) {
  request.put({
    url: couchUrl + '/' + map._id,
    json: map
  }, function (err, resp, body) {
    console.error(err);
    console.log(body);
  });
}
<|endoftext|>


<commit_before>/*
 * https://github.com/mattma/ember-rocks
 *
 * Copyright (c) 2014 Matt Ma
 * Licensed under the MIT license.
 */

'use strict';

var program = require('commander'),
    create = require('./create'),
    generate = require('./generate'),
    commands = require('./commands'),
    pkg = require('../../package.json');

program
  .version('em-cli ' + pkg.version)
  .usage('[command] [options]\n\n  Command-Specific Help\n\n    em [command] --help');

program
  .command('new')
  .option(
      '-p, --path [path]',
      '# the generator url on web (ex: github.com/mattma/ember-generator)'
  )
  .option(
      '-T, --test',
      '# running in test mode. It won\'s fetch npm or bower packages or init the git repo'
  )
  .description('Creates a new ember application at [dirName]')
  .usage(
      '[ dirName ]  # Make a new directory and Scaffold a new web application' +
      '\n  Ex:    em new my-app'
  )
  .action(create);

program
  .command('g')
  .alias('generate')
  .description('Generate a new file with ES6 support in the ember app')
  .usage('[type:[name | /nested/folder/to/name]]' +
      '\n\n  @description Generate a new file located app/[type]/[name].js' +
      '\n\n  @arg type: ' +
      '\n\n     adapter        ex: em g adapter(s):post' +
      '\n                    Generated: app/adapters/post.js'+
      '\n\n     component      ex: em g component(s):my-post' +
      '\n                    Generated: app/components/my-post.js'+
      '\n                    Generated: app/templates/components/my-post.hbs'+
      '\n\n     controller     ex: em g controller(s):blog/post' +
      '\n                    Generated: app/controllers/blog/post.js'+
      '\n\n     helper         ex: em g helper(s):post' +
      '\n                    Generated: app/helpers/post.js'+
      '\n\n     initializer    ex: em g initializer(s):post' +
      '\n                    Generated: app/initializers/post.js'+
      '\n\n     mixin          ex: em g mixin(s):post' +
      '\n                    Generated: app/mixins/post.js'+
      '\n\n     model          ex: em g model(s):post' +
      '\n                    Generated: app/models/post.js'+
      '\n\n     route          ex: em g route(s):post' +
      '\n                    Generated: app/routes/post.js'+
      '\n                    Generated: app/templates/post.hbs'+
      '\n\n     serializer     ex: em g serializer(s):post' +
      '\n                    Generated: app/serializers/post.js'+
      '\n\n     template       ex: em g template(s):post' +
      '\n                    Generated: app/templates/post.hbs'+
      '\n\n     transform      ex: em g transform(s):post' +
      '\n                    Generated: app/transforms/post.js'+
      '\n\n     util           ex: em g util(s):post' +
      '\n                    Generated: app/utils/post.js'+
      '\n\n     view           ex: em g view(s):long/folder/name/post' +
      '\n                    Generated: app/views/long/folder/name/post.js'+

      '\n\n  @arg name: any valid string' +
      ' \n             or use \'/\'separated string to create a nested folder structure' +
      '\n             See @arg type (above): controller and view sections for details')
  .action(generate);

program
  .command('s')
  .alias('serve')
  .description('Builds and serves your app, rebuilding on file changes.')
  .action(commands);

program
  .command('m')
  .alias('mobile')
  .description('Builds an Cordova application, and ready to deploy to phone or tablet.')
  .action(commands);

program
  .command('b')
  .alias('build')
  .description('Release your app and places it into the output path \'~/build\'')
  .action(commands);

// must be before .parse() since node's emit() is immediate
program.on('--help', function(){
  console.log('  Examples:');
  console.log('');
  console.log('    $ em new [dirName]' +
    '\n\n      @description Scaffold a node.js server-side app and an Ember.js client-side app' +
    '\n\n      @example  em new my-app && cd my-app');
  console.log('');
  console.log('    $ em new [dirName] -p git_public_url' +
    '\n\n      @description Do same things above and fetch an Ember app boilerplate ' +
                  'from custom git repo' +
    '\n\n      @example  em new my-app --path github.com/mattma/Ember-Rocks-Template-Basic');
  console.log('');
  console.log('    $ em generate [type:[name | /nested/folder/to/name]]' +
    '\n\n      @description Generate a new file ember app folder' +
    '\n\n      @info \'em generate --help\' for addtional helper information ' +
    '\n\n      @example  em generate route(s):posts/post' +
    '\n      @example  em generate component(s)/x-foo'
    );
  console.log('');
  console.log('    $ em serve' );
  console.log('');
  console.log('    $ em build' );
  console.log('');
  console.log('    $ em mobile' +
    '\n\n      @description Builds an Cordova application, and ready to' +
    ' deploy to phone or tablet.');
});

program.parse(process.argv);
<commit_msg>add em mobile helper message with same description<commit_after>/*
 * https://github.com/mattma/ember-rocks
 *
 * Copyright (c) 2014 Matt Ma
 * Licensed under the MIT license.
 */

'use strict';

var program = require('commander'),
    create = require('./create'),
    generate = require('./generate'),
    commands = require('./commands'),
    pkg = require('../../package.json');

program
  .version('em-cli ' + pkg.version)
  .usage('[command] [options]\n\n  Command-Specific Help\n\n    em [command] --help');

program
  .command('new')
  .option(
      '-p, --path [path]',
      '# the generator url on web (ex: github.com/mattma/ember-generator)'
  )
  .option(
      '-T, --test',
      '# running in test mode. It won\'s fetch npm or bower packages or init the git repo'
  )
  .description('Creates a new ember application at [dirName]')
  .usage(
      '[ dirName ]  # Make a new directory and Scaffold a new web application' +
      '\n  Ex:    em new my-app'
  )
  .action(create);

program
  .command('g')
  .alias('generate')
  .description('Generate a new file with ES6 support in the ember app')
  .usage('[type:[name | /nested/folder/to/name]]' +
      '\n\n  @description Generate a new file located app/[type]/[name].js' +
      '\n\n  @arg type: ' +
      '\n\n     adapter        ex: em g adapter(s):post' +
      '\n                    Generated: app/adapters/post.js'+
      '\n\n     component      ex: em g component(s):my-post' +
      '\n                    Generated: app/components/my-post.js'+
      '\n                    Generated: app/templates/components/my-post.hbs'+
      '\n\n     controller     ex: em g controller(s):blog/post' +
      '\n                    Generated: app/controllers/blog/post.js'+
      '\n\n     helper         ex: em g helper(s):post' +
      '\n                    Generated: app/helpers/post.js'+
      '\n\n     initializer    ex: em g initializer(s):post' +
      '\n                    Generated: app/initializers/post.js'+
      '\n\n     mixin          ex: em g mixin(s):post' +
      '\n                    Generated: app/mixins/post.js'+
      '\n\n     model          ex: em g model(s):post' +
      '\n                    Generated: app/models/post.js'+
      '\n\n     route          ex: em g route(s):post' +
      '\n                    Generated: app/routes/post.js'+
      '\n                    Generated: app/templates/post.hbs'+
      '\n\n     serializer     ex: em g serializer(s):post' +
      '\n                    Generated: app/serializers/post.js'+
      '\n\n     template       ex: em g template(s):post' +
      '\n                    Generated: app/templates/post.hbs'+
      '\n\n     transform      ex: em g transform(s):post' +
      '\n                    Generated: app/transforms/post.js'+
      '\n\n     util           ex: em g util(s):post' +
      '\n                    Generated: app/utils/post.js'+
      '\n\n     view           ex: em g view(s):long/folder/name/post' +
      '\n                    Generated: app/views/long/folder/name/post.js'+

      '\n\n  @arg name: any valid string' +
      ' \n             or use \'/\'separated string to create a nested folder structure' +
      '\n             See @arg type (above): controller and view sections for details')
  .action(generate);

program
  .command('s')
  .alias('serve')
  .description('Builds and serves your app, rebuilding on file changes.')
  .action(commands);

program
  .command('m')
  .alias('mobile')
  .description('Builds an Cordova application, and ready to deploy to phone or tablet.')
  .action(commands);

program
  .command('b')
  .alias('build')
  .description('Release your app and places it into the output path \'~/build\'')
  .action(commands);

// must be before .parse() since node's emit() is immediate
program.on('--help', function(){
  console.log('  Examples:');
  console.log('');
  console.log('    $ em new [dirName]' +
    '\n\n      @description Scaffold a node.js server-side app and an Ember.js client-side app' +
    '\n\n      @example  em new my-app && cd my-app');
  console.log('');
  console.log('    $ em new [dirName] -p git_public_url' +
    '\n\n      @description Do same things above and fetch an Ember app boilerplate ' +
                  'from custom git repo' +
    '\n\n      @example  em new my-app --path github.com/mattma/Ember-Rocks-Template-Basic');
  console.log('');
  console.log('    $ em generate [type:[name | /nested/folder/to/name]]' +
    '\n\n      @description Generate a new file ember app folder' +
    '\n\n      @info \'em generate --help\' for addtional helper information ' +
    '\n\n      @example  em generate route(s):posts/post' +
    '\n      @example  em generate component(s)/x-foo'
    );
  console.log('');
  console.log('    $ em serve' );
  console.log('');
  console.log('    $ em build' );
  console.log('');
  console.log('    $ em mobile' +
    '\n\n      @description Builds an Cordova application, and ready to' +
    ' deploy to phone or tablet.');
  console.log('');
  console.log('');
});

program.parse(process.argv);
<|endoftext|>


<commit_before><commit_msg>Admin utils: isAuthenticated<commit_after>module.exports.isAuthenticated = function isAuthenticated (req, res, next) {
  // If not logged user, ask for login.
  if (!req.user) {
    return res.redirect('/admin/login')
  }

  // User is logged In
  return next()
}
<|endoftext|>


<commit_before>var intervalId = {};
var numPlayers = 0;
var players = [];
exports.actions = function(req, res, ss) {

	// Russ, it's all hooked up. Access the db via ss.db
	// console.log(ss.db);

	return {
		// on: function() {
		// 	intervalId = setInterval(function() {
		// 			var message = 'Message from player';
		// 			ss.publish.all('ss-multi', message);
		// 	}, 3000);
		// 	setTimeout(function() {
		// 		res("Receiving SpaceMail");
		// 	}, 2000);
		// },
		// off: function(reason) {
		// 	console.log("Received reason: %s", reason);
		// 	clearInterval(intervalId);
		// 	setTimeout(function() {
		// 		ss.publish.all('ss-multi', reason);
		// 		res("Ignoring SpaceMail");
		// 	}, 2000);
		// },
		checkIn: function() {
			numPlayers++;
			ss.publish.all('ss-count',numPlayers);
			res(numPlayers);
		},
		addMe: function(player) {
			players.push(player);
			ss.publish.all('ss-allPlayers',players);
		},
		playerMoved: function(player){
			console.log(player);
			for(var p=0; p<players.length;p++){
				//console.log("in array: "+p.id);
				console.log(players[p]);

				//ridic stupid way to check if it's the right one (id isn't working)
				if(players[p].r ==player.r && players[p].g ==player.g){
					players[p].x = player.x;
					players[p].y = player.y;
					continue;
				}
			}
			ss.publish.all('ss-allPlayers',players);
		}

	};
}<commit_msg>small changes<commit_after>var intervalId = {};
var numPlayers = 0;
var players = [];
exports.actions = function(req, res, ss) {

	// Russ, it's all hooked up. Access the db via ss.db
	//console.log(ss.db);
	return {
		// on: function() {
		// 	intervalId = setInterval(function() {
		// 			var message = 'Message from player';
		// 			ss.publish.all('ss-multi', message);
		// 	}, 3000);
		// 	setTimeout(function() {
		// 		res("Receiving SpaceMail");
		// 	}, 2000);
		// },
		// off: function(reason) {
		// 	console.log("Received reason: %s", reason);
		// 	clearInterval(intervalId);
		// 	setTimeout(function() {
		// 		ss.publish.all('ss-multi', reason);
		// 		res("Ignoring SpaceMail");
		// 	}, 2000);
		// },
		checkIn: function() {
			numPlayers++;
			ss.publish.all('ss-count',numPlayers);
			res(numPlayers);
		},
		addMe: function(player) {
			players.push(player);
			ss.publish.all('ss-allPlayers',players);
		},
		playerMoved: function(player){
			console.log(player);
			for(var p=0; p<players.length;p++){
				//console.log("in array: "+p.id);
				console.log(players[p]);

				//ridic stupid way to check if it's the right one (id isn't working)
				if(players[p].r ==player.r && players[p].g ==player.g){
					players[p].x = player.x;
					players[p].y = player.y;
					continue;
				}
			}
			ss.publish.all('ss-allPlayers',players);
		}

	};
}<|endoftext|>


<commit_before>class Vector2 {
  constructor (x,y) {
    this.x = x;
    this.y = y;
  }
  magnitude () {
    return Math.sqrt(Vector2.dot(this, this));
  }
  normalize () {
    var m = 1/this.magnitude();
    if(m == Infinity) {
      m = 0;
    }
    this.x = this.x * m;
    this.y = this.y * m;
  }
  multiply(scaler) {
    this.x = this.x * scaler;
    this.y = this.y * scaler;
  }
  add (v) {
    this.x = this.x + v.x;
    this.y = this.y + v.y;
  }
  subract(v) {
    var n = new Vector2(v.x, v.y);
        n.negate();
    this.add(m);
  }
  divide(scaler) {
    this.x = this.x / scaler;
    this.y = this.y / scaler;
  }
  negate() {
    this.x = -this.x;
    this.y = -this.y;
  }
  clamp (limit) {
    if (this.x > limit) {
      this.x = limit;
    }
    if (this.y > limit) {
      this.y = limit;
    }
  }
  static lerp (a, b, t) {
    var x = a.x + t * (b.x - a.x);
    var y = a.y + t * (b.y - a.y);
    return new Vector2(x,y);
  }
  static normalize (a) {
    var m = 1/a.magnitude();
    if(m == Infinity) {
      m = 0;
    }
    return new Vector2(a.x * m, a.y * m);
  }
  increase(amount) {
    this.x = this.x + amount;
    this.y = this.y + amount;
  }
    decrease(amount) {
    this.x = this.x - amount;
    this.y = this.y -amount;
  }
  static add (a, b) {
    return new Vector2((a.x + b.x),(a.y + b.y));
  }
  static subtract (a, b) {
    var n = new Vector2(b.x, b.y);
        n.negate();
    return Vector2.add(a, n);
  }
  static multiply (a, scaler) {
    return new Vector2((a.x * scaler),(a.y * scaler));
  }
  static divide (a, scaler) {
    return new Vector2((a.x / scaler),(a.y / scaler));
  }
  static dot (a, b) {
     return a.x * b.x + a.y * b.y;
  }
  static dist (a, b) {
    var vec1 = a.x - b.x;
    var vec2 = a.y - b.y;
    return Math.sqrt((vec1 * vec1)+(vec2 * vec2));
  }
  get () {
    return new Vector2(this.x, this.y);
  }
  set (x,y) {
    this.x = x;
    this.y = y;
  }
}

class Mover {
  constructor(x,y) {
      this.location = new Vector2(x,y);
      this.acceleration = new Vector2(0,0);
      this.velocity = new Vector2(0,0);
      this.mass = 5;
  }
  applyForce(force) {
    var f = force.get();
        f.divide(this.mass);
    this.acceleration.add(f);
  }
  update () {
    this.velocity.add(this.acceleration);
    this.location.add(this.velocity);
    this.acceleration.set(0,0);
  }
}

class Attractor {
  constructor(x,y) {
    this.mass = 100;
    this.location = new Vector2(x,y);
  }
  attract(m) {
    // not implemented
  }
}<commit_msg>Added vector rotate function<commit_after>class Vector2 {
  constructor (x,y) {
    this.x = x;
    this.y = y;
  }
  magnitude () {
    return Math.sqrt(Vector2.dot(this, this));
  }
  normalize () {
    var m = 1/this.magnitude();
    if(m == Infinity) {
      m = 0;
    }
    this.x = this.x * m;
    this.y = this.y * m;
  }
  multiply(scaler) {
    this.x = this.x * scaler;
    this.y = this.y * scaler;
  }
  add (v) {
    this.x = this.x + v.x;
    this.y = this.y + v.y;
  }
  subract(v) {
    var n = new Vector2(v.x, v.y);
        n.negate();
    this.add(m);
  }
  divide(scaler) {
    this.x = this.x / scaler;
    this.y = this.y / scaler;
  }
  negate() {
    this.x = -this.x;
    this.y = -this.y;
  }
  clamp (limit) {
    if (this.x > limit) {
      this.x = limit;
    }
    if (this.y > limit) {
      this.y = limit;
    }
  }
  rotate (amount) {
        var ca = Math.cos(radians);
        var sa = Math.sin(radians);
        return new Vector(ca*this.x - sa*this.y, sa*this.x + ca*this.y);
  }
  static lerp (a, b, t) {
    var x = a.x + t * (b.x - a.x);
    var y = a.y + t * (b.y - a.y);
    return new Vector2(x,y);
  }
  static normalize (a) {
    var m = 1/a.magnitude();
    if(m == Infinity) {
      m = 0;
    }
    return new Vector2(a.x * m, a.y * m);
  }
  increase(amount) {
    this.x = this.x + amount;
    this.y = this.y + amount;
  }
    decrease(amount) {
    this.x = this.x - amount;
    this.y = this.y -amount;
  }
  static add (a, b) {
    return new Vector2((a.x + b.x),(a.y + b.y));
  }
  static subtract (a, b) {
    var n = new Vector2(b.x, b.y);
        n.negate();
    return Vector2.add(a, n);
  }
  static multiply (a, scaler) {
    return new Vector2((a.x * scaler),(a.y * scaler));
  }
  static divide (a, scaler) {
    return new Vector2((a.x / scaler),(a.y / scaler));
  }
  static dot (a, b) {
     return a.x * b.x + a.y * b.y;
  }
  static dist (a, b) {
    var vec1 = a.x - b.x;
    var vec2 = a.y - b.y;
    return Math.sqrt((vec1 * vec1)+(vec2 * vec2));
  }
  get () {
    return new Vector2(this.x, this.y);
  }
  set (x,y) {
    this.x = x;
    this.y = y;
  }
}

class Mover {
  constructor(x,y) {
      this.location = new Vector2(x,y);
      this.acceleration = new Vector2(0,0);
      this.velocity = new Vector2(0,0);
      this.mass = 5;
  }
  applyForce(force) {
    var f = force.get();
        f.divide(this.mass);
    this.acceleration.add(f);
  }
  update () {
    this.velocity.add(this.acceleration);
    this.location.add(this.velocity);
    this.acceleration.set(0,0);
  }
}

class Attractor {
  constructor(x,y) {
    this.mass = 100;
    this.location = new Vector2(x,y);
  }
  attract(m) {
    // not implemented
  }
}<|endoftext|>


<commit_before>var Struct = require("new-struct");
var vinyl = require('vinyl-fs');
var eos = require('end-of-stream');
var pump = require('pump');
var debug = require("local-debug")('task');
var format = require("format-text");
var rightpad = require("right-pad");
var style = require("style-format");
var through = require("through");
var chokidar = require('chokidar');
var Options = require("./options");
var map = require("./map");
var run = require("./run");
var exec = require("./exec");
var globby = require('globby');

var Task = Struct({
  New: New,
  done: done,
  run: run,
  watch: watch,
  files: globglob,
  exec: exec,
  src: src,
  dest: dest,
  end: end
});

var colors = [
  'red',
  'green',
  'cyan',
  'magenta'
];

module.exports = Task;

function New (name, options, fn) {
  if (arguments.length === 2 && typeof options === 'function') {
    fn = options;
    options = Options.New();
  }

  debug('Created new task "%s"%s', name, options && options._watch ? (' watching ' + options._watch.join(',')) : '');

  var task = map.set(name, Task({
    name: name,
    key: map.slug(name),
    options: options,
    path: options._path,
    watching: options._watch,
    files: globglob,
    src: src,
    dest: dest,
    fn: fn,
    pump: pump,
    done: done,
    color: nextColor(),
    processes: [],
    params: {},
    info: info,
    end: end
  }));

  stdout();
  stderr();

  return task;

  function stdout () {
    if (task.stdout) {
      task.stdout.destroy();
    }

    task.stdout = std(task, stdout);
    task.stdout.pipe(process.stdout).setMaxListeners(0);
  }

  function stderr () {
    if (task.stderr) {
      task.stderr.destroy();
    }

    task.stderr = std(task, stderr);
    task.stderr.pipe(process.stderr).setMaxListeners(0);
  }
}

function std (task, callback) {
  return through(function (line) {
    this.queue(beautify(task, line));
  }, callback);
}

function done (task) {
  var diff = Date.now() - task.startTS;

  task.info(task, 'Completed in {0}', humanize(diff));

  task.onDone.publish();
  delete task.onDone;
  delete task.startTS;
}

function humanize (ms) {
  var sec = 1000;
  var min = 60 * 1000;
  var hour = 60 * min;

  if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
  if (ms >= min) return (ms / min).toFixed(1) + 'm';
  if (ms >= sec) return (ms / sec | 0) + 's';

  return ms + 'ms';
}

function watch (task) {
  if (!task.watching && !task.path) return;
  var files;
  if (task.watching) {
    files = task.files('watching');
  } else {
    files = task.files('path');
  }
  debug('Watching changes on %s\'s files: %s (Total: %d files)', task.key, files.slice(0, 5).join(', '), files.length);

  var watcher = chokidar.watch(files, { persistent: true, interval: 250 });

  watcher.on('change', function() {
    debug('Restarting %s after the changes', task.key);
    task.run(false, true);
  });

  return watcher;
}

function nextColor () {
  if (typeof colors.next === 'undefined')
    colors.next = 0;
  else
    colors.next++;

  return colors[colors.next % colors.length];
}

function info (task) {
  var text = format.apply(undefined, Array.prototype.slice.call(arguments, 1));
  var key = rightpad(task.key, map.len);
  console.log(style(format('    {' + task.color + '}' + key + '{reset}  {grey}' + text + '{reset}')));
}

function beautify (task, line) {
  var key = rightpad(task.key, map.len);

  return style(format('    {color}{key}{reset} {line}', {
    color: '{' + task.color + '}',
    line: line.toString(),
    key: key
  })) + '\n';
}

function end (task, stream) {
  return eos(stream, task.done);
}

function globglob (task, opt) {
  if (task.path && opt === 'path')
    return globby.sync(task.path);
  else if (task.watching && opt === 'watching')
    return globby.sync(task.watching);
  else if (task.path || task.watching) {
    if (!opt) {
      var path = task.path || task.watching;
      return globby.sync(path);
    }
  } else {
    return [];
  }
}

function src (task, path) {
  if (path){
    return vinyl.src(path);
  } else if (task.path) {
    return vinyl.src(task.path);
  }
}

function dest (task, path) {
  if (path) {
    return vinyl.dest(path);
  } else if (task.options._dest) {
    return vinyl.dest(task.options._dest);
  }
}<commit_msg>update<commit_after>var Struct = require("new-struct");
var vinyl = require('vinyl-fs');
var eos = require('end-of-stream');
var pump = require('pump');
var debug = require("local-debug")('task');
var format = require("format-text");
var rightpad = require("right-pad");
var style = require("style-format");
var through = require("through");
var chokidar = require('chokidar');
var Options = require("./options");
var map = require("./map");
var run = require("./run");
var exec = require("./exec");
var globby = require('globby');

var Task = Struct({
  New: New,
  done: done,
  run: run,
  watch: watch,
  files: globglob,
  exec: exec,
  src: src,
  dest: dest,
  end: end
});

var colors = [
  'red',
  'green',
  'cyan',
  'magenta'
];

module.exports = Task;

function New (name, options, fn) {
  if (arguments.length === 2 && typeof options === 'function') {
    fn = options;
    options = Options.New();
  }

  debug('Created new task "%s"%s', name, options && options._watch ? (' watching ' + options._watch.join(',')) : '');

  var task = map.set(name, Task({
    name: name,
    key: map.slug(name),
    options: options,
    path: options._path,
    watching: options._watch,
    files: globglob,
    src: src,
    dest: dest,
    fn: fn,
    pump: pump,
    transform: transform,
    done: done,
    color: nextColor(),
    processes: [],
    params: {},
    info: info,
    end: end
  }));

  stdout();
  stderr();

  return task;

  function stdout () {
    if (task.stdout) {
      task.stdout.destroy();
    }

    task.stdout = std(task, stdout);
    task.stdout.pipe(process.stdout).setMaxListeners(0);
  }

  function stderr () {
    if (task.stderr) {
      task.stderr.destroy();
    }

    task.stderr = std(task, stderr);
    task.stderr.pipe(process.stderr).setMaxListeners(0);
  }
}

function std (task, callback) {
  return through(function (line) {
    this.queue(beautify(task, line));
  }, callback);
}

function done (task) {
  var diff = Date.now() - task.startTS;

  task.info(task, 'Completed in {0}', humanize(diff));

  task.onDone.publish();
  delete task.onDone;
  delete task.startTS;
}

function humanize (ms) {
  var sec = 1000;
  var min = 60 * 1000;
  var hour = 60 * min;

  if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
  if (ms >= min) return (ms / min).toFixed(1) + 'm';
  if (ms >= sec) return (ms / sec | 0) + 's';

  return ms + 'ms';
}

function watch (task) {
  if (!task.watching && !task.path) return;
  var files;
  if (task.watching) {
    files = task.files('watching');
  } else {
    files = task.files('path');
  }
  debug('Watching changes on %s\'s files: %s (Total: %d files)', task.key, files.slice(0, 5).join(', '), files.length);

  var watcher = chokidar.watch(files, { persistent: true, interval: 250 });

  watcher.on('change', function() {
    debug('Restarting %s after the changes', task.key);
    task.run(false, true);
  });

  return watcher;
}

function nextColor () {
  if (typeof colors.next === 'undefined')
    colors.next = 0;
  else
    colors.next++;

  return colors[colors.next % colors.length];
}

function info (task) {
  var text = format.apply(undefined, Array.prototype.slice.call(arguments, 1));
  var key = rightpad(task.key, map.len);
  console.log(style(format('    {' + task.color + '}' + key + '{reset}  {grey}' + text + '{reset}')));
}

function beautify (task, line) {
  var key = rightpad(task.key, map.len);

  return style(format('    {color}{key}{reset} {line}', {
    color: '{' + task.color + '}',
    line: line.toString(),
    key: key
  })) + '\n';
}

function end (task, stream) {
  return eos(stream, task.done);
}

function transform (task, arr) {
  var trans = [task.src()].concat(arr).push(task.dest());
  return pump(trans, function(err) {
    task.done(err);
  })
}

function globglob (task, opt) {
  if (task.path && opt === 'path')
    return globby.sync(task.path);
  else if (task.watching && opt === 'watching')
    return globby.sync(task.watching);
  else if (task.path || task.watching) {
    if (!opt) {
      var path = task.path || task.watching;
      return globby.sync(path);
    }
  } else {
    return [];
  }
}

function src (task, path) {
  if (path){
    return vinyl.src(path);
  } else if (task.path) {
    return vinyl.src(task.path);
  }
}

function dest (task, path) {
  if (path) {
    return vinyl.dest(path);
  } else if (task.options._dest) {
    return vinyl.dest(task.options._dest);
  }
}<|endoftext|>