<commit_before>define(function() {

  'use strict';

  function Terp() {
  }

  var validTerpScripts = new WeakMap();

  // modified version of JSON.stringify with specialized whitespace rules
  function stringifyStepOrBlock(stepOrBlock, indent) {
    if (typeof stepOrBlock[0] === 'string') {
      // step mode
      function stringifyElement(element) {
        if (typeof element === 'object' && element !== null) {
          if (!Array.isArray(element)) {
            throw new SyntaxError('Non-Array objects are not currently supported in TerpScript');
          }
          return stringifyStepOrBlock(element, indent);
        }
        return JSON.stringify(element);
      }
      return '[' + stepOrBlock.map(stringifyElement).join(', ') + ']';
    }
    if (stepOrBlock.length === 0) return '[ ]';
    if (stepOrBlock.length === 1) {
      indent = indent || '';
      var single = stringifyStepOrBlock(stepOrBlock[0], indent);
      if (!/\n/.test(single)) {
        return '[ ' + single + ' ]';
      }
      return '[\n' + indent + single + '\n' + indent + ']';
    }
    if (typeof indent !== 'string') {
      indent = '';
      function stringifyStepTop(step) {
        return stringifyStepOrBlock(step, indent);
      }
      return '[\n\n' + stepOrBlock.map(stringifyStepTop).join(',\n') + '\n\n]';
    }
    indent = indent || '';
    var newIndent = indent + '  ';
    function stringifyStep(step) {
      return stringifyStepOrBlock(step, newIndent);
    }
    return '[\n' + newIndent + stepOrBlock.map(stringifyStep).join(',\n' + newIndent) + '\n' + indent + ']';
  }

  var emptyScript = Object.freeze([]);
  validTerpScripts.set(emptyScript, true);

  function toTerpScript(stepOrBlock, okToModify) {
    if (stepOrBlock.length === 0) return emptyScript;
    if (!okToModify) {
      stepOrBlock = stepOrBlock.slice();
    }
    for (var i = 0; i < stepOrBlock.length; i++) {
      if (typeof stepOrBlock[i] === 'object' && stepOrBlock[i] !== null) {
        if (validTerpScripts.has(stepOrBlock[i])) {
          continue;
        }
        if (!Array.isArray(stepOrBlock(i))) {
          throw new SyntaxError('Non-Array objects are not currently supported in TerpScript');
        }
        stepOrBlock[i] = toTerpScript(stepOrBlock[i], okToModify);
      }
    }
    Object.freeze(stepOrBlock);
    validTerpScripts.set(stepOrBlock, true);
    return stepOrBlock;
  }

  function script(v, isTheOnlyReference) {
    if (validTerpScripts.has(v)) return v;
    if (typeof v === 'string') {
      v = JSON.parse(v);
      if (!Array.isArray(v)) {
        throw new SyntaxError('TerpScripts must be contained in an Array');
      }
      return toTerpScript(JSON.parse(v), true);
    }
    if (!Array.isArray(v)) {
      if (typeof v.toJSON !== 'function' || !Array.isArray(v = v.toJSON())) {
        throw new SyntaxError('TerpScripts must be contained in an Array');
      }
      return toTerpScript(v, true);
    }
    return toTerpScript(v, isTheOnlyReference);
  }

  Object.assign(Terp, {
    script: Object.assign(script, {
      stringify: function(script) {
        if (typeof script === 'string') {
          script = JSON.parse(script);
          if (Array.isArray(script)) {
            return stringifyStepOrBlock(script);
          }
        }
        else {
          if (Array.isArray(script)) {
            return stringifyStepOrBlock(script);
          }
          if (typeof script.toJSON === 'function' && Array.isArray(script = script.toJSON())) {
            return stringifyStepOrBlock(script);
          }
        }
        throw new SyntaxError('TerpScript must be an contained in an Array');
      },
      empty: emptyScript,
    }),
  });

  return Terp;

});
<commit_msg>Call should be subscript<commit_after>define(function() {

  'use strict';

  function Terp() {
  }

  var validTerpScripts = new WeakMap();

  // modified version of JSON.stringify with specialized whitespace rules
  function stringifyStepOrBlock(stepOrBlock, indent) {
    if (typeof stepOrBlock[0] === 'string') {
      // step mode
      function stringifyElement(element) {
        if (typeof element === 'object' && element !== null) {
          if (!Array.isArray(element)) {
            throw new SyntaxError('Non-Array objects are not currently supported in TerpScript');
          }
          return stringifyStepOrBlock(element, indent);
        }
        return JSON.stringify(element);
      }
      return '[' + stepOrBlock.map(stringifyElement).join(', ') + ']';
    }
    if (stepOrBlock.length === 0) return '[ ]';
    if (stepOrBlock.length === 1) {
      indent = indent || '';
      var single = stringifyStepOrBlock(stepOrBlock[0], indent);
      if (!/\n/.test(single)) {
        return '[ ' + single + ' ]';
      }
      return '[\n' + indent + single + '\n' + indent + ']';
    }
    if (typeof indent !== 'string') {
      indent = '';
      function stringifyStepTop(step) {
        return stringifyStepOrBlock(step, indent);
      }
      return '[\n\n' + stepOrBlock.map(stringifyStepTop).join(',\n') + '\n\n]';
    }
    indent = indent || '';
    var newIndent = indent + '  ';
    function stringifyStep(step) {
      return stringifyStepOrBlock(step, newIndent);
    }
    return '[\n' + newIndent + stepOrBlock.map(stringifyStep).join(',\n' + newIndent) + '\n' + indent + ']';
  }

  var emptyScript = Object.freeze([]);
  validTerpScripts.set(emptyScript, true);

  function toTerpScript(stepOrBlock, okToModify) {
    if (stepOrBlock.length === 0) return emptyScript;
    if (!okToModify) {
      stepOrBlock = stepOrBlock.slice();
    }
    for (var i = 0; i < stepOrBlock.length; i++) {
      if (typeof stepOrBlock[i] === 'object' && stepOrBlock[i] !== null) {
        if (validTerpScripts.has(stepOrBlock[i])) {
          continue;
        }
        if (!Array.isArray(stepOrBlock[i])) {
          throw new SyntaxError('Non-Array objects are not currently supported in TerpScript');
        }
        stepOrBlock[i] = toTerpScript(stepOrBlock[i], okToModify);
      }
    }
    Object.freeze(stepOrBlock);
    validTerpScripts.set(stepOrBlock, true);
    return stepOrBlock;
  }

  function script(v, isTheOnlyReference) {
    if (validTerpScripts.has(v)) return v;
    if (typeof v === 'string') {
      v = JSON.parse(v);
      if (!Array.isArray(v)) {
        throw new SyntaxError('TerpScripts must be contained in an Array');
      }
      return toTerpScript(JSON.parse(v), true);
    }
    if (!Array.isArray(v)) {
      if (typeof v.toJSON !== 'function' || !Array.isArray(v = v.toJSON())) {
        throw new SyntaxError('TerpScripts must be contained in an Array');
      }
      return toTerpScript(v, true);
    }
    return toTerpScript(v, isTheOnlyReference);
  }

  Object.assign(Terp, {
    script: Object.assign(script, {
      stringify: function(script) {
        if (typeof script === 'string') {
          script = JSON.parse(script);
          if (Array.isArray(script)) {
            return stringifyStepOrBlock(script);
          }
        }
        else {
          if (Array.isArray(script)) {
            return stringifyStepOrBlock(script);
          }
          if (typeof script.toJSON === 'function' && Array.isArray(script = script.toJSON())) {
            return stringifyStepOrBlock(script);
          }
        }
        throw new SyntaxError('TerpScript must be an contained in an Array');
      },
      empty: emptyScript,
    }),
  });

  return Terp;

});
<|endoftext|>


