text: /**
   * @param obj
   * @return {Boolean} true if `obj` is a function
   */
  exports.isFunction = function (obj) {
    return Object.prototype.toString.call(obj) === '[object Function]';
  };
  
  /**
   * Simple object extend based on underscore.js's _.extend()
   */
  exports.extend = function (obj) {
    Array.prototype.slice.call(arguments, 1).forEach(function (source) {
      for (var prop in source) {
        obj[prop] = source[prop];
      }
    });
    return obj;
  };
  
  /**
   * Applies a callback to each key-value pair of
   * an object, passing the key and value as parameters
   *
   * Example:
   *  eachPair({a:1, b:2}, function(key, value) { console.log(key, value) })
   *  => a 1
   *  => b 2
   * @param obj The object to iterate
   * @param iterator Iterator function
   */
  exports.eachPair = function (obj, iterator) {
    Object.keys(obj).forEach(function (key) {
      iterator(key, obj[key]);
    });
  };
  
  /**
   * Creates a proxy around a function and turns it into a function that takes a number and a time-unit-name as parameters
   * The proxied function will be applied with the converted amount of milliseconds as first parameter
   *
   * Example:
   *   > var func = withTimeUnit(function(ms) { console.log("Given milliseconds:", ms); });
   *   > func(1, 'minute')
   *   => Given milliseconds: 60000
   *
   *  It also ensures given unit is valid:
   *    > func(1, 'lightyear')
   *  => Error: Unknown unit "lightyear" must be one of [millis, ms, milliseconds, millisecond, s, (...)]
   *
   *  If no unit name is given, milliseconds is assumed
   *
   * @param func The function to wrap
   * @return {Function} The wrapped function
   */
  exports.parseTimeUnitArgs = (function () {
  
    // Supported time units and their associated abbreviations
    var unitsMap = [
      {ms:1, aliases:['millis', 'ms', 'milliseconds', 'millisecond']},
      {ms:1000, aliases:['s', 'sec', 'secs', 'seconds', 'second']},
      {ms:1000 * 60, aliases:['m', 'min', 'mins', 'minutes', 'minute']},
      {ms:1000 * 60 * 60, aliases:['h', 'hours', 'hour']},
      {ms:1000 * 60 * 60 * 24, aliases:['d', 'days', 'day']}
    ].reduce(function (prev, timeUnit) {
          timeUnit.aliases.forEach(function (alias) {
            prev[alias] = timeUnit.ms
          });
          return prev
        }, {});
  
    return function (val, unit) {
      if (unit === undefined && typeof val === "string" && isNan(Number(val))) {
        var match = val.match(/(\d+)\s?(\w+)?/);
        val = match[1];
        unit = match[2];
      }
      if (unit && !unitsMap[unit]) {
        throw new Error('Unknown unit "' + unit + '" must be one of [' + Object.keys(unitsMap).join(", ") + ']');
      }
      return (unit && unitsMap[unit] * val) || val;
    };
  }());
  
  /**
   * Takes a scope object and a function and make sure the function always returns the scope object
   * after its been invoked.
   *
   * Example:
   *  var scope = 1;
   *  var func = chain(scope, function(arg) { console.log(arg); });
   *  func('foo') == scope == 1
   *  => true
   *
   * @param instance The instance object to return at the end of invocation
   * @param func The function to chain
   * @return {Function} The chained function
   */
  exports.chain = function (func) {
    return function () {
      func.apply(this, arguments);
      return this;
    };
  };