<commit_before>/*global module*/
(function () {

	// Establish the root object
	var
		root = this, // 'window' or 'global'
		atom = { VERSION: '0.0.7' },
		previous = root.atom
	;
	if (typeof module !== 'undefined' && module.exports) {
		module.exports = atom;
	}
	root.atom = atom;

	atom.noConflict = function () {
		root.atom = previous;
		return this;
	};

	// Convenience methods
	var slice = Array.prototype.slice;
	function isObject(obj) {
		return typeof obj === 'object';
	}
	var isArray = Array.isArray || function (obj) {
		return Object.prototype.toString.call(obj) === '[object Array]';
	};
	function inArray(arr, value) {
		for (var i = arr.length; --i >= 0;) {
			if (arr[i] === value) {
				return true;
			}
		}
	}
	function toArray(obj) {
		return isArray(obj) ? obj : [obj];
	}
	function isEmpty(obj) {
		for (var p in obj) {
			if (obj.hasOwnProperty(p)) {
				return false;
			}
		}
		return true;
	}

	// Property getter
	function get(nucleus, keyOrList, func) {
		var isList = isArray(keyOrList), keys = isList ? keyOrList : [keyOrList],
			key, values = [], props = nucleus.props, missing = {},
			result = { values: values };
		for (var i = keys.length; --i >= 0;) {
			key = keys[i];
			if (!props.hasOwnProperty(key)) {
				result.missing = missing;
				missing[key] = true;
			}
			values.unshift(props[key]);
		}
		return func ? func.apply({}, values) : result;
	}

	function removeListener(listeners, listener) {
		for (var i = listeners.length; --i >= 0;) {
			if (!listeners[i].calls) {
				return listeners.splice(i, 1);
			}
		}
	}

	// Property setter
	function set(nucleus, key, value) {
		var keys, listener, listeners = nucleus.listeners, values, missing,
			listenersCopy = [].concat(listeners), i = listenersCopy.length,
			props = nucleus.props, oldValue = props[key],
			had = props.hasOwnProperty(key);
		props[key] = value;
		if (!had || oldValue !== value || (value && typeof value === 'object')) {
			while (--i >= 0) {
				listener = listenersCopy[i];
				keys = listener.keys;
				missing = listener.missing;
				if (missing) {
					if (missing.hasOwnProperty(key)) {
						delete missing[key];
						if (isEmpty(missing)) {
							listener.cb.apply({}, get(nucleus, keys).values);
							listener.calls--;
						}
					}
				} else if (inArray(keys, key)) {
					listener.cb.apply({}, get(nucleus, keys).values);
					listener.calls--;
				}
				if (!listener.calls) {
					removeListener(listeners, listener);
				}
			}
			delete nucleus.needs[key];
		}
	}

	function provide(nucleus, key, provider) {
		provider(function (result) {
			set(nucleus, key, result);
		});
	}

	atom.create = function () {
		var
			nucleus = { props: {}, needs: {}, providers: {}, listeners: [] },
			props = nucleus.props,
			needs = nucleus.needs,
			providers = nucleus.providers,
			listeners = nucleus.listeners,
			q = []
		;
		function doNext() {
			if (q) {
				q.pending = q.next = (!q.next && q.length) ?
					q.shift() : q.next;
				q.args = slice.call(arguments, 0);
				if (q.pending) {
					q.next = null;
					q.pending.apply({}, [doNext].concat(q.args));
				}
			}
		}
		var me = {

			// Call `func` whenever any of the specified keys change.  The values
			// of the keys will be provided as args to func.
			bind: function (keyOrList, func) { // alias: `on`
				listeners.unshift({ keys: toArray(keyOrList), cb: func,
					calls: Infinity });
			},

			// Add a function or functions to the async queue.  Functions added
			// thusly must call their first arg as a callback when done.  Any args
			// provided to the callback will be passed in to the next function in
			// the queue.
			chain: function () {
				if (q) {
					for (var i = 0, len = arguments.length; i < len; i++) {
						q.push(arguments[i]);
						if (!q.pending) {
							doNext.apply({}, q.args);
						}
					}
				}
			},

			// Remove references to all properties and listeners.  This releases
			// memory, and effective stops the atom from working.
			destroy: function () {
				delete nucleus.props;
				delete nucleus.needs;
				delete nucleus.providers;
				delete nucleus.listeners;
				while (q.length) {
					q.pop();
				}
				nucleus = props = needs = providers = listeners =
					q = q.pending = q.next = q.args = null;
			},

			// Call `func` on each of the specified keys.  The key is provided as
			// the first arg, and the value as the second.
			each: function (keyOrList, func) {
				var keys = toArray(keyOrList), i = -1, len = keys.length, key;
				while (++i < len) {
					key = keys[i];
					func(key, me.get(key));
				}
			},

			// Establish two-way binding between a key or list of keys for two
			// different atoms, so that changing a property on either atom will
			// propagate to the other.  If a map is provided for `keyOrListOrMap`,
			// properties on this atom may be bound to differently named properties
			// on `otherAtom`.
			entangle: function (otherAtom, keyOrListOrMap) {
				var
					isList = isArray(keyOrListOrMap),
					isMap = !isList && isObject(keyOrListOrMap),
					i, key,
					keys = isList ? keyOrListOrMap : isMap ? [] : [keyOrListOrMap],
					map = isMap ? keyOrListOrMap : {}
				;
				if (isMap) {
					for (key in map) {
						if (map.hasOwnProperty(key)) {
							keys.push(key);
						}
					}
				} else {
					for (i = keys.length; --i >= 0;) {
						key = keys[i];
						map[key] = key;
					}
				}
				me.each(keys, function (key) {
					var otherKey = map[key];
					me.bind(key, function (value) {
						otherAtom.set(otherKey, value);
					});
					otherAtom.bind(otherKey, function (value) {
						me.set(key, value);
					});
				});
			},

			// Get current values for the specified keys.  If `func` is provided,
			// it will be called with the values as args.
			get: function (keyOrList, func) {
				var result = get(nucleus, keyOrList, func);
				return func ? result : typeof keyOrList === 'string' ?
					result.values[0] : result.values;
			},

			// Returns true iff all of the specified keys exist (regardless of
			// value).
			has: function (keyOrList) {
				var keys = toArray(keyOrList);
				for (var i = keys.length; --i >= 0;) {
					if (!props.hasOwnProperty(keys[i])) {
						return false;
					}
				}
				return true;
			},

			// Return a list of all keys.
			keys: function () {
				var keys = [];
				for (var key in props) {
					if (props.hasOwnProperty(key)) {
						keys.push(key);
					}
				}
				return keys;
			},

			// Add arbitrary properties to this atom's interface.
			mixin: function (obj) {
				for (var p in obj) {
					if (obj.hasOwnProperty(p)) {
						me[p] = obj[p];
					}
				}
				return me;
			},

			// Call `func` as soon as all of the specified keys have been set.  If
			// they are already set, the function will be called immediately, with
			// all the values provided as args.  In this, it is identical to
			// `once()`.  However, calling `need()` will additionally invoke
			// providers when possible, in order to try and create the required
			// values.
			need: function (keyOrList, func) {
				var key, keys = toArray(keyOrList), values, provider;
				for (var i = keys.length; --i >= 0;) {
					key = keys[i];
					provider = providers[key];
					if (!props.hasOwnProperty(key) && provider) {
						provide(nucleus, key, provider);
						delete providers[key];
					} else {
						needs[key] = true;
					}
				}
				me.once(keys, func);
			},

			// Call `func` whenever any of the specified keys is next changed.  The
			// values of all keys will be provided as args to the function.  The
			// function will automatically be unbound after being called the first
			// time, so it is guaranteed to be called no more than once.
			next: function (keyOrList, func) {
				listeners.unshift(
					{ keys: toArray(keyOrList), cb: func, calls: 1 });
			},

			// Call `func` as soon as all of the specified keys have been set.  If
			// they are already set, the function will be called immediately, with
			// all the values provided as args.  Guaranteed to be called no more
			// than once.
			once: function (keyOrList, func) {
				var keys = toArray(keyOrList),
					results = get(nucleus, keys),
					values = results.values,
					missing = results.missing;
				if (!missing) {
					func.apply({}, values);
				} else {
					listeners.unshift(
						{ keys: keys, cb: func, missing: missing, calls: 1 });
				}
			},

			// Register a provider for a particular key.  The provider `func` is a
			// function that will be called if there is a need to create the key.
			// It must call its first arg as a callback, with the value.  Provider
			// functions will be called at most once.
			provide: function (key, func) {
				if (needs[key]) {
					provide(nucleus, key, func);
				} else if (!providers[key]) {
					providers[key] = func;
				}
			},

			// Set value for a key, or if `keyOrMap` is an object then set all the
			// keys' corresponding values.
			set: function (keyOrMap, value) {
				if (isObject(keyOrMap)) {
					for (var key in keyOrMap) {
						if (keyOrMap.hasOwnProperty(key)) {
							set(nucleus, key, keyOrMap[key]);
						}
					}
				} else {
					set(nucleus, keyOrMap, value);
				}
			},

			// Unregister a listener `func` that was previously registered using
			// `bind()`, `need()`, `next()` or `once()`.
			unbind: function (func) { // alias: `off`
				for (var i = listeners.length; --i >= 0;) {
					if (listeners[i].cb === func) {
						listeners.splice(i, 1);
					}
				}
			}
		};
		me.on = me.bind;
		me.off = me.unbind;
		return me;
	};

}());
<commit_msg>Better module definition pattern<commit_after>/*global global, module*/
(function () {

	// Make a module
	var atom = (function (name) {
		var rt = typeof window !== 'undefined' ? window : global,
			had = rt.hasOwnProperty(name), prev = rt[name], me = rt[name] = {};
		if (typeof module !== 'undefined' && module.exports) {
			module.exports = me;
		}
		me.noConflict = function () {
			delete rt[name];
			if (had) {
				rt[name] = prev;
			}
			return this;
		};
		return me;
	}('atom'));

	atom.VERSION = '0.0.8';

	// Convenience methods
	var slice = Array.prototype.slice;
	function isObject(obj) {
		return typeof obj === 'object';
	}
	var isArray = Array.isArray || function (obj) {
		return Object.prototype.toString.call(obj) === '[object Array]';
	};
	function inArray(arr, value) {
		for (var i = arr.length; --i >= 0;) {
			if (arr[i] === value) {
				return true;
			}
		}
	}
	function toArray(obj) {
		return isArray(obj) ? obj : [obj];
	}
	function isEmpty(obj) {
		for (var p in obj) {
			if (obj.hasOwnProperty(p)) {
				return false;
			}
		}
		return true;
	}

	// Property getter
	function get(nucleus, keyOrList, func) {
		var isList = isArray(keyOrList), keys = isList ? keyOrList : [keyOrList],
			key, values = [], props = nucleus.props, missing = {},
			result = { values: values };
		for (var i = keys.length; --i >= 0;) {
			key = keys[i];
			if (!props.hasOwnProperty(key)) {
				result.missing = missing;
				missing[key] = true;
			}
			values.unshift(props[key]);
		}
		return func ? func.apply({}, values) : result;
	}

	function removeListener(listeners, listener) {
		for (var i = listeners.length; --i >= 0;) {
			if (!listeners[i].calls) {
				return listeners.splice(i, 1);
			}
		}
	}

	// Property setter
	function set(nucleus, key, value) {
		var keys, listener, listeners = nucleus.listeners, values, missing,
			listenersCopy = [].concat(listeners), i = listenersCopy.length,
			props = nucleus.props, oldValue = props[key],
			had = props.hasOwnProperty(key);
		props[key] = value;
		if (!had || oldValue !== value || (value && typeof value === 'object')) {
			while (--i >= 0) {
				listener = listenersCopy[i];
				keys = listener.keys;
				missing = listener.missing;
				if (missing) {
					if (missing.hasOwnProperty(key)) {
						delete missing[key];
						if (isEmpty(missing)) {
							listener.cb.apply({}, get(nucleus, keys).values);
							listener.calls--;
						}
					}
				} else if (inArray(keys, key)) {
					listener.cb.apply({}, get(nucleus, keys).values);
					listener.calls--;
				}
				if (!listener.calls) {
					removeListener(listeners, listener);
				}
			}
			delete nucleus.needs[key];
		}
	}

	function provide(nucleus, key, provider) {
		provider(function (result) {
			set(nucleus, key, result);
		});
	}

	atom.create = function () {
		var
			nucleus = { props: {}, needs: {}, providers: {}, listeners: [] },
			props = nucleus.props,
			needs = nucleus.needs,
			providers = nucleus.providers,
			listeners = nucleus.listeners,
			q = []
		;
		function doNext() {
			if (q) {
				q.pending = q.next = (!q.next && q.length) ?
					q.shift() : q.next;
				q.args = slice.call(arguments, 0);
				if (q.pending) {
					q.next = null;
					q.pending.apply({}, [doNext].concat(q.args));
				}
			}
		}
		var me = {

			// Call `func` whenever any of the specified keys change.  The values
			// of the keys will be provided as args to func.
			bind: function (keyOrList, func) { // alias: `on`
				listeners.unshift({ keys: toArray(keyOrList), cb: func,
					calls: Infinity });
			},

			// Add a function or functions to the async queue.  Functions added
			// thusly must call their first arg as a callback when done.  Any args
			// provided to the callback will be passed in to the next function in
			// the queue.
			chain: function () {
				if (q) {
					for (var i = 0, len = arguments.length; i < len; i++) {
						q.push(arguments[i]);
						if (!q.pending) {
							doNext.apply({}, q.args);
						}
					}
				}
			},

			// Remove references to all properties and listeners.  This releases
			// memory, and effective stops the atom from working.
			destroy: function () {
				delete nucleus.props;
				delete nucleus.needs;
				delete nucleus.providers;
				delete nucleus.listeners;
				while (q.length) {
					q.pop();
				}
				nucleus = props = needs = providers = listeners =
					q = q.pending = q.next = q.args = null;
			},

			// Call `func` on each of the specified keys.  The key is provided as
			// the first arg, and the value as the second.
			each: function (keyOrList, func) {
				var keys = toArray(keyOrList), i = -1, len = keys.length, key;
				while (++i < len) {
					key = keys[i];
					func(key, me.get(key));
				}
			},

			// Establish two-way binding between a key or list of keys for two
			// different atoms, so that changing a property on either atom will
			// propagate to the other.  If a map is provided for `keyOrListOrMap`,
			// properties on this atom may be bound to differently named properties
			// on `otherAtom`.
			entangle: function (otherAtom, keyOrListOrMap) {
				var
					isList = isArray(keyOrListOrMap),
					isMap = !isList && isObject(keyOrListOrMap),
					i, key,
					keys = isList ? keyOrListOrMap : isMap ? [] : [keyOrListOrMap],
					map = isMap ? keyOrListOrMap : {}
				;
				if (isMap) {
					for (key in map) {
						if (map.hasOwnProperty(key)) {
							keys.push(key);
						}
					}
				} else {
					for (i = keys.length; --i >= 0;) {
						key = keys[i];
						map[key] = key;
					}
				}
				me.each(keys, function (key) {
					var otherKey = map[key];
					me.bind(key, function (value) {
						otherAtom.set(otherKey, value);
					});
					otherAtom.bind(otherKey, function (value) {
						me.set(key, value);
					});
				});
			},

			// Get current values for the specified keys.  If `func` is provided,
			// it will be called with the values as args.
			get: function (keyOrList, func) {
				var result = get(nucleus, keyOrList, func);
				return func ? result : typeof keyOrList === 'string' ?
					result.values[0] : result.values;
			},

			// Returns true iff all of the specified keys exist (regardless of
			// value).
			has: function (keyOrList) {
				var keys = toArray(keyOrList);
				for (var i = keys.length; --i >= 0;) {
					if (!props.hasOwnProperty(keys[i])) {
						return false;
					}
				}
				return true;
			},

			// Return a list of all keys.
			keys: function () {
				var keys = [];
				for (var key in props) {
					if (props.hasOwnProperty(key)) {
						keys.push(key);
					}
				}
				return keys;
			},

			// Add arbitrary properties to this atom's interface.
			mixin: function (obj) {
				for (var p in obj) {
					if (obj.hasOwnProperty(p)) {
						me[p] = obj[p];
					}
				}
				return me;
			},

			// Call `func` as soon as all of the specified keys have been set.  If
			// they are already set, the function will be called immediately, with
			// all the values provided as args.  In this, it is identical to
			// `once()`.  However, calling `need()` will additionally invoke
			// providers when possible, in order to try and create the required
			// values.
			need: function (keyOrList, func) {
				var key, keys = toArray(keyOrList), values, provider;
				for (var i = keys.length; --i >= 0;) {
					key = keys[i];
					provider = providers[key];
					if (!props.hasOwnProperty(key) && provider) {
						provide(nucleus, key, provider);
						delete providers[key];
					} else {
						needs[key] = true;
					}
				}
				me.once(keys, func);
			},

			// Call `func` whenever any of the specified keys is next changed.  The
			// values of all keys will be provided as args to the function.  The
			// function will automatically be unbound after being called the first
			// time, so it is guaranteed to be called no more than once.
			next: function (keyOrList, func) {
				listeners.unshift(
					{ keys: toArray(keyOrList), cb: func, calls: 1 });
			},

			// Call `func` as soon as all of the specified keys have been set.  If
			// they are already set, the function will be called immediately, with
			// all the values provided as args.  Guaranteed to be called no more
			// than once.
			once: function (keyOrList, func) {
				var keys = toArray(keyOrList),
					results = get(nucleus, keys),
					values = results.values,
					missing = results.missing;
				if (!missing) {
					func.apply({}, values);
				} else {
					listeners.unshift(
						{ keys: keys, cb: func, missing: missing, calls: 1 });
				}
			},

			// Register a provider for a particular key.  The provider `func` is a
			// function that will be called if there is a need to create the key.
			// It must call its first arg as a callback, with the value.  Provider
			// functions will be called at most once.
			provide: function (key, func) {
				if (needs[key]) {
					provide(nucleus, key, func);
				} else if (!providers[key]) {
					providers[key] = func;
				}
			},

			// Set value for a key, or if `keyOrMap` is an object then set all the
			// keys' corresponding values.
			set: function (keyOrMap, value) {
				if (isObject(keyOrMap)) {
					for (var key in keyOrMap) {
						if (keyOrMap.hasOwnProperty(key)) {
							set(nucleus, key, keyOrMap[key]);
						}
					}
				} else {
					set(nucleus, keyOrMap, value);
				}
			},

			// Unregister a listener `func` that was previously registered using
			// `bind()`, `need()`, `next()` or `once()`.
			unbind: function (func) { // alias: `off`
				for (var i = listeners.length; --i >= 0;) {
					if (listeners[i].cb === func) {
						listeners.splice(i, 1);
					}
				}
			}
		};
		me.on = me.bind;
		me.off = me.unbind;
		return me;
	};

}());
<|endoftext|>


<commit_before>const git = require('simple-git');
const firebase = require('firebase')
const config = require('./config')

// const path = __dirname + '/iotos';
// git(path).then etc..

firebase.initializeApp(config);

var ref = firebase.database().ref().child("servers")

ref.child(config.device).on('value', deploy)
// ref.child(config.device).on('value', function (data) {
// 	//console.log(data.val())
// 	deploy();
// })
function deploy () {
  console.log('Starting Deploying aplication ::-)');

	git()
	.then(function() {
		console.log('Starting pull ... :-(´´)');
	})
	.pull(function(err, update) {
		if(update && update.summary.changes) {
			console.log('processing and restarting app...');
		}
	})
	.then(function() {
	console.log('pull done.');
	});
}<commit_msg>update project<commit_after>const git = require('simple-git');
const firebase = require('firebase')
const config = require('./config')

// const path = __dirname + '/iotos';
// git(path).then etc..

firebase.initializeApp(config);

var ref = firebase.database().ref().child("servers")

ref.child(config.device).on('value', deploy)

// ref.child(config.device).on('value', function (data) {
// 	//console.log(data.val())
// 	deploy();
// })

function deploy () {
  console.log('Starting Deploying aplication -)');

	git()
	.then(function() {
		console.log('Starting pull ... :-');
	})
	.pull(function(err, update) {
		if(update && update.summary.changes) {
			console.log('processing and restarting app...');
		}
	})
	.then(function() {
	console.log('pull done.');
	});
}<|endoftext|>


<commit_before>var baseClass             = require('./libs/base');
var scraper               = new (require('./libs/scraper'));
var db                    = require('./libs/db');
var _                     = require('underscore');
var Promise               = require('promise');
var querystring           = require('querystring');
var airlines              = {"airasia": 1, "citilink": 2, "garuda": 3, "lion": 4, "sriwijaya": 5, "xpress": 6};
var priceScraperPrototype = {
	init                     : init,
	setOption                : setOption,
	setOptions               : setOptions,
	setMode                  : setMode,
	prepareRequestData       : prepareRequestData,
	prepareRequestQuery      : prepareRequestQuery,
	prepareDatabaseQuery     : prepareDatabaseQuery,
	preparePricesOutputFromDB: preparePricesOutputFromDB,
	getCache                 : getCache,
	preparePricesInputToDB   : preparePricesInputToDB,
	saveCache                : saveCache,
	generateId               : generateId,
	get                      : get,
	getAll                   : getAll,
	getAllParallel           : getAllParallel,
	isCacheComplete          : isCacheComplete,
	calculatePrices          : calculatePrices,
	run                      : run,
}
_.mixin(require('underscore.deep'));
var priceScraper = baseClass.extend(priceScraperPrototype);
/**
 * [init description]
 * @param  {Object} args Custom options.
 */
function init(args) {
	this.db = db;
	this.setOptions(args);
	this.priceCode = airlines[this.airline] || 0;
}
/**
 * setting options, using one arguments: an object with key-value pair,
 * or two arguments, with the first as key and second as value
 */
function setOptions() {
	if (arguments.length === 1) {
		var args = arguments[0];
		var defaults = {
			scrape: '', //if url will be used as request with query, if function will be executed with dt object
			dt: {ori: '', dst: '', flightCode: '', classCode: '' },
			airline: '',
			index: 'pluto',
			type: 'price',
			parallel: false
		}
		var options = _.deepExtend(defaults, args);
		for (var key in defaults) {
			var value = options[key];
			this[key] = value;
			if (typeof this[key] === 'string')
				this[key] = this[key].toLowerCase();
		}
	} else {
		var key = arguments[0];
		var value = arguments[1];
		this[key] = value;
	}
	return this;
}
/**
 * alias for setOptions
 */
function setOption() {
	return setOptions.apply(this, arguments);
}
/**
 * setting mode before running scrape price
 * @param {string} mode Passengers count e.g: '100', '101', '110'
 */
function setMode(mode) {
	if(!mode || !mode.length || mode.length !== 3) {
		mode = '100';
	}
	var aMode      = mode.split('').filter(function (val) { return val == 0 || val == 1});
	this.dt.adult  = aMode[0];
	this.dt.child  = aMode[1];
	this.dt.infant = aMode[2];
	return this;
}
/**
 * preparing data for scrape function arguments
 * @return {Object} Data formatted for parameter in scraper function
 */
function prepareRequestData () {
	var _dt  = {}
	var dt   = _.deepExtend(this.dt, _dt)
	dt.priceScraper = true;
	var data = {airline: this.airline, action: this.type, query: dt }
	return data;
}
/**
 * preparing querystring for request function
 * @return {String} String formatted for parameter in request function
 */
function prepareRequestQuery () {
	var _dt  = {}
	var dt   = _.deepExtend(this.dt, _dt)
	dt.priceScraper = true;
	var query = querystring.stringify(dt);
	query = query.replace(/%2B/g, '+');
	return query;
}
/**
 * create query for retrieving data from db
 * @return {string} query for db
 */
function prepareDatabaseQuery () {
	var _this       = this;
	var _ori        = _this.dt.ori.toLowerCase();
	var _dst        = _this.dt.dst.toLowerCase();
	var _flightCode = _this.dt.flightCode;
	var _classCode  = _this.dt.classCode;
	var _airline    = _this.airline;
	var query = {"size":1, "query": {"filtered": {"filter": {"and" : [
		{ "term": { "origin": _ori } },
		{ "term": { "destination": _dst} },
		{ "term": { "flight": _flightCode } },
		{ "term": { "class": _classCode } },
		{ "term": { "airline": _airline} } ] } } } };
	if (_this.dt.transit)
		query.query.filtered.filter.and.push({"term": {"transit": _this.dt.transit}});
	if (_this.dt.transit2)
		query.query.filtered.filter.and.push({"term": {"transit2": _this.dt.transit2}});
	if (_this.dt.transit3)
		query.query.filtered.filter.and.push({"term": {"transit3": _this.dt.transit3}});
	return query;
}
function preparePricesOutputFromDB (prices) {
	var _this = this;
	return _.object(
		_.map(prices, function (value, key, object) {
			return [key, value - _this.priceCode];
		})
	);
}
/**
 * Get cache data from db
 * @return {Object} Data price for current dt
 */
function getCache () {
	var _this = this;
	return new Promise(function (resolve, reject) {
		var query = _this.prepareDatabaseQuery();
		_this.db.search(_this.index, _this.type, query, function (err, res) {
			if (err)
				return reject(err)
			try {res = JSON.parse(res)} catch(err) { return reject(err)}
			// console.log(JSON.stringify(res, null, 2));
			if (res.hits.total <= 0)
				return reject(new Error('No cache found'));
			var prices = res.hits.hits[0]._source.prices;
			// console.log(JSON.stringify(res));
			if (!!prices && typeof prices === 'object')
				return resolve(prices);
			prices = {};
			var price = res.hits.hits[0]._source.price;
			if(!!price)
				prices.adult = price
			prices = _this.preparePricesOutputFromDB(prices);
			return resolve(prices);
		});
	})
	.catch(function (err) {
		return Promise.reject(err);
	});
}
function preparePricesInputToDB (prices) {
	var _this = this;
	return _.object(
		_.map(prices, function (value, key, object) {
			return [key, value + _this.priceCode];
		})
	);
}
/**
 * save price data to db
 * @param  {Object} price object containing price data
 */
function saveCache (prices, callback) {
	callback = (typeof callback === 'function') ? callback : function() {};
	var _this = this;
	var _prices = _this.preparePricesInputToDB(prices);
	var data = {
		origin     : _this.dt.ori,
		destination: _this.dt.dst,
		airline    : _this.airline,
		flight     : _this.dt.flightCode || '',
		class      : _this.dt.classCode || '',
		prices     : _prices,
		price      : _prices.adult
	};
	data.id = _this.generateId(data);
	// console.log(data);
	db.index(_this.index, _this.type, data, function (err, res) {
		console.log('savecache', res, data);
		return callback(err, res)
	});
}
/**
 * get price by scraping it as defined in scrape option
 * @param  {string} mode Passengers count e.g.(100,110,101)
 * @return {Object}      Object Promise
 */
function get(mode) {
	this.setMode(mode);
	if (typeof this.scrape === 'function') {
		var data = this.prepareRequestData();
		return this.scrape(data);
	} else {
		var query = this.prepareRequestQuery();
		var url = this.scrape + '?' + query;
		return scraper.get(url);
	}
}
/**
 * get scrape data all modes sequence
 * @return {Object} Array of object containing data price
 */
function getAll () {
	if(!!this.parallel)
		return this.getAllParallel();
	var _this = this;
	var results = [];
	var modes = ['100', '110', '101'];
	var steps = modes.reduce(function (sequence, mode) {
		return sequence.then(function () {
			return _this.get(mode)
				.then(function (res) {
					results.push(res);
				})
		});
	}, Promise.resolve());
	return new Promise(function (resolve, reject) {
		steps
			.then(function () {
				// console.log(results,'results');
				return resolve(results);
			})
	})
}
/**
 * get scrape data all modes paraller
 * @return {Object} Array of object containing data price
 */
function getAllParallel () {
	var _this = this;
	var modes = ['100', '110', '101'];
	var steps = [];
	modes.forEach(function (mode) {
		var step = _this.get(mode)
		steps.push(step);
	});
	return Promise.all(steps);
}
/**
 * return formatted prices from results
 * @param  {object} results Results from getAll
 * @return {Object}         Formatted prices to be outputted
 */
function calculatePrices (results) {
	var prices = {
		adult : this.calculateAdult(results),
		child : this.calculateChild(results),
		infant: this.calculateInfant(results),
		basic : this.calculateBasic(results),
	};
	return prices;
}
function run () {
	var _this = this;
	return new Promise(function (resolve, reject) {
		if(!!_this.dt.priceScraper){
			console.log('_this.dt.priceScraper');
			return resolve(true);
		}
		_this.getCache()
			.then(function (cache) {
				console.log(;cache found', cache);
				if (_this.isCacheComplete(cache))
					return reject();
				return resolve(cache);
			})
			.catch(function () {
				console.log('no cache');
				return _this.getAll()
			})
			.then(function (results) {
				console.log('got results getAll', results);
				var prices = _this.calculatePrices(results);
				_this.saveCache(prices);
				return resolve(prices);
			})
			.catch(function (err) {
				// console.log(err.stack);
				return reject(err);
			})
	})
}
/**
 * internal function used when saving data to db
 * @param  {Object} data Save to db
 * @return {string}      id for db
 */
function generateId (data) {
	return data.origin + data.destination + data.airline + data.flight + data.class;
};
/**
 * check if cache qualified as complete
 * @param  {Object}  cache data from db
 * @return {Boolean}       whether cache incomplete or not
 */
function isCacheComplete (cache) {
	if (!cache)
		return false;
	var requirements = ['adult', 'child', 'infant', 'basic'];
	return _.every(requirements, function (requirement) {
		return !!cache[requirement] && cache[requirement] > 0;
	});
}
module.exports = priceScraper;<commit_msg>debug<commit_after>var baseClass             = require('./libs/base');
var scraper               = new (require('./libs/scraper'));
var db                    = require('./libs/db');
var _                     = require('underscore');
var Promise               = require('promise');
var querystring           = require('querystring');
var airlines              = {"airasia": 1, "citilink": 2, "garuda": 3, "lion": 4, "sriwijaya": 5, "xpress": 6};
var priceScraperPrototype = {
	init                     : init,
	setOption                : setOption,
	setOptions               : setOptions,
	setMode                  : setMode,
	prepareRequestData       : prepareRequestData,
	prepareRequestQuery      : prepareRequestQuery,
	prepareDatabaseQuery     : prepareDatabaseQuery,
	preparePricesOutputFromDB: preparePricesOutputFromDB,
	getCache                 : getCache,
	preparePricesInputToDB   : preparePricesInputToDB,
	saveCache                : saveCache,
	generateId               : generateId,
	get                      : get,
	getAll                   : getAll,
	getAllParallel           : getAllParallel,
	isCacheComplete          : isCacheComplete,
	calculatePrices          : calculatePrices,
	run                      : run,
}
_.mixin(require('underscore.deep'));
var priceScraper = baseClass.extend(priceScraperPrototype);
/**
 * [init description]
 * @param  {Object} args Custom options.
 */
function init(args) {
	this.db = db;
	this.setOptions(args);
	this.priceCode = airlines[this.airline] || 0;
}
/**
 * setting options, using one arguments: an object with key-value pair,
 * or two arguments, with the first as key and second as value
 */
function setOptions() {
	if (arguments.length === 1) {
		var args = arguments[0];
		var defaults = {
			scrape: '', //if url will be used as request with query, if function will be executed with dt object
			dt: {ori: '', dst: '', flightCode: '', classCode: '' },
			airline: '',
			index: 'pluto',
			type: 'price',
			parallel: false
		}
		var options = _.deepExtend(defaults, args);
		for (var key in defaults) {
			var value = options[key];
			this[key] = value;
			if (typeof this[key] === 'string')
				this[key] = this[key].toLowerCase();
		}
	} else {
		var key = arguments[0];
		var value = arguments[1];
		this[key] = value;
	}
	return this;
}
/**
 * alias for setOptions
 */
function setOption() {
	return setOptions.apply(this, arguments);
}
/**
 * setting mode before running scrape price
 * @param {string} mode Passengers count e.g: '100', '101', '110'
 */
function setMode(mode) {
	if(!mode || !mode.length || mode.length !== 3) {
		mode = '100';
	}
	var aMode      = mode.split('').filter(function (val) { return val == 0 || val == 1});
	this.dt.adult  = aMode[0];
	this.dt.child  = aMode[1];
	this.dt.infant = aMode[2];
	return this;
}
/**
 * preparing data for scrape function arguments
 * @return {Object} Data formatted for parameter in scraper function
 */
function prepareRequestData () {
	var _dt  = {}
	var dt   = _.deepExtend(this.dt, _dt)
	dt.priceScraper = true;
	var data = {airline: this.airline, action: this.type, query: dt }
	return data;
}
/**
 * preparing querystring for request function
 * @return {String} String formatted for parameter in request function
 */
function prepareRequestQuery () {
	var _dt  = {}
	var dt   = _.deepExtend(this.dt, _dt)
	dt.priceScraper = true;
	var query = querystring.stringify(dt);
	query = query.replace(/%2B/g, '+');
	return query;
}
/**
 * create query for retrieving data from db
 * @return {string} query for db
 */
function prepareDatabaseQuery () {
	var _this       = this;
	var _ori        = _this.dt.ori.toLowerCase();
	var _dst        = _this.dt.dst.toLowerCase();
	var _flightCode = _this.dt.flightCode;
	var _classCode  = _this.dt.classCode;
	var _airline    = _this.airline;
	var query = {"size":1, "query": {"filtered": {"filter": {"and" : [
		{ "term": { "origin": _ori } },
		{ "term": { "destination": _dst} },
		{ "term": { "flight": _flightCode } },
		{ "term": { "class": _classCode } },
		{ "term": { "airline": _airline} } ] } } } };
	if (_this.dt.transit)
		query.query.filtered.filter.and.push({"term": {"transit": _this.dt.transit}});
	if (_this.dt.transit2)
		query.query.filtered.filter.and.push({"term": {"transit2": _this.dt.transit2}});
	if (_this.dt.transit3)
		query.query.filtered.filter.and.push({"term": {"transit3": _this.dt.transit3}});
	return query;
}
function preparePricesOutputFromDB (prices) {
	var _this = this;
	return _.object(
		_.map(prices, function (value, key, object) {
			return [key, value - _this.priceCode];
		})
	);
}
/**
 * Get cache data from db
 * @return {Object} Data price for current dt
 */
function getCache () {
	var _this = this;
	return new Promise(function (resolve, reject) {
		var query = _this.prepareDatabaseQuery();
		_this.db.search(_this.index, _this.type, query, function (err, res) {
			if (err)
				return reject(err)
			try {res = JSON.parse(res)} catch(err) { return reject(err)}
			// console.log(JSON.stringify(res, null, 2));
			if (res.hits.total <= 0)
				return reject(new Error('No cache found'));
			var prices = res.hits.hits[0]._source.prices;
			// console.log(JSON.stringify(res));
			if (!!prices && typeof prices === 'object')
				return resolve(prices);
			prices = {};
			var price = res.hits.hits[0]._source.price;
			if(!!price)
				prices.adult = price
			prices = _this.preparePricesOutputFromDB(prices);
			return resolve(prices);
		});
	})
	.catch(function (err) {
		return Promise.reject(err);
	});
}
function preparePricesInputToDB (prices) {
	var _this = this;
	return _.object(
		_.map(prices, function (value, key, object) {
			return [key, value + _this.priceCode];
		})
	);
}
/**
 * save price data to db
 * @param  {Object} price object containing price data
 */
function saveCache (prices, callback) {
	callback = (typeof callback === 'function') ? callback : function() {};
	var _this = this;
	var _prices = _this.preparePricesInputToDB(prices);
	var data = {
		origin     : _this.dt.ori,
		destination: _this.dt.dst,
		airline    : _this.airline,
		flight     : _this.dt.flightCode || '',
		class      : _this.dt.classCode || '',
		prices     : _prices,
		price      : _prices.adult
	};
	data.id = _this.generateId(data);
	// console.log(data);
	db.index(_this.index, _this.type, data, function (err, res) {
		console.log('savecache', res, data);
		return callback(err, res)
	});
}
/**
 * get price by scraping it as defined in scrape option
 * @param  {string} mode Passengers count e.g.(100,110,101)
 * @return {Object}      Object Promise
 */
function get(mode) {
	this.setMode(mode);
	if (typeof this.scrape === 'function') {
		var data = this.prepareRequestData();
		return this.scrape(data);
	} else {
		var query = this.prepareRequestQuery();
		var url = this.scrape + '?' + query;
		return scraper.get(url);
	}
}
/**
 * get scrape data all modes sequence
 * @return {Object} Array of object containing data price
 */
function getAll () {
	if(!!this.parallel)
		return this.getAllParallel();
	var _this = this;
	var results = [];
	var modes = ['100', '110', '101'];
	var steps = modes.reduce(function (sequence, mode) {
		return sequence.then(function () {
			return _this.get(mode)
				.then(function (res) {
					results.push(res);
				})
		});
	}, Promise.resolve());
	return new Promise(function (resolve, reject) {
		steps
			.then(function () {
				// console.log(results,'results');
				return resolve(results);
			})
	})
}
/**
 * get scrape data all modes paraller
 * @return {Object} Array of object containing data price
 */
function getAllParallel () {
	var _this = this;
	var modes = ['100', '110', '101'];
	var steps = [];
	modes.forEach(function (mode) {
		var step = _this.get(mode)
		steps.push(step);
	});
	return Promise.all(steps);
}
/**
 * return formatted prices from results
 * @param  {object} results Results from getAll
 * @return {Object}         Formatted prices to be outputted
 */
function calculatePrices (results) {
	var prices = {
		adult : this.calculateAdult(results),
		child : this.calculateChild(results),
		infant: this.calculateInfant(results),
		basic : this.calculateBasic(results),
	};
	return prices;
}
function run () {
	var _this = this;
	return new Promise(function (resolve, reject) {
		if(!!_this.dt.priceScraper){
			console.log('_this.dt.priceScraper');
			return resolve(true);
		}
		_this.getCache()
			.then(function (cache) {
				console.log('cache found', cache);
				if (_this.isCacheComplete(cache))
					return reject();
				return resolve(cache);
			})
			.catch(function () {
				console.log('no cache');
				return _this.getAll()
			})
			.then(function (results) {
				console.log('got results getAll', results);
				var prices = _this.calculatePrices(results);
				_this.saveCache(prices);
				return resolve(prices);
			})
			.catch(function (err) {
				// console.log(err.stack);
				return reject(err);
			})
	})
}
/**
 * internal function used when saving data to db
 * @param  {Object} data Save to db
 * @return {string}      id for db
 */
function generateId (data) {
	return data.origin + data.destination + data.airline + data.flight + data.class;
};
/**
 * check if cache qualified as complete
 * @param  {Object}  cache data from db
 * @return {Boolean}       whether cache incomplete or not
 */
function isCacheComplete (cache) {
	if (!cache)
		return false;
	var requirements = ['adult', 'child', 'infant', 'basic'];
	return _.every(requirements, function (requirement) {
		return !!cache[requirement] && cache[requirement] > 0;
	});
}
module.exports = priceScraper;<|endoftext|>


<commit_before>#!/usr/bin/env node

const HELP =
"blah --help" +
"\nusage: blah [options] [actions]" +
"\n" +
"\nBlah version. Blah gitignore. Blah README. Boring. You need blah." +
"\n" +
"\noptions:" +
"\n  --v, --version          print the version" +
"\n  --help                  print this output" +
"\n" +
"\nactions:" +
"\n  readme                  creates the readme.md file" +
"\n  gitignore               creates .gitignore file" +
"\n  license [license-name]  creates the LICENSE file by providing the license name" +
"\n" +
"\nDocumentation can be found at https://github.com/IonicaBizau/node-blah";

/**
 * getPackage
 * Returns the parsed content of package.json
 *
 * @return string representing the content of package.json file
 * found in the current directory
 */
function getPackage () {
    return require (process.env.PWD + "/package");
}

/**
 * generateReadme
 * Returns a string representing the readme content of the project.
 *
 * @return: string representing the content of README.md file
 */
function generateReadme () {

    var pack = getPackage ()
      , Fs = require("fs")
      , Path = require("path")
      , JxUtils = require("jxutils")
      , flattenPack = JxUtils.flattenObject(pack)
      , content = Fs.readFileSync(__dirname + "/templates/README.md").toString();
      , MarkDox = require("markdox")
      , Parser = require("dox-parser")
      , markdoxOps = {
            output: function () {
                console.log(arguments);
            }
          , formatter: MarkDox
          , compiler: function (filepath, data) {
                return myCustomCompiler(data);
            }
          , template: Path.resolve(__dirname + "/markdox-res/template.ejs")
        }
      ;

    MarkDox.process(Parser, options, function () {
         console.log('File `all.md` generated with success');

        for (var key in flattenPack) {
            content = content.replace(new RegExp("{" + key + "+}", "g"), flattenPack[key]);
        }

        return content;
    });
}

/**
 * generateGitignore
 * Returns the content of .gitignore file
 *
 * @return: string representing the content of .gitignore file
 */
function generateGitignore () {

    var content =
        "*.swp\n" +
        "*.swo\n" +
        "*~\n" +
        "*.log\n" +
        "node_modules"
      ;

    return content;
}

/**
 * generateLicense
 * Returns the content of the LICENSE by providing the @licenseName
 *
 * @param licenseName: the license name
 * @return string representing the LICENSE content
 */
function generateLicense (licenseName) {

    var fullName = null
      , pack = require (process.env.PWD + "/package")
      ;

    try {
        var gitconfigLines = require ("fs").readFileSync(
            require('path-extra').homedir() + "/.gitconfig"
        ).toString().replace(/\t/g, "").split("\n");

        for (var i = 0; i < gitconfigLines.length; ++i) {
            var cLine = gitconfigLines[i].trim();
            if (/^name/.test(cLine)) {
                fullName = cLine.split("=")[1].trim();
                break;
            }
        }
    } catch (e) {
    }

    if (!fullName) {
        console.log("No fullname found in .gitconfig. Please modify LICENSE [fullname] manually");
        fullName = "[fullname]";
    }

    return require ("fs")
        .readFileSync (__dirname + "/templates/licenses/" + licenseName.toLowerCase() + ".txt")
        .toString ()
        .replace ("[project]", pack.name)
        .replace ("[year]", new Date().getFullYear())
        .replace ("[fullname]", fullName)
        .replace ("[description]", pack.description)
        ;
}

/**
 * generateDocs
 *
 * @name generateDocs
 * @function
 * @param {String} fileName The input JavaScript file'
 * @return {String} The generated docs
 */
function generateDocs (fileName) {
    var content = require("fs").readFileSync(require("path").resolve(fileName)).toString().split("\n");
    var docs = "";
    for (var i = 0, parsing = false, k = -1; i < content; ++i) {
        var cLine = content[i];
        if (cLine.indexOf("/**") !== -1 && !parsing) {
            parsing = true;
        }

        var cDoc = {};

        if (parsing) {
            docs += ([
                // name
                function () { cDoc.name = cLine.replace("*", "").trim(); }
                // empty line
              , undefined
                // name
              , function () { return cLine.replace("*", "").trim() }
            ][++k] || function () {})()
        }
    }

}

/**
 * Available options and actions
 *
 */
var options = {

    // Options
    "version": {
        run: function () {
            console.log("Blah v" + require ("./package").version)
        }
      , aliases: ["-v", "--version", "--v", "-version"]
    }
  , "help": {
        run: function () {
            console.log (HELP);
        }
      , aliases: ["-h", "--help", "--h", "-help"]
    }

    // Actions
  , "readme": {
        run: function () {
            require ("fs").writeFileSync (
                "./README.md"
              , generateReadme()
            )
        }
      , aliases: ["readme"]
    }
  , "gitignore": {
        run: function () {
            require ("fs").writeFileSync (
                "./.gitignore"
              , generateGitignore()
            )
        }
      , aliases: ["gitignore"]
    }
  , "license": {
        run: function () {
            require ("fs").writeFileSync (
                "./LICENSE"
              , generateLicense (process.argv[3])
            )
        }
      , aliases: ["license"]
    }
  , "docs": {
        run: function () {
            require ("fs").writeFileSync (
                "./docs.md"
              , generateDocs (process.argv[3])
            )
        }
      , aliases: ["docs"]
    }
};

// Parse process.argv and run the needed action
for (var i = 2; i < process.argv.length; ++i) {
    var cArg = process.argv[i];
    for (var op in options) {
        var cOp = options[op];
        if (cOp.aliases.indexOf (cArg) !== -1) {
            cOp.run();
            process.exit (0);
        }
    }
}

// No actions, no fun
if (process.argv.length === 2) {
    console.error ("No action/option provided. Run blah --help for more information");
    process.exit (1);
}

// Invalid option/action
console.error ("Invalid option or action: " + process.argv.slice (2).join(", "));
<commit_msg>Pass path to doc md file<commit_after>#!/usr/bin/env node

const HELP =
"blah --help" +
"\nusage: blah [options] [actions]" +
"\n" +
"\nBlah version. Blah gitignore. Blah README. Boring. You need blah." +
"\n" +
"\noptions:" +
"\n  --v, --version          print the version" +
"\n  --help                  print this output" +
"\n" +
"\nactions:" +
"\n  readme                  creates the readme.md file" +
"\n  gitignore               creates .gitignore file" +
"\n  license [license-name]  creates the LICENSE file by providing the license name" +
"\n" +
"\nDocumentation can be found at https://github.com/IonicaBizau/node-blah";

/**
 * getPackage
 * Returns the parsed content of package.json
 *
 * @return string representing the content of package.json file
 * found in the current directory
 */
function getPackage () {
    return require (process.env.PWD + "/package");
}

/**
 * generateReadme
 * Returns a string representing the readme content of the project.
 *
 * @return: string representing the content of README.md file
 */
function generateReadme () {

    var pack = getPackage ()
      , Fs = require("fs")
      , Path = require("path")
      , JxUtils = require("jxutils")
      , flattenPack = JxUtils.flattenObject(pack)
      , content = Fs.readFileSync(__dirname + "/templates/README.md").toString();
      , MarkDox = require("markdox")
      , Parser = require("dox-parser")
      , markdoxOps = {
            output: function () {
                console.log(arguments);
            }
          , formatter: MarkDox
          , compiler: function (filepath, data) {
                return myCustomCompiler(data);
            }
          , template: Path.resolve(__dirname + "/markdox-res/template.ejs")
        }
      ;

    MarkDox.process("./all.md", options, function () {
         console.log('File `all.md` generated with success');

        for (var key in flattenPack) {
            content = content.replace(new RegExp("{" + key + "+}", "g"), flattenPack[key]);
        }

        return content;
    });
}

/**
 * generateGitignore
 * Returns the content of .gitignore file
 *
 * @return: string representing the content of .gitignore file
 */
function generateGitignore () {

    var content =
        "*.swp\n" +
        "*.swo\n" +
        "*~\n" +
        "*.log\n" +
        "node_modules"
      ;

    return content;
}

/**
 * generateLicense
 * Returns the content of the LICENSE by providing the @licenseName
 *
 * @param licenseName: the license name
 * @return string representing the LICENSE content
 */
function generateLicense (licenseName) {

    var fullName = null
      , pack = require (process.env.PWD + "/package")
      ;

    try {
        var gitconfigLines = require ("fs").readFileSync(
            require('path-extra').homedir() + "/.gitconfig"
        ).toString().replace(/\t/g, "").split("\n");

        for (var i = 0; i < gitconfigLines.length; ++i) {
            var cLine = gitconfigLines[i].trim();
            if (/^name/.test(cLine)) {
                fullName = cLine.split("=")[1].trim();
                break;
            }
        }
    } catch (e) {
    }

    if (!fullName) {
        console.log("No fullname found in .gitconfig. Please modify LICENSE [fullname] manually");
        fullName = "[fullname]";
    }

    return require ("fs")
        .readFileSync (__dirname + "/templates/licenses/" + licenseName.toLowerCase() + ".txt")
        .toString ()
        .replace ("[project]", pack.name)
        .replace ("[year]", new Date().getFullYear())
        .replace ("[fullname]", fullName)
        .replace ("[description]", pack.description)
        ;
}

/**
 * generateDocs
 *
 * @name generateDocs
 * @function
 * @param {String} fileName The input JavaScript file'
 * @return {String} The generated docs
 */
function generateDocs (fileName) {
    var content = require("fs").readFileSync(require("path").resolve(fileName)).toString().split("\n");
    var docs = "";
    for (var i = 0, parsing = false, k = -1; i < content; ++i) {
        var cLine = content[i];
        if (cLine.indexOf("/**") !== -1 && !parsing) {
            parsing = true;
        }

        var cDoc = {};

        if (parsing) {
            docs += ([
                // name
                function () { cDoc.name = cLine.replace("*", "").trim(); }
                // empty line
              , undefined
                // name
              , function () { return cLine.replace("*", "").trim() }
            ][++k] || function () {})()
        }
    }

}

/**
 * Available options and actions
 *
 */
var options = {

    // Options
    "version": {
        run: function () {
            console.log("Blah v" + require ("./package").version)
        }
      , aliases: ["-v", "--version", "--v", "-version"]
    }
  , "help": {
        run: function () {
            console.log (HELP);
        }
      , aliases: ["-h", "--help", "--h", "-help"]
    }

    // Actions
  , "readme": {
        run: function () {
            require ("fs").writeFileSync (
                "./README.md"
              , generateReadme()
            )
        }
      , aliases: ["readme"]
    }
  , "gitignore": {
        run: function () {
            require ("fs").writeFileSync (
                "./.gitignore"
              , generateGitignore()
            )
        }
      , aliases: ["gitignore"]
    }
  , "license": {
        run: function () {
            require ("fs").writeFileSync (
                "./LICENSE"
              , generateLicense (process.argv[3])
            )
        }
      , aliases: ["license"]
    }
  , "docs": {
        run: function () {
            require ("fs").writeFileSync (
                "./docs.md"
              , generateDocs (process.argv[3])
            )
        }
      , aliases: ["docs"]
    }
};

// Parse process.argv and run the needed action
for (var i = 2; i < process.argv.length; ++i) {
    var cArg = process.argv[i];
    for (var op in options) {
        var cOp = options[op];
        if (cOp.aliases.indexOf (cArg) !== -1) {
            cOp.run();
            process.exit (0);
        }
    }
}

// No actions, no fun
if (process.argv.length === 2) {
    console.error ("No action/option provided. Run blah --help for more information");
    process.exit (1);
}

// Invalid option/action
console.error ("Invalid option or action: " + process.argv.slice (2).join(", "));
<|endoftext|>


<commit_before>var tags = {};

function scrollToBody() {
	console.log("scrolling to body");
	$("html, body").animate({
		scrollTop: $("#body").offset().top
	}, 1000);
}

$(document).ready(function(){
	$(window).resize();

    showAllPostPreviews();
    var hash = decodeURI(window.location.hash);
    if (hash) {
        showPost(hash.substring(1, hash.length));
    }
});

$(window).resize(function(){
	if ($(this).width() < 1000) {
		$("#otherInfos").css("width", "90%");
		$("#content").css("width", "90%");
	} else {
		$("#otherInfos").css("width", "25%");
		$("#content").css("width", "60%");
	}
});

function showPostsPreviews(posts) {
	$("#shareLink").html("");
    if (posts != null) {
		// posts found
		$("#content").html("");
        for (i in posts) {
			var html = "";
			html += "

"
			$("#content").append(html);
			var xhttp = new XMLHttpRequest();
			xhttp["postId"] = posts[i];
			xhttp.onreadystatechange = function() {
			    if (this.readyState == 4 && this.status == 200) {
					var info = JSON.parse(this.responseText);
		            if (info == null) {
		                return;
		            }

					var html = "";
		            html += "
";
		            html += info.title;
		            html += "

";
		            html += info.timestamp;
		            html += "

";
		            html += info.extract;
		            html += " Read more...

Tags: ";
		            for (j in info.tags) {
		                html += "";
		                html += info.tags[j] + ", ";

		                // add tags to tags
		                if (tags[info.tags[j]] == null) {
		                    tags[info.tags[j]] = [this["postId"]];
		                } else {
		                    if ($.inArray(posts[i], tags[info.tags[j]]) == -1) {
		                        tags[info.tags[j]].push(this["postId"]);
		                    }
		                }
		            }
		            html = html.substring(0, html.length - 2);
		            html += "
";

			        $("#" + this["postId"]).html(html);
			    }
			};
            xhttp.open("GET", posts[i] + "/info.json", true);
			xhttp.timeout = 2000;
            xhttp.send();
        }
    } else {
        // no posts
		$("#content").html("No Posts. ");
    }
}

function showAllPostPreviews() {
	var xhttp = new XMLHttpRequest();
	xhttp.onreadystatechange = function() {
	    if (this.readyState == 4 && this.status == 200) {
			var posts = JSON.parse(this.responseText).posts;
			showPostsPreviews(posts);
		}
	};
    xhttp.open("GET", "postSum.json", true);
	xhttp.timeout = 2000;
    xhttp.send();
}

function showTagPostsPreviews(tagName) {
	showPostsPreviews(tags[tagName]);
	$("#content").prepend("
Tag: " + tagName + "
");
}

function showPost(name) {
	var html = "";
	html = $("
").append($("#" + name).clone()).html();
	$("#content").html(html);
	$("#" + name + ">.postTitle").css("font-size", "40px");

	var xhttp = new XMLHttpRequest();
	xhttp.onreadystatechange = function() {
	    if (this.readyState == 4 && this.status == 200) {
			if (this.responseText != null) {
				var escapedContent = this.responseText.replace(/&/g, "&")
									.replace(/\n/g, "
")
									.replace(/        /g, "        ")
									.replace(/\t/g, "        ")
									//.replace(/</g, "<")
									//.replace(/>/g, ">")
									//.replace(/"/g, """)
									.replace(/'/g, "'")
									;

				$("#content>#" + name + ">.postExtract").html("
"+ escapedContent + "
");
				//$("#shareLink").html("Link to this page (URL does not work):
http://blog.zhukaihan.com/index.html#" + name + "
");
		    } else {
		        $("#content>#" + name + ">.postExtract").html("
No Such Article.
");
		    }
		}
	};
	xhttp.open("GET", name + "/content", true);
	xhttp.timeout = 2000;
	xhttp.send();

	scrollToBody();
}
<commit_msg>Update Code<commit_after>var tags = {};

function scrollToBody() {
	console.log("scrolling to body");
	$("html, body").animate({
		scrollTop: $("#body").offset().top
	}, 1000);
}

$(document).ready(function(){
	$(window).resize();

    showAllPostPreviews();
    var hash = decodeURI(window.location.hash);
    if (hash) {
        showPost(hash.substring(1, hash.length));
    }
});

$(window).resize(function(){
	if ($(this).width() < 1000) {
		$("#otherInfos").css("width", "90%");
		$("#content").css("width", "90%");
	} else {
		$("#otherInfos").css("width", "25%");
		$("#content").css("width", "60%");
	}
});

function showPostsPreviews(posts) {
	$("#shareLink").html("");
    if (posts != null) {
		// posts found
		$("#content").html("");
        for (i in posts) {
			var html = "";
			html += "

"
			$("#content").append(html);
			var xhttp = new XMLHttpRequest();
			xhttp["postId"] = posts[i];
			xhttp.onreadystatechange = function() {
			    if (this.readyState == 4 && this.status == 200) {
					var info = JSON.parse(this.responseText);
		            if (info == null) {
		                return;
		            }

					var html = "";
		            html += "
";
		            html += info.title;
		            html += "

";
		            html += info.timestamp;
		            html += "

";
		            html += info.extract;
		            html += " Read more...

Tags: ";
		            for (j in info.tags) {
		                html += "";
		                html += info.tags[j] + ", ";

		                // add tags to tags
						if ($.inArray(this["postId"], tags[info.tags[j]]) == -1) {
							tags[info.tags[j]].push(this["postId"]);
						}
		                /*if (tags[info.tags[j]] == null) {
		                    tags[info.tags[j]] = [this["postId"]];
		                } else {

		                }*/
		            }
		            html = html.substring(0, html.length - 2);
		            html += "
";

			        $("#" + this["postId"]).html(html);
			    }
			};
            xhttp.open("GET", posts[i] + "/info.json", true);
			xhttp.timeout = 2000;
            xhttp.send();
        }
    } else {
        // no posts
		$("#content").html("No Posts. ");
    }
}

function showAllPostPreviews() {
	var xhttp = new XMLHttpRequest();
	xhttp.onreadystatechange = function() {
	    if (this.readyState == 4 && this.status == 200) {
			var posts = JSON.parse(this.responseText).posts;
			showPostsPreviews(posts);
		}
	};
    xhttp.open("GET", "postSum.json", true);
	xhttp.timeout = 2000;
    xhttp.send();
}

function showTagPostsPreviews(tagName) {
	showPostsPreviews(tags[tagName]);
	$("#content").prepend("
Tag: " + tagName + "
");
}

function showPost(name) {
	var html = "";
	html = $("
").append($("#" + name).clone()).html();
	$("#content").html(html);
	$("#" + name + ">.postTitle").css("font-size", "40px");

	var xhttp = new XMLHttpRequest();
	xhttp.onreadystatechange = function() {
	    if (this.readyState == 4 && this.status == 200) {
			if (this.responseText != null) {
				var escapedContent = this.responseText.replace(/&/g, "&")
									.replace(/\n/g, "
")
									.replace(/        /g, "        ")
									.replace(/\t/g, "        ")
									//.replace(/</g, "<")
									//.replace(/>/g, ">")
									//.replace(/"/g, """)
									.replace(/'/g, "'")
									;

				$("#content>#" + name + ">.postExtract").html("
"+ escapedContent + "
");
				//$("#shareLink").html("Link to this page (URL does not work):
http://blog.zhukaihan.com/index.html#" + name + "
");
		    } else {
		        $("#content>#" + name + ">.postExtract").html("
No Such Article.
");
		    }
		}
	};
	xhttp.open("GET", name + "/content", true);
	xhttp.timeout = 2000;
	xhttp.send();

	scrollToBody();
}
<|endoftext|>


<commit_before>/*global require, applicationContext*/

////////////////////////////////////////////////////////////////////////////////
/// @brief A Foxx.Controller to show all Foxx Applications
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Michael Hackstein
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

"use strict";

// Initialise a new FoxxController called controller under the urlPrefix: "foxxes".
var FoxxController = require("org/arangodb/foxx").Controller,
  controller = new FoxxController(applicationContext),
  ArangoError = require("org/arangodb").ArangoError,
  underscore = require("underscore"),
  joi = require("joi"),
  notifications = require("org/arangodb/configuration").notifications,
  db = require("internal").db,
  foxxInstallKey = joi.string().required().description(
    "The _key attribute, where the information of this Foxx-Install is stored."
  ),
  appname = joi.string().required();

var foxxes = new (require("lib/foxxes").Foxxes)();
var FoxxManager = require("org/arangodb/foxx/manager");
var docus = new (require("lib/swagger").Swagger)();

controller.get("/whoAmI", function(req, res) {
  res.json({
    name: req.user
  });
});

controller.get("/unauthorized", function(req, res) {
  throw new ArangoError();
}).errorResponse(ArangoError, 401, "unauthorized");

/** Is version check allowed
 *
 * Check if version check is allowed
 */
controller.get("shouldCheckVersion", function(req, res) {
  var versions = notifications.versions();
  if (!versions || versions.enableVersionNotification === false) {
    res.json(false);
  } else {
    res.json(true);
  }
});

/** Disable version check
 *
 * Disable the version check in web interface
 */
controller.post("disableVersionCheck", function(req, res) {
  notifications.setVersions({
    enableVersionNotification: false
  });
  res.json("ok");
});

/** Fetch a foxx from temp folder
 *
 * Makes a foxx uploaded to the temp folder
 * available for mounting.
 */

controller.post("/foxxes/inspect", function (req, res) {
  var content = JSON.parse(req.requestBody),
    path = content.filename;
  res.json(foxxes.inspect(path));
}).errorResponse(ArangoError, 500, "No valid app");

// .............................................................................
// install
// .............................................................................

controller.put("/foxxes/install", function (req, res) {
  var content = JSON.parse(req.requestBody),
    name = content.name,
    mount = content.mount,
    version = content.version,
    options = content.options;
    res.json(foxxes.install(name, mount, version, options));
}).summary("Installs a new foxx")
.notes("This function is used to install a new foxx.");

/** Install a Foxx from Github
 *
 * Install a Foxx with URL and .....
 */

controller.post("/foxxes/gitinstall", function (req, res) {

  var content = JSON.parse(req.requestBody),
  name = content.name,
  url = content.url,
  version = content.version;

  var appID = FoxxManager.fetchFromGithub(url, name, version);

  res.json(appID);
}).summary("Installs a foxx or update existing")
.notes("This function is used to install or update a (new) foxx.");

/** Remove an uninstalled Foxx
 *
 * Remove the Foxx with the given key.
 */

controller.del("/foxxes/purge/:key", function (req, res) {
  res.json(FoxxManager.purge(req.params("key")));
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("Remove a Foxx.")
.notes("This function is used to remove a foxx.");

/** Remove all uninstalled Foxx versions
 *
 * Remove the Foxx with the given array of versions app ids.
 */

controller.del("/foxxes/purgeall/:key", function (req, res) {
  var name = req.params("key");

  var allFoxxes = foxxes.viewAll();
  var toDelete = [];

  underscore.each(allFoxxes, function(myFoxx) {
    if (myFoxx.name === name) {
      toDelete.push(myFoxx.app);
    }
  });

  underscore.each(toDelete, function(myFoxx) {
    FoxxManager.purge(myFoxx);
  });

  res.json({res: true});
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("Remove a all existing Foxx versions .")
.notes("This function is used to remove all versions of a foxx.");

/** Get info about github information of an available Foxx
 *
 * Returns github information of Foxx
 */

controller.get("/foxxes/gitinfo/:key", function (req, res) {
  res.json(FoxxManager.gitinfo(req.params("key")));
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("List git information of a Foxx")
.notes("This function is used to display all available github information of a foxx");

/** Get info about mount points of an installed Foxx
 *
 * Returns mount points of Foxx
 */

controller.get("/foxxes/mountinfo/:key", function (req, res) {
  res.json(FoxxManager.mountinfo(req.params("key")));
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("List mount points of a Foxx")
.notes("This function is used to display all available mount points of a foxx");

/** Get info about all mount points of all installed Foxx
 *
 * Returns mount points of all Foxxes
 */

controller.get("/foxxes/mountinfo/", function (req, res) {
  res.json(FoxxManager.mountinfo());
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("List mount points of all Foxx")
.notes("This function is used to display all available mount points of all foxxes");

/** Uninstall a Foxx
 *
 * Uninstall the Foxx with the given key.
 */

controller.del("/foxxes/:key", function (req, res) {
  res.json(foxxes.uninstall(req.params("key")));
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("Uninstall a Foxx.")
.notes("This function is used to uninstall a foxx.");

/** Update a Foxx
 *
 * Update the Foxx with the given information.
 */

controller.put("/foxxes/:key", function (req, res) {
  var content = JSON.parse(req.requestBody),
    active = content.active;
  // TODO: Other changes applied to foxx! e.g. Mount
  if (active) {
    res.json(foxxes.activate());
  } else {
    res.json(foxxes.deactivate());
  }
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("Update a foxx.")
  .notes("Used to either activate/deactivate a foxx, or change the mount point.");

/** Get the thubmail of a Foxx
 *
 * Request the Thumbnail stored for a Foxx
 */

controller.get("/foxxes/thumbnail/:app", function (req, res) {
  res.transformations = [ "base64decode" ];
  res.body = foxxes.thumbnail(req.params("app"));

  // evil mimetype detection attempt...
  var start = require("internal").base64Decode(res.body.substr(0, 8));
  if (start.indexOf("PNG") !== -1) {
    res.contentType = "image/png";
  }
}).pathParam("app", {
  type: appname.description(
    "The appname which is used to identify the foxx in the list of available foxxes."
  ),
  allowMultiple: false
}).summary("Get the thumbnail of a foxx.")
  .notes("Used to request the thumbnail of the given Foxx in order to display it on the screen.");

/** List all Foxxes
 *
 * Get a List of all Foxxes available and running
 *
 */
controller.get('/foxxes', function (req, res) {
  res.json(foxxes.viewAll());
}).summary("List of all foxxes.")
  .notes("This function simply returns the list of all running foxxes");

/** List available Documentation
 *
 * Get the list of all running Foxxes with links to their documentation
 */
controller.get('/docus', function (req, res) {
  res.json(docus.list(req.protocol + "://" + req.headers.host + "/_db/" + req.database + req.path + "/"));
}).summary("List documentation of all foxxes.")
  .notes("This function simply returns the list of all running"
       + " foxxes and supplies the paths for the swagger documentation");
/** Get Documentation for one Foxx
 *
 * Get the complete documentation available for one Foxx
 *
 */

controller.get("/docu/:key",function (req, res) {
  var subPath = req.path.substr(0, req.path.lastIndexOf("[") - 1),
    key = req.params("key"),
    path = req.protocol + "://" + req.headers.host +
           "/_db/" + encodeURIComponent(req.database) + subPath + "/" + encodeURIComponent(key) + "/";
  res.json(docus.listOne(path, key));
}).summary("List documentation of one foxxes.")
  .notes("This function simply returns one specific"
       + " foxx and supplies the paths for the swagger documentation");

 /** Subroutes for API Documentation
  *
  * Get the Elements of the API Documentation subroutes
  *
  */
controller.get('/docu/:key/*', function(req, res) {
  var mountPoint = "";
    underscore.each(req.suffix, function(part) {
      mountPoint += "/" + part;
    });
  res.json(docus.show(mountPoint));
}).summary("List the API for one foxx")
  .notes("This function lists the API of the foxx"
       + " running under the given mount point");

/** Subroutes for API Documentation
  *
  * Get the Elements of the API Documentation subroutes
  *
  */
controller.get('/swagger/:mount', function(req, res) {
  var subPath = req.path.substr(0, req.path.lastIndexOf("[") - 1),
    mount = decodeURIComponent(req.params("mount")),
    path = req.protocol + "://" + req.headers.host +
           "/_db/" + encodeURIComponent(req.database) + subPath + "/" + encodeURIComponent(mount) + "/",
    candidate = db._aal.firstExample({ mount: mount });

  if (candidate === null) {
    throw "no entry found for mount";
  }
  res.json(docus.show(mount));
//  res.json(docus.listOneForMount(path, mount));
}).summary("Returns the generated Swagger JSON description for one foxx")
  .notes("This function returns the Swagger JSON API description of the foxx"
       + " running under the given mount point");

/** Move Foxx to other Mount
 *
 * Move a running Foxx from one mount point to another
 *
 */
controller.put('/foxx/move/:key', function(req, res) {
  var body = req.body();
  var mountPoint = body.mount;
  var app = body.app;
  var key = req.params("key");
  var prefix = body.prefix;
  var result = foxxes.move(key, app, mountPoint, prefix);
  if (result.error) {
    res.status(result.status);
    res.body = result.message;
    return;
  }
  res.json(result);
})
.summary("Move one foxx to another moint point")
  .notes ("This function moves one installed foxx"
    + " to a given mount point.");

/** Download stored queries
 *
 * Download and export all queries from the given username.
 *
 */

controller.post("/query/upload/:user", function(req, res) {
  var user = req.params("user");
  var response, queries, userColl, storedQueries, queriesToSave;

  queries = req.body();
  userColl = db._users.byExample({"user": user}).toArray()[0];
  storedQueries = userColl.extra.queries;
  queriesToSave = [];

  underscore.each(queries, function(newq) {
    var toBeStored = true;
    underscore.each(storedQueries, function(stored) {
      if (stored.name === newq.name) {
        toBeStored = false;
      }
    });
    if (toBeStored === true) {
      queriesToSave.push(newq);
    }
  });

  queriesToSave = queriesToSave.concat(storedQueries);

  var toUpdate = {
    extra: {
      queries: queriesToSave
    }
  }

  var result = db._users.update(userColl, toUpdate, true);
  res.json(result);
}).summary("Upload user queries")
  .notes("This function uploads all given user queries");

/** Download stored queries
 *
 * Download and export all queries from the given username.
 *
 */

controller.get("/query/download/:user", function(req, res) {
  var user = req.params("user");
  var result = db._users.byExample({"user": user}).toArray()[0];

  res.set("Content-Type", "application/json");
  res.set("Content-Disposition", "attachment; filename=queries.json");

  res.json(result.userData.queries);

}).summary("Download all user queries")
  .notes("This function downloads all user queries from the given user");

/** Download a query result
 *
 * Download and export all queries from the given username.
 *
 */

controller.get("/query/result/download/:query", function(req, res) {
  var query = req.params("query"),
  parsedQuery;

  var internal = require("internal");
  query = internal.base64Decode(query);
  try {
    parsedQuery = JSON.parse(query);
  }
  catch (ignore) {
  }

  var result = db._query(parsedQuery.query, parsedQuery.bindVars).toArray();
  res.set("Content-Type", "application/json");
  res.set("Content-Disposition", "attachment; filename=results.json");
  res.json(result);

}).summary("Download the result of a query")
  .notes("This function downloads the result of a user query.");

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

/// Local Variables:
/// mode: outline-minor
/// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
/// End:
<commit_msg>issue #1103:  Error while importing user queries<commit_after>/*global require, applicationContext*/

////////////////////////////////////////////////////////////////////////////////
/// @brief A Foxx.Controller to show all Foxx Applications
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Michael Hackstein
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

"use strict";

// Initialise a new FoxxController called controller under the urlPrefix: "foxxes".
var FoxxController = require("org/arangodb/foxx").Controller,
  controller = new FoxxController(applicationContext),
  ArangoError = require("org/arangodb").ArangoError,
  underscore = require("underscore"),
  joi = require("joi"),
  notifications = require("org/arangodb/configuration").notifications,
  db = require("internal").db,
  foxxInstallKey = joi.string().required().description(
    "The _key attribute, where the information of this Foxx-Install is stored."
  ),
  appname = joi.string().required();

var foxxes = new (require("lib/foxxes").Foxxes)();
var FoxxManager = require("org/arangodb/foxx/manager");
var docus = new (require("lib/swagger").Swagger)();

controller.get("/whoAmI", function(req, res) {
  res.json({
    name: req.user
  });
});

controller.get("/unauthorized", function(req, res) {
  throw new ArangoError();
}).errorResponse(ArangoError, 401, "unauthorized");

/** Is version check allowed
 *
 * Check if version check is allowed
 */
controller.get("shouldCheckVersion", function(req, res) {
  var versions = notifications.versions();
  if (!versions || versions.enableVersionNotification === false) {
    res.json(false);
  } else {
    res.json(true);
  }
});

/** Disable version check
 *
 * Disable the version check in web interface
 */
controller.post("disableVersionCheck", function(req, res) {
  notifications.setVersions({
    enableVersionNotification: false
  });
  res.json("ok");
});

/** Fetch a foxx from temp folder
 *
 * Makes a foxx uploaded to the temp folder
 * available for mounting.
 */

controller.post("/foxxes/inspect", function (req, res) {
  var content = JSON.parse(req.requestBody),
    path = content.filename;
  res.json(foxxes.inspect(path));
}).errorResponse(ArangoError, 500, "No valid app");

// .............................................................................
// install
// .............................................................................

controller.put("/foxxes/install", function (req, res) {
  var content = JSON.parse(req.requestBody),
    name = content.name,
    mount = content.mount,
    version = content.version,
    options = content.options;
    res.json(foxxes.install(name, mount, version, options));
}).summary("Installs a new foxx")
.notes("This function is used to install a new foxx.");

/** Install a Foxx from Github
 *
 * Install a Foxx with URL and .....
 */

controller.post("/foxxes/gitinstall", function (req, res) {

  var content = JSON.parse(req.requestBody),
  name = content.name,
  url = content.url,
  version = content.version;

  var appID = FoxxManager.fetchFromGithub(url, name, version);

  res.json(appID);
}).summary("Installs a foxx or update existing")
.notes("This function is used to install or update a (new) foxx.");

/** Remove an uninstalled Foxx
 *
 * Remove the Foxx with the given key.
 */

controller.del("/foxxes/purge/:key", function (req, res) {
  res.json(FoxxManager.purge(req.params("key")));
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("Remove a Foxx.")
.notes("This function is used to remove a foxx.");

/** Remove all uninstalled Foxx versions
 *
 * Remove the Foxx with the given array of versions app ids.
 */

controller.del("/foxxes/purgeall/:key", function (req, res) {
  var name = req.params("key");

  var allFoxxes = foxxes.viewAll();
  var toDelete = [];

  underscore.each(allFoxxes, function(myFoxx) {
    if (myFoxx.name === name) {
      toDelete.push(myFoxx.app);
    }
  });

  underscore.each(toDelete, function(myFoxx) {
    FoxxManager.purge(myFoxx);
  });

  res.json({res: true});
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("Remove a all existing Foxx versions .")
.notes("This function is used to remove all versions of a foxx.");

/** Get info about github information of an available Foxx
 *
 * Returns github information of Foxx
 */

controller.get("/foxxes/gitinfo/:key", function (req, res) {
  res.json(FoxxManager.gitinfo(req.params("key")));
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("List git information of a Foxx")
.notes("This function is used to display all available github information of a foxx");

/** Get info about mount points of an installed Foxx
 *
 * Returns mount points of Foxx
 */

controller.get("/foxxes/mountinfo/:key", function (req, res) {
  res.json(FoxxManager.mountinfo(req.params("key")));
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("List mount points of a Foxx")
.notes("This function is used to display all available mount points of a foxx");

/** Get info about all mount points of all installed Foxx
 *
 * Returns mount points of all Foxxes
 */

controller.get("/foxxes/mountinfo/", function (req, res) {
  res.json(FoxxManager.mountinfo());
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("List mount points of all Foxx")
.notes("This function is used to display all available mount points of all foxxes");

/** Uninstall a Foxx
 *
 * Uninstall the Foxx with the given key.
 */

controller.del("/foxxes/:key", function (req, res) {
  res.json(foxxes.uninstall(req.params("key")));
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("Uninstall a Foxx.")
.notes("This function is used to uninstall a foxx.");

/** Update a Foxx
 *
 * Update the Foxx with the given information.
 */

controller.put("/foxxes/:key", function (req, res) {
  var content = JSON.parse(req.requestBody),
    active = content.active;
  // TODO: Other changes applied to foxx! e.g. Mount
  if (active) {
    res.json(foxxes.activate());
  } else {
    res.json(foxxes.deactivate());
  }
}).pathParam("key", {
  type: foxxInstallKey,
  allowMultiple: false
}).summary("Update a foxx.")
  .notes("Used to either activate/deactivate a foxx, or change the mount point.");

/** Get the thubmail of a Foxx
 *
 * Request the Thumbnail stored for a Foxx
 */

controller.get("/foxxes/thumbnail/:app", function (req, res) {
  res.transformations = [ "base64decode" ];
  res.body = foxxes.thumbnail(req.params("app"));

  // evil mimetype detection attempt...
  var start = require("internal").base64Decode(res.body.substr(0, 8));
  if (start.indexOf("PNG") !== -1) {
    res.contentType = "image/png";
  }
}).pathParam("app", {
  type: appname.description(
    "The appname which is used to identify the foxx in the list of available foxxes."
  ),
  allowMultiple: false
}).summary("Get the thumbnail of a foxx.")
  .notes("Used to request the thumbnail of the given Foxx in order to display it on the screen.");

/** List all Foxxes
 *
 * Get a List of all Foxxes available and running
 *
 */
controller.get('/foxxes', function (req, res) {
  res.json(foxxes.viewAll());
}).summary("List of all foxxes.")
  .notes("This function simply returns the list of all running foxxes");

/** List available Documentation
 *
 * Get the list of all running Foxxes with links to their documentation
 */
controller.get('/docus', function (req, res) {
  res.json(docus.list(req.protocol + "://" + req.headers.host + "/_db/" + req.database + req.path + "/"));
}).summary("List documentation of all foxxes.")
  .notes("This function simply returns the list of all running"
       + " foxxes and supplies the paths for the swagger documentation");
/** Get Documentation for one Foxx
 *
 * Get the complete documentation available for one Foxx
 *
 */

controller.get("/docu/:key",function (req, res) {
  var subPath = req.path.substr(0, req.path.lastIndexOf("[") - 1),
    key = req.params("key"),
    path = req.protocol + "://" + req.headers.host +
           "/_db/" + encodeURIComponent(req.database) + subPath + "/" + encodeURIComponent(key) + "/";
  res.json(docus.listOne(path, key));
}).summary("List documentation of one foxxes.")
  .notes("This function simply returns one specific"
       + " foxx and supplies the paths for the swagger documentation");

 /** Subroutes for API Documentation
  *
  * Get the Elements of the API Documentation subroutes
  *
  */
controller.get('/docu/:key/*', function(req, res) {
  var mountPoint = "";
    underscore.each(req.suffix, function(part) {
      mountPoint += "/" + part;
    });
  res.json(docus.show(mountPoint));
}).summary("List the API for one foxx")
  .notes("This function lists the API of the foxx"
       + " running under the given mount point");

/** Subroutes for API Documentation
  *
  * Get the Elements of the API Documentation subroutes
  *
  */
controller.get('/swagger/:mount', function(req, res) {
  var subPath = req.path.substr(0, req.path.lastIndexOf("[") - 1),
    mount = decodeURIComponent(req.params("mount")),
    path = req.protocol + "://" + req.headers.host +
           "/_db/" + encodeURIComponent(req.database) + subPath + "/" + encodeURIComponent(mount) + "/",
    candidate = db._aal.firstExample({ mount: mount });

  if (candidate === null) {
    throw "no entry found for mount";
  }
  res.json(docus.show(mount));
//  res.json(docus.listOneForMount(path, mount));
}).summary("Returns the generated Swagger JSON description for one foxx")
  .notes("This function returns the Swagger JSON API description of the foxx"
       + " running under the given mount point");

/** Move Foxx to other Mount
 *
 * Move a running Foxx from one mount point to another
 *
 */
controller.put('/foxx/move/:key', function(req, res) {
  var body = req.body();
  var mountPoint = body.mount;
  var app = body.app;
  var key = req.params("key");
  var prefix = body.prefix;
  var result = foxxes.move(key, app, mountPoint, prefix);
  if (result.error) {
    res.status(result.status);
    res.body = result.message;
    return;
  }
  res.json(result);
})
.summary("Move one foxx to another moint point")
  .notes ("This function moves one installed foxx"
    + " to a given mount point.");

/** Download stored queries
 *
 * Download and export all queries from the given username.
 *
 */

controller.post("/query/upload/:user", function(req, res) {
  var user = req.params("user");
  var response, queries, userColl, storedQueries, queriesToSave;

  queries = req.body();
  userColl = db._users.byExample({"user": user}).toArray()[0];
  queriesToSave = userColl.userData.queries || [ ];

  underscore.each(queries, function(newq) {
    var found = false, i;
    for (i = 0; i < queriesToSave.length; ++i) {
      if (queriesToSave[i].name === newq.name) {
        queriesToSave[i] = newq;
        found = true;
        break;
      }
    }
    if (! found) {
      queriesToSave.push(newq);
    }
  });

  var toUpdate = {
    userData: {
      queries: queriesToSave
    }
  }

  var result = db._users.update(userColl, toUpdate, true);
  res.json(result);
}).summary("Upload user queries")
  .notes("This function uploads all given user queries");

/** Download stored queries
 *
 * Download and export all queries from the given username.
 *
 */

controller.get("/query/download/:user", function(req, res) {
  var user = req.params("user");
  var result = db._users.byExample({"user": user}).toArray()[0];

  res.set("Content-Type", "application/json");
  res.set("Content-Disposition", "attachment; filename=queries.json");

  res.json(result.userData.queries);

}).summary("Download all user queries")
  .notes("This function downloads all user queries from the given user");

/** Download a query result
 *
 * Download and export all queries from the given username.
 *
 */

controller.get("/query/result/download/:query", function(req, res) {
  var query = req.params("query"),
  parsedQuery;

  var internal = require("internal");
  query = internal.base64Decode(query);
  try {
    parsedQuery = JSON.parse(query);
  }
  catch (ignore) {
  }

  var result = db._query(parsedQuery.query, parsedQuery.bindVars).toArray();
  res.set("Content-Type", "application/json");
  res.set("Content-Disposition", "attachment; filename=results.json");
  res.json(result);

}).summary("Download the result of a query")
  .notes("This function downloads the result of a user query.");

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

/// Local Variables:
/// mode: outline-minor
/// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
/// End:
<|endoftext|>