diff options
Diffstat (limited to 'module/web')
| -rw-r--r-- | module/web/static/js/default.js | 4 | ||||
| -rw-r--r-- | module/web/static/js/libs/lodash-0.5.2.js (renamed from module/web/static/js/libs/lodash-0.4.2.js) | 2396 | ||||
| -rw-r--r-- | module/web/static/js/libs/require-2.0.6.js (renamed from module/web/static/js/libs/require-2.0.5.js) | 32 | ||||
| -rw-r--r-- | module/web/static/js/models/model.js | 2 | ||||
| -rw-r--r-- | module/web/static/js/plugins/text-2.0.3.js | 308 | ||||
| -rw-r--r-- | module/web/templates/default/base.html | 11 | 
6 files changed, 1755 insertions, 998 deletions
| diff --git a/module/web/static/js/default.js b/module/web/static/js/default.js index 05f8ad1c7..3ec133a87 100644 --- a/module/web/static/js/default.js +++ b/module/web/static/js/default.js @@ -10,11 +10,11 @@ require.config({          flot:"libs/jquery.flot.min",          omniwindow: "libs/jquery.omniwindow", -        underscore:"libs/lodash-0.4.2", +        underscore:"libs/lodash-0.5.2",          backbone:"libs/backbone-0.9.2",          // Require.js Plugins -        text:"plugins/text-2.0.0" +        text:"plugins/text-2.0.3"      }, diff --git a/module/web/static/js/libs/lodash-0.4.2.js b/module/web/static/js/libs/lodash-0.5.2.js index 67806db05..3c5448223 100644 --- a/module/web/static/js/libs/lodash-0.4.2.js +++ b/module/web/static/js/libs/lodash-0.5.2.js @@ -1,5 +1,5 @@  /*! - * Lo-Dash v0.4.2 <http://lodash.com> + * Lo-Dash v0.5.2 <http://lodash.com>   * Copyright 2012 John-David Dalton <http://allyoucanleet.com/>   * Based on Underscore.js 1.3.3, copyright 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.   * <http://documentcloud.github.com/underscore> @@ -39,7 +39,10 @@    /** Native prototype shortcuts */    var ArrayProto = Array.prototype, -      ObjectProto = Object.prototype; +      BoolProto = Boolean.prototype, +      ObjectProto = Object.prototype, +      NumberProto = Number.prototype, +      StringProto = String.prototype;    /** Used to generate unique IDs */    var idCounter = 0; @@ -55,6 +58,9 @@        reEmptyStringMiddle = /\b(__p \+=) '' \+/g,        reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; +  /** Used to match regexp flags from their coerced string values */ +  var reFlags = /\w*$/; +    /** Used to insert the data object variable into compiled template source */    var reInsertVariable = /(?:__e|__t = )\(\s*(?![\d\s"']|this\.)/g; @@ -104,11 +110,13 @@        nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys;    /** `Object#toString` result shortcuts */ -  var arrayClass = '[object Array]', +  var argsClass = '[object Arguments]', +      arrayClass = '[object Array]',        boolClass = '[object Boolean]',        dateClass = '[object Date]',        funcClass = '[object Function]',        numberClass = '[object Number]', +      objectClass = '[object Object]',        regexpClass = '[object RegExp]',        stringClass = '[object String]'; @@ -121,7 +129,26 @@     * In IE < 9 an objects own properties, shadowing non-enumerable ones, are     * made non-enumerable as well.     */ -  var hasDontEnumBug = !propertyIsEnumerable.call({ 'valueOf': 0 }, 'valueOf'); +  var hasDontEnumBug; + +  /** Detect if own properties are iterated after inherited properties (IE < 9) */ +  var iteratesOwnLast; + +  /** Detect if an `arguments` object's indexes are non-enumerable (IE < 9) */ +  var noArgsEnum = true; + +  (function() { +    var props = []; +    function ctor() { this.x = 1; } +    ctor.prototype = { 'valueOf': 1, 'y': 1 }; +    for (var prop in new ctor) { props.push(prop); } +    for (prop in arguments) { noArgsEnum = !prop; } +    hasDontEnumBug = (props + '').length < 4; +    iteratesOwnLast = props[0] != 'x'; +  }(1)); + +  /** Detect if an `arguments` object's [[Class]] is unresolvable (Firefox < 4, IE < 9) */ +  var noArgsClass = !isArguments(arguments);    /** Detect if `Array#slice` cannot be used to convert strings to arrays (Opera < 10.52) */    var noArraySliceOnStrings = slice.call('x')[0] != 'x'; @@ -133,18 +160,47 @@     */    var noCharByIndex = ('x'[0] + Object('x')[0]) != 'xx'; +  /** +   * Detect if a node's [[Class]] is unresolvable (IE < 9) +   * and that the JS engine won't error when attempting to coerce an object to +   * a string without a `toString` property value of `typeof` "function". +   */ +  try { +    var noNodeClass = ({ 'toString': 0 } + '', toString.call(window.document || 0) == objectClass); +  } catch(e) { } +    /* Detect if `Function#bind` exists and is inferred to be fast (all but V8) */    var isBindFast = nativeBind && /\n|Opera/.test(nativeBind + toString.call(window.opera)); -  /* Detect if `Object.keys` exists and is inferred to be fast (V8, Opera, IE) */ +  /* Detect if `Object.keys` exists and is inferred to be fast (IE, Opera, V8) */    var isKeysFast = nativeKeys && /^.+$|true/.test(nativeKeys + !!window.attachEvent);    /** Detect if sourceURL syntax is usable without erroring */    try { -    // Adobe's and Narwhal's JS engines will error -    var useSourceURL = (Function('//@')(), true); +    // The JS engine in Adobe products, like InDesign, will throw a syntax error +    // when it encounters a single line comment beginning with the `@` symbol. +    // The JS engine in Narwhal will generate the function `function anonymous(){//}` +    // and throw a syntax error. In IE, `@` symbols are part of its non-standard +    // conditional compilation support. The `@cc_on` statement activates its support +    // while the trailing ` !` induces a syntax error to exlude it. Compatibility +    // modes in IE > 8 require a space before the `!` to induce a syntax error. +    // See http://msdn.microsoft.com/en-us/library/121hztk3(v=vs.94).aspx +    var useSourceURL = (Function('//@cc_on !')(), true);    } catch(e){ } +  /** Used to identify object classifications that are array-like */ +  var arrayLikeClasses = {}; +  arrayLikeClasses[boolClass] = arrayLikeClasses[dateClass] = arrayLikeClasses[funcClass] = +  arrayLikeClasses[numberClass] = arrayLikeClasses[objectClass] = arrayLikeClasses[regexpClass] = false; +  arrayLikeClasses[argsClass] = arrayLikeClasses[arrayClass] = arrayLikeClasses[stringClass] = true; + +  /** Used to identify object classifications that `_.clone` supports */ +  var cloneableClasses = {}; +  cloneableClasses[argsClass] = cloneableClasses[funcClass] = false; +  cloneableClasses[arrayClass] = cloneableClasses[boolClass] = cloneableClasses[dateClass] = +  cloneableClasses[numberClass] = cloneableClasses[objectClass] = cloneableClasses[regexpClass] = +  cloneableClasses[stringClass] = true; +    /**     * Used to escape characters for inclusion in HTML.     * The `>` and `/` characters don't require escaping in HTML and have no @@ -165,7 +221,8 @@      'object': true,      'number': false,      'string': false, -    'undefined': false +    'undefined': false, +    'unknown': true    };    /** Used to escape characters for inclusion in compiled string literals */ @@ -210,8 +267,9 @@    }    /** -   * By default, Lo-Dash uses embedded Ruby (ERB) style template delimiters, -   * change the following template settings to use alternative delimiters. +   * By default, the template delimiters used by Lo-Dash are similar to those in +   * embedded Ruby (ERB). Change the following template settings to use alternative +   * delimiters.     *     * @static     * @memberOf _ @@ -253,7 +311,7 @@       * @memberOf _.templateSettings       * @type String       */ -    'variable': 'obj' +    'variable': ''    };    /*--------------------------------------------------------------------------*/ @@ -267,10 +325,10 @@     */    var iteratorTemplate = template(      // conditional strict mode -   '<% if (useStrict) { %>\'use strict\';\n<% } %>' + +    '<% if (useStrict) { %>\'use strict\';\n<% } %>' +      // the `iteratee` may be reassigned by the `top` snippet -    'var index, iteratee = <%= firstArg %>, ' + +    'var index, value, iteratee = <%= firstArg %>, ' +      // assign the `result` variable an initial value      'result<% if (init) { %> = <%= init %><% } %>;\n' +      // add code to exit early or do so if the first argument is falsey @@ -281,7 +339,7 @@      // the following branch is for iterating arrays and array-like objects      '<% if (arrayBranch) { %>' +      'var length = iteratee.length; index = -1;' + -    '  <% if (objectBranch) { %>\nif (length === length >>> 0) {<% } %>' + +    '  <% if (objectBranch) { %>\nif (length > -1 && length === length >>> 0) {<% } %>' +      // add support for accessing string characters by index if needed      '  <% if (noCharByIndex) { %>\n' + @@ -292,6 +350,7 @@      '  <%= arrayBranch.beforeLoop %>;\n' +      '  while (++index < length) {\n' + +    '    value = iteratee[index];\n' +      '    <%= arrayBranch.inLoop %>\n' +      '  }' +      '  <% if (objectBranch) { %>\n}<% } %>' + @@ -299,7 +358,19 @@      // the following branch is for iterating an object's own/inherited properties      '<% if (objectBranch) { %>' + -    '  <% if (arrayBranch) { %>\nelse {<% } %>' + +    '  <% if (arrayBranch) { %>\nelse {' + + +    // add support for iterating over `arguments` objects if needed +    '  <%  } else if (noArgsEnum) { %>\n' + +    '  var length = iteratee.length; index = -1;\n' + +    '  if (length && isArguments(iteratee)) {\n' + +    '    while (++index < length) {\n' + +    '      value = iteratee[index += \'\'];\n' + +    '      <%= objectBranch.inLoop %>\n' + +    '    }\n' + +    '  } else {' + +    '  <% } %>' + +      '  <% if (!hasDontEnumBug) { %>\n' +      '  var skipProto = typeof iteratee == \'function\' && \n' +      '    propertyIsEnumerable.call(iteratee, \'prototype\');\n' + @@ -307,15 +378,16 @@      // iterate own properties using `Object.keys` if it's fast      '  <% if (isKeysFast && useHas) { %>\n' + -    '  var props = nativeKeys(iteratee),\n' + -    '      propIndex = -1,\n' + -    '      length = props.length;\n\n' + +    '  var ownIndex = -1,\n' + +    '      ownProps = objectTypes[typeof iteratee] ? nativeKeys(iteratee) : [],\n' + +    '      length = ownProps.length;\n\n' +      '  <%= objectBranch.beforeLoop %>;\n' + -    '  while (++propIndex < length) {\n' + -    '    index = props[propIndex];\n' + -    '    if (!(skipProto && index == \'prototype\')) {\n' + -    '      <%= objectBranch.inLoop %>\n' + -    '    }\n' + +    '  while (++ownIndex < length) {\n' + +    '    index = ownProps[ownIndex];\n' + +    '    <% if (!hasDontEnumBug) { %>if (!(skipProto && index == \'prototype\')) {\n  <% } %>' + +    '    value = iteratee[index];\n' + +    '    <%= objectBranch.inLoop %>\n' + +    '    <% if (!hasDontEnumBug) { %>}\n<% } %>' +      '  }' +      // else using a for-in loop @@ -324,9 +396,9 @@      '  for (index in iteratee) {' +      '    <% if (hasDontEnumBug) { %>\n' +      '    <%   if (useHas) { %>if (hasOwnProperty.call(iteratee, index)) {\n  <% } %>' + +    '    value = iteratee[index];\n' +      '    <%= objectBranch.inLoop %>;\n' +      '    <%   if (useHas) { %>}<% } %>' + -    '    <% } else { %>\n' +      // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1      // (if the prototype or a property on the prototype has been set) @@ -334,8 +406,10 @@      // value to `true`. Because of this Lo-Dash standardizes on skipping      // the the `prototype` property of functions regardless of its      // [[Enumerable]] value. +    '    <% } else { %>\n' +      '    if (!(skipProto && index == \'prototype\')<% if (useHas) { %> &&\n' +      '        hasOwnProperty.call(iteratee, index)<% } %>) {\n' + +    '      value = iteratee[index];\n' +      '      <%= objectBranch.inLoop %>\n' +      '    }' +      '    <% } %>\n' + @@ -354,11 +428,12 @@      '      if (shadowed[k] == \'constructor\') {' +      '        %>!(ctor && ctor.prototype === iteratee) && <%' +      '      } %>hasOwnProperty.call(iteratee, index)) {\n' + +    '    value = iteratee[index];\n' +      '    <%= objectBranch.inLoop %>\n' +      '  }' +      '    <% } %>' +      '  <% } %>' + -    '  <% if (arrayBranch) { %>\n}<% } %>' + +    '  <% if (arrayBranch || noArgsEnum) { %>\n}<% } %>' +      '<% } %>\n' +      // add code to the bottom of the iteration function @@ -382,13 +457,30 @@        'else if (thisArg) {\n' +        '  callback = iteratorBind(callback, thisArg)\n' +        '}', -    'inLoop': 'callback(iteratee[index], index, collection)' +    'inLoop': 'if (callback(value, index, collection) === false) return result' +  }; + +  /** Reusable iterator options for `countBy`, `groupBy`, and `sortBy` */ +  var countByIteratorOptions = { +    'init': '{}', +    'top': +      'var prop;\n' + +      'if (typeof callback != \'function\') {\n' + +      '  var valueProp = callback;\n' + +      '  callback = function(value) { return value[valueProp] }\n' + +      '}\n' + +      'else if (thisArg) {\n' + +      '  callback = iteratorBind(callback, thisArg)\n' + +      '}', +    'inLoop': +      'prop = callback(value, index, collection);\n' + +      '(hasOwnProperty.call(result, prop) ? result[prop]++ : result[prop] = 1)'    };    /** Reusable iterator options for `every` and `some` */    var everyIteratorOptions = {      'init': 'true', -    'inLoop': 'if (!callback(iteratee[index], index, collection)) return !result' +    'inLoop': 'if (!callback(value, index, collection)) return !result'    };    /** Reusable iterator options for `defaults` and `extend` */ @@ -398,17 +490,16 @@      'args': 'object',      'init': 'object',      'top': -      'for (var iterateeIndex = 1, length = arguments.length; iterateeIndex < length; iterateeIndex++) {\n' + -      '  iteratee = arguments[iterateeIndex];\n' + -      (hasDontEnumBug ? '  if (iteratee) {' : ''), -    'inLoop': 'result[index] = iteratee[index]', -    'bottom': (hasDontEnumBug ? '  }\n' : '') + '}' +      'for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {\n' + +      '  if (iteratee = arguments[argsIndex]) {', +    'inLoop': 'result[index] = value', +    'bottom': '  }\n}'    }; -  /** Reusable iterator options for `filter` and `reject` */ +  /** Reusable iterator options for `filter`, `reject`, and `where` */    var filterIteratorOptions = {      'init': '[]', -    'inLoop': 'callback(iteratee[index], index, collection) && result.push(iteratee[index])' +    'inLoop': 'callback(value, index, collection) && result.push(value)'    };    /** Reusable iterator options for `find`, `forEach`, `forIn`, and `forOwn` */ @@ -432,8 +523,8 @@        'object': 'result = ' + (isKeysFast ? 'Array(length)' : '[]')      },      'inLoop': { -      'array':  'result[index] = callback(iteratee[index], index, collection)', -      'object': 'result' + (isKeysFast ? '[propIndex] = ' : '.push') + '(callback(iteratee[index], index, collection))' +      'array':  'result[index] = callback(value, index, collection)', +      'object': 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '(callback(value, index, collection))'      }    }; @@ -554,6 +645,7 @@      data.firstArg = firstArg;      data.hasDontEnumBug = hasDontEnumBug;      data.isKeysFast = isKeysFast; +    data.noArgsEnum = noArgsEnum;      data.shadowed = shadowed;      data.useHas = data.useHas !== false;      data.useStrict = data.useStrict !== false; @@ -569,29 +661,35 @@      }      // create the function factory      var factory = Function( -        'arrayClass, bind, compareAscending, funcClass, hasOwnProperty, identity, ' + -        'iteratorBind, objectTypes, nativeKeys, propertyIsEnumerable, slice, ' + -        'stringClass, toString', -      'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}' +        'arrayLikeClasses, ArrayProto, bind, compareAscending, concat, forIn, ' + +        'hasOwnProperty, identity, indexOf, isArguments, isArray, isFunction, ' + +        'isPlainObject, iteratorBind, objectClass, objectTypes, nativeKeys, ' + +        'propertyIsEnumerable, slice, stringClass, toString', +      'var callee = function(' + args + ') {\n' + iteratorTemplate(data) + '\n};\n' + +      'return callee'      );      // return the compiled function      return factory( -      arrayClass, bind, compareAscending, funcClass, hasOwnProperty, identity, -      iteratorBind, objectTypes, nativeKeys, propertyIsEnumerable, slice, -      stringClass, toString +      arrayLikeClasses, ArrayProto, bind, compareAscending, concat, forIn, +      hasOwnProperty, identity, indexOf, isArguments, isArray, isFunction, +      isPlainObject, iteratorBind, objectClass, objectTypes, nativeKeys, +      propertyIsEnumerable, slice, stringClass, toString      );    }    /** -   * Used by `sortBy` to compare transformed values of `collection`, sorting +   * Used by `sortBy` to compare transformed `collection` values, stable sorting     * them in ascending order.     *     * @private     * @param {Object} a The object to compare to `b`.     * @param {Object} b The object to compare to `a`. -   * @returns {Number} Returns `-1` if `a` < `b`, `0` if `a` == `b`, or `1` if `a` > `b`. +   * @returns {Number} Returns the sort order indicator of `1` or `-1`.     */    function compareAscending(a, b) { +    var ai = a.index, +        bi = b.index; +      a = a.criteria;      b = b.criteria; @@ -601,7 +699,9 @@      if (b === undefined) {        return -1;      } -    return a < b ? -1 : a > b ? 1 : 0; +    // ensure a stable sort in V8 and other engines +    // http://code.google.com/p/v8/issues/detail?id=90 +    return a < b ? -1 : a > b ? 1 : ai < bi ? -1 : 1;    }    /** @@ -640,6 +740,51 @@    }    /** +   * Checks if a given `value` is an object created by the `Object` constructor +   * assuming objects created by the `Object` constructor have no inherited +   * enumerable properties and that there are no `Object.prototype` extensions. +   * +   * @private +   * @param {Mixed} value The value to check. +   * @param {Boolean} [skipArgsCheck=false] Internally used to skip checks for +   *  `arguments` objects. +   * @returns {Boolean} Returns `true` if the `value` is a plain `Object` object, +   *  else `false`. +   */ +  function isPlainObject(value, skipArgsCheck) { +    // avoid non-objects and false positives for `arguments` objects +    var result = false; +    if (!(value && typeof value == 'object') || (!skipArgsCheck && isArguments(value))) { +      return result; +    } +    // IE < 9 presents DOM nodes as `Object` objects except they have `toString` +    // methods that are `typeof` "string" and still can coerce nodes to strings. +    // Also check that the constructor is `Object` (i.e. `Object instanceof Object`) +    var ctor = value.constructor; +    if ((!noNodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) && +        (!isFunction(ctor) || ctor instanceof ctor)) { +      // IE < 9 iterates inherited properties before own properties. If the first +      // iterated property is an object's own property then there are no inherited +      // enumerable properties. +      if (iteratesOwnLast) { +        forIn(value, function(objValue, objKey) { +          result = !hasOwnProperty.call(value, objKey); +          return false; +        }); +        return result === false; +      } +      // In most environments an object's own properties are iterated before +      // its inherited properties. If the last iterated property is an object's +      // own property then there are no inherited enumerable properties. +      forIn(value, function(objValue, objKey) { +        result = objKey; +      }); +      return result === false || hasOwnProperty.call(value, result); +    } +    return result; +  } + +  /**     * Creates a new function that, when called, invokes `func` with the `this`     * binding of `thisArg` and the arguments (value, index, object).     * @@ -664,21 +809,6 @@    }    /** -   * A shim implementation of `Object.keys` that produces an array of the given -   * object's own enumerable property names. -   * -   * @private -   * @param {Object} object The object to inspect. -   * @returns {Array} Returns a new array of property names. -   */ -  var shimKeys = createIterator({ -    'args': 'object', -    'exit': 'if (!(object && objectTypes[typeof object])) throw TypeError()', -    'init': '[]', -    'inLoop': 'result.push(index)' -  }); - -  /**     * Used by `template` to replace "escape" template delimiters with tokens.     *     * @private @@ -687,7 +817,7 @@     * @returns {String} Returns a token.     */    function tokenizeEscape(match, value) { -    if (reComplexDelimiter.test(value)) { +    if (match && reComplexDelimiter.test(value)) {        return '<e%-' + value + '%>';      }      var index = tokenized.length; @@ -701,21 +831,20 @@     *     * @private     * @param {String} match The matched template delimiter. -   * @param {String} value The delimiter value. -   * @param {String} escapeValue The "escape" delimiter value. -   * @param {String} interpolateValue The "interpolate" delimiter value. +   * @param {String} escapeValue The complex "escape" delimiter value. +   * @param {String} interpolateValue The complex "interpolate" delimiter value. +   * @param {String} [evaluateValue] The "evaluate" delimiter value.     * @returns {String} Returns a token.     */ -  function tokenizeEvaluate(match, value, escapeValue, interpolateValue) { -    var index = tokenized.length; -    if (value) { -      tokenized[index] = "';\n" + value + ";\n__p += '" -    } else if (escapeValue) { -      tokenized[index] = "' +\n__e(" + escapeValue + ") +\n'"; -    } else if (interpolateValue) { -      tokenized[index] = "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'"; +  function tokenizeEvaluate(match, escapeValue, interpolateValue, evaluateValue) { +    if (evaluateValue) { +      var index = tokenized.length; +      tokenized[index] = "';\n" + evaluateValue + ";\n__p += '"; +      return token + index;      } -    return token + index; +    return escapeValue +      ? tokenizeEscape(null, escapeValue) +      : tokenizeInterpolate(null, interpolateValue);    }    /** @@ -727,7 +856,7 @@     * @returns {String} Returns a token.     */    function tokenizeInterpolate(match, value) { -    if (reComplexDelimiter.test(value)) { +    if (match && reComplexDelimiter.test(value)) {        return '<e%=' + value + '%>';      }      var index = tokenized.length; @@ -738,7 +867,990 @@    /*--------------------------------------------------------------------------*/    /** -   * Checks if a given `target` value is present in a `collection` using strict +   * Checks if `value` is an `arguments` object. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is an `arguments` object, else `false`. +   * @example +   * +   * (function() { return _.isArguments(arguments); })(1, 2, 3); +   * // => true +   * +   * _.isArguments([1, 2, 3]); +   * // => false +   */ +  function isArguments(value) { +    return toString.call(value) == argsClass; +  } +  // fallback for browsers that can't detect `arguments` objects by [[Class]] +  if (noArgsClass) { +    isArguments = function(value) { +      return !!(value && hasOwnProperty.call(value, 'callee')); +    }; +  } + +  /** +   * Checks if `value` is an array. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is an array, else `false`. +   * @example +   * +   * (function() { return _.isArray(arguments); })(); +   * // => false +   * +   * _.isArray([1, 2, 3]); +   * // => true +   */ +  var isArray = nativeIsArray || function(value) { +    return toString.call(value) == arrayClass; +  }; + +  /** +   * Checks if `value` is a function. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is a function, else `false`. +   * @example +   * +   * _.isFunction(''.concat); +   * // => true +   */ +  function isFunction(value) { +    return typeof value == 'function'; +  } +  // fallback for older versions of Chrome and Safari +  if (isFunction(/x/)) { +    isFunction = function(value) { +      return toString.call(value) == funcClass; +    }; +  } + +  /** +   * A shim implementation of `Object.keys` that produces an array of the given +   * object's own enumerable property names. +   * +   * @private +   * @param {Object} object The object to inspect. +   * @returns {Array} Returns a new array of property names. +   */ +  var shimKeys = createIterator({ +    'args': 'object', +    'init': '[]', +    'inLoop': 'result.push(index)' +  }); + +  /*--------------------------------------------------------------------------*/ + +  /** +   * Creates a clone of `value`. If `deep` is `true`, all nested objects will +   * also be cloned otherwise they will be assigned by reference. If a value has +   * a `clone` method it will be used to perform the clone. Functions, DOM nodes, +   * `arguments` objects, and objects created by constructors other than `Object` +   * are **not** cloned unless they have a custom `clone` method. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to clone. +   * @param {Boolean} deep A flag to indicate a deep clone. +   * @param {Object} [guard] Internally used to allow this method to work with +   *  others like `_.map` without using their callback `index` argument for `deep`. +   * @param {Array} [stack=[]] Internally used to keep track of traversed objects +   *  to avoid circular references. +   * @param {Object} thorough Internally used to indicate whether or not to perform +   *  a more thorough clone of non-object values. +   * @returns {Mixed} Returns the cloned `value`. +   * @example +   * +   * var stooges = [ +   *   { 'name': 'moe', 'age': 40 }, +   *   { 'name': 'larry', 'age': 50 }, +   *   { 'name': 'curly', 'age': 60 } +   * ]; +   * +   * _.clone({ 'name': 'moe' }); +   * // => { 'name': 'moe' } +   * +   * var shallow = _.clone(stooges); +   * shallow[0] === stooges[0]; +   * // => true +   * +   * var deep = _.clone(stooges, true); +   * shallow[0] === stooges[0]; +   * // => false +   */ +  function clone(value, deep, guard, stack, thorough) { +    if (value == null) { +      return value; +    } +    if (guard) { +      deep = false; +    } +    // avoid slower checks on primitives +    thorough || (thorough = { 'value': null }); +    if (thorough.value == null) { +      // primitives passed from iframes use the primary document's native prototypes +      thorough.value = !!(BoolProto.clone || NumberProto.clone || StringProto.clone); +    } +    // use custom `clone` method if available +    var isObj = objectTypes[typeof value]; +    if ((isObj || thorough.value) && value.clone && isFunction(value.clone)) { +      thorough.value = null; +      return value.clone(deep); +    } +    // inspect [[Class]] +    if (isObj) { +      // don't clone `arguments` objects, functions, or non-object Objects +      var className = toString.call(value); +      if (!cloneableClasses[className] || (noArgsClass && isArguments(value))) { +        return value; +      } +      var isArr = className == arrayClass; +      isObj = isArr || (className == objectClass ? isPlainObject(value, true) : isObj); +    } +    // shallow clone +    if (!isObj || !deep) { +      // don't clone functions +      return isObj +        ? (isArr ? slice.call(value) : extend({}, value)) +        : value; +    } + +    var ctor = value.constructor; +    switch (className) { +      case boolClass: +        return new ctor(value == true); + +      case dateClass: +        return new ctor(+value); + +      case numberClass: +      case stringClass: +        return new ctor(value); + +      case regexpClass: +        return ctor(value.source, reFlags.exec(value)); +    } + +    // check for circular references and return corresponding clone +    stack || (stack = []); +    var length = stack.length; +    while (length--) { +      if (stack[length].source == value) { +        return stack[length].value; +      } +    } + +    // init cloned object +    length = value.length; +    var result = isArr ? ctor(length) : {}; + +    // add current clone and original source value to the stack of traversed objects +    stack.push({ 'value': result, 'source': value }); + +    // recursively populate clone (susceptible to call stack limits) +    if (isArr) { +      var index = -1; +      while (++index < length) { +        result[index] = clone(value[index], deep, null, stack, thorough); +      } +    } else { +      forOwn(value, function(objValue, key) { +        result[key] = clone(objValue, deep, null, stack, thorough); +      }); +    } +    return result; +  } + +  /** +   * Assigns enumerable properties of the default object(s) to the `destination` +   * object for all `destination` properties that resolve to `null`/`undefined`. +   * Once a property is set, additional defaults of the same property will be +   * ignored. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Object} object The destination object. +   * @param {Object} [default1, default2, ...] The default objects. +   * @returns {Object} Returns the destination object. +   * @example +   * +   * var iceCream = { 'flavor': 'chocolate' }; +   * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' }); +   * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' } +   */ +  var defaults = createIterator(extendIteratorOptions, { +    'inLoop': 'if (result[index] == null) ' + extendIteratorOptions.inLoop +  }); + +  /** +   * Creates a shallow clone of `object` excluding the specified properties. +   * Property names may be specified as individual arguments or as arrays of +   * property names. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Object} object The source object. +   * @param {Object} [prop1, prop2, ...] The properties to drop. +   * @returns {Object} Returns an object without the dropped properties. +   * @example +   * +   * _.drop({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'userid'); +   * // => { 'name': 'moe', 'age': 40 } +   */ +  var drop = createIterator({ +    'useHas': false, +    'args': 'object', +    'init': '{}', +    'top': 'var props = concat.apply(ArrayProto, arguments)', +    'inLoop': 'if (indexOf(props, index) < 0) result[index] = value' +  }); + +  /** +   * Assigns enumerable properties of the source object(s) to the `destination` +   * object. Subsequent sources will overwrite propery assignments of previous +   * sources. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Object} object The destination object. +   * @param {Object} [source1, source2, ...] The source objects. +   * @returns {Object} Returns the destination object. +   * @example +   * +   * _.extend({ 'name': 'moe' }, { 'age': 40 }); +   * // => { 'name': 'moe', 'age': 40 } +   */ +  var extend = createIterator(extendIteratorOptions); + +  /** +   * Iterates over `object`'s own and inherited enumerable properties, executing +   * the `callback` for each property. The `callback` is bound to `thisArg` and +   * invoked with 3 arguments; (value, key, object). Callbacks may exit iteration +   * early by explicitly returning `false`. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Object} object The object to iterate over. +   * @param {Function} callback The function called per iteration. +   * @param {Mixed} [thisArg] The `this` binding for the callback. +   * @returns {Object} Returns `object`. +   * @example +   * +   * function Dog(name) { +   *   this.name = name; +   * } +   * +   * Dog.prototype.bark = function() { +   *   alert('Woof, woof!'); +   * }; +   * +   * _.forIn(new Dog('Dagny'), function(value, key) { +   *   alert(key); +   * }); +   * // => alerts 'name' and 'bark' (order is not guaranteed) +   */ +  var forIn = createIterator(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions, { +    'useHas': false +  }); + +  /** +   * Iterates over `object`'s own enumerable properties, executing the `callback` +   * for each property. The `callback` is bound to `thisArg` and invoked with 3 +   * arguments; (value, key, object). Callbacks may exit iteration early by +   * explicitly returning `false`. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Object} object The object to iterate over. +   * @param {Function} callback The function called per iteration. +   * @param {Mixed} [thisArg] The `this` binding for the callback. +   * @returns {Object} Returns `object`. +   * @example +   * +   * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { +   *   alert(key); +   * }); +   * // => alerts '0', '1', and 'length' (order is not guaranteed) +   */ +  var forOwn = createIterator(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions); + +  /** +   * Creates a sorted array of all enumerable properties, own and inherited, +   * of `object` that have function values. +   * +   * @static +   * @memberOf _ +   * @alias methods +   * @category Objects +   * @param {Object} object The object to inspect. +   * @returns {Array} Returns a new array of property names that have function values. +   * @example +   * +   * _.functions(_); +   * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] +   */ +  var functions = createIterator({ +    'useHas': false, +    'args': 'object', +    'init': '[]', +    'inLoop': 'if (isFunction(value)) result.push(index)', +    'bottom': 'result.sort()' +  }); + +  /** +   * Checks if the specified object `property` exists and is a direct property, +   * instead of an inherited property. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Object} object The object to check. +   * @param {String} property The property to check for. +   * @returns {Boolean} Returns `true` if key is a direct property, else `false`. +   * @example +   * +   * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); +   * // => true +   */ +  function has(object, property) { +    return object ? hasOwnProperty.call(object, property) : false; +  } + +  /** +   * Checks if `value` is a boolean (`true` or `false`) value. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is a boolean value, else `false`. +   * @example +   * +   * _.isBoolean(null); +   * // => false +   */ +  function isBoolean(value) { +    return value === true || value === false || toString.call(value) == boolClass; +  } + +  /** +   * Checks if `value` is a date. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is a date, else `false`. +   * @example +   * +   * _.isDate(new Date); +   * // => true +   */ +  function isDate(value) { +    return toString.call(value) == dateClass; +  } + +  /** +   * Checks if `value` is a DOM element. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is a DOM element, else `false`. +   * @example +   * +   * _.isElement(document.body); +   * // => true +   */ +  function isElement(value) { +    return value ? value.nodeType === 1 : false; +  } + +  /** +   * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a +   * length of `0` and objects with no own enumerable properties are considered +   * "empty". +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Array|Object|String} value The value to inspect. +   * @returns {Boolean} Returns `true` if the `value` is empty, else `false`. +   * @example +   * +   * _.isEmpty([1, 2, 3]); +   * // => false +   * +   * _.isEmpty({}); +   * // => true +   * +   * _.isEmpty(''); +   * // => true +   */ +  var isEmpty = createIterator({ +    'args': 'value', +    'init': 'true', +    'top': +      'var className = toString.call(value),\n' + +      '    length = value.length;\n' + +      'if (arrayLikeClasses[className]' + +      (noArgsClass ? ' || isArguments(value)' : '') + ' ||\n' + +      '  (className == objectClass && length > -1 && length === length >>> 0 &&\n' + +      '  isFunction(value.splice))' + +      ') return !length', +    'inLoop': { +      'object': 'return false' +    } +  }); + +  /** +   * Performs a deep comparison between two values to determine if they are +   * equivalent to each other. If a value has an `isEqual` method it will be +   * used to perform the comparison. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} a The value to compare. +   * @param {Mixed} b The other value to compare. +   * @param {Array} [stack=[]] Internally used to keep track of traversed objects +   *  to avoid circular references. +   * @param {Object} thorough Internally used to indicate whether or not to perform +   *  a more thorough comparison of non-object values. +   * @returns {Boolean} Returns `true` if the values are equvalent, else `false`. +   * @example +   * +   * var moe = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; +   * var clone = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; +   * +   * moe == clone; +   * // => false +   * +   * _.isEqual(moe, clone); +   * // => true +   */ +  function isEqual(a, b, stack, thorough) { +    // a strict comparison is necessary because `null == undefined` +    if (a == null || b == null) { +      return a === b; +    } +    // avoid slower checks on non-objects +    thorough || (thorough = { 'value': null }); +    if (thorough.value == null) { +      // primitives passed from iframes use the primary document's native prototypes +      thorough.value = !!(BoolProto.isEqual || NumberProto.isEqual || StringProto.isEqual); +    } +    if (objectTypes[typeof a] || objectTypes[typeof b] || thorough.value) { +      // unwrap any LoDash wrapped values +      if (a._chain) { +        a = a._wrapped; +      } +      if (b._chain) { +        b = b._wrapped; +      } +      // use custom `isEqual` method if available +      if (a.isEqual && isFunction(a.isEqual)) { +        thorough.value = null; +        return a.isEqual(b); +      } +      if (b.isEqual && isFunction(b.isEqual)) { +        thorough.value = null; +        return b.isEqual(a); +      } +    } +    // exit early for identical values +    if (a === b) { +      // treat `+0` vs. `-0` as not equal +      return a !== 0 || (1 / a == 1 / b); +    } +    // compare [[Class]] names +    var className = toString.call(a); +    if (className != toString.call(b)) { +      return false; +    } +    switch (className) { +      case boolClass: +      case dateClass: +        // coerce dates and booleans to numbers, dates to milliseconds and booleans +        // to `1` or `0`, treating invalid dates coerced to `NaN` as not equal +        return +a == +b; + +      case numberClass: +        // treat `NaN` vs. `NaN` as equal +        return a != +a +          ? b != +b +          // but treat `+0` vs. `-0` as not equal +          : (a == 0 ? (1 / a == 1 / b) : a == +b); + +      case regexpClass: +      case stringClass: +        // coerce regexes to strings (http://es5.github.com/#x15.10.6.4) +        // treat string primitives and their corresponding object instances as equal +        return a == b + ''; +    } +    // exit early, in older browsers, if `a` is array-like but not `b` +    var isArr = arrayLikeClasses[className]; +    if (noArgsClass && !isArr && (isArr = isArguments(a)) && !isArguments(b)) { +      return false; +    } +    // exit for functions and DOM nodes +    if (!isArr && (className != objectClass || (noNodeClass && ( +        (typeof a.toString != 'function' && typeof (a + '') == 'string') || +        (typeof b.toString != 'function' && typeof (b + '') == 'string'))))) { +      return false; +    } + +    // assume cyclic structures are equal +    // the algorithm for detecting cyclic structures is adapted from ES 5.1 +    // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3) +    stack || (stack = []); +    var length = stack.length; +    while (length--) { +      if (stack[length] == a) { +        return true; +      } +    } + +    var index = -1, +        result = true, +        size = 0; + +    // add `a` to the stack of traversed objects +    stack.push(a); + +    // recursively compare objects and arrays (susceptible to call stack limits) +    if (isArr) { +      // compare lengths to determine if a deep comparison is necessary +      size = a.length; +      result = size == b.length; + +      if (result) { +        // deep compare the contents, ignoring non-numeric properties +        while (size--) { +          if (!(result = isEqual(a[size], b[size], stack, thorough))) { +            break; +          } +        } +      } +      return result; +    } + +    var ctorA = a.constructor, +        ctorB = b.constructor; + +    // non `Object` object instances with different constructors are not equal +    if (ctorA != ctorB && !( +          isFunction(ctorA) && ctorA instanceof ctorA && +          isFunction(ctorB) && ctorB instanceof ctorB +        )) { +      return false; +    } +    // deep compare objects +    for (var prop in a) { +      if (hasOwnProperty.call(a, prop)) { +        // count the number of properties. +        size++; +        // deep compare each property value. +        if (!(hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stack, thorough))) { +          return false; +        } +      } +    } +    // ensure both objects have the same number of properties +    for (prop in b) { +      // The JS engine in Adobe products, like InDesign, has a bug that causes +      // `!size--` to throw an error so it must be wrapped in parentheses. +      // https://github.com/documentcloud/underscore/issues/355 +      if (hasOwnProperty.call(b, prop) && !(size--)) { +        // `size` will be `-1` if `b` has more properties than `a` +        return false; +      } +    } +    // handle JScript [[DontEnum]] bug +    if (hasDontEnumBug) { +      while (++index < 7) { +        prop = shadowed[index]; +        if (hasOwnProperty.call(a, prop) && +            !(hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stack, thorough))) { +          return false; +        } +      } +    } +    return true; +  } + +  /** +   * Checks if `value` is a finite number. +   * +   * Note: This is not the same as native `isFinite`, which will return true for +   * booleans and other values. See http://es5.github.com/#x15.1.2.5. +   * +   * @deprecated +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is a finite number, else `false`. +   * @example +   * +   * _.isFinite(-101); +   * // => true +   * +   * _.isFinite('10'); +   * // => false +   * +   * _.isFinite(Infinity); +   * // => false +   */ +  function isFinite(value) { +    return nativeIsFinite(value) && toString.call(value) == numberClass; +  } + +  /** +   * Checks if `value` is the language type of Object. +   * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is an object, else `false`. +   * @example +   * +   * _.isObject({}); +   * // => true +   * +   * _.isObject(1); +   * // => false +   */ +  function isObject(value) { +    // check if the value is the ECMAScript language type of Object +    // http://es5.github.com/#x8 +    // and avoid a V8 bug +    // http://code.google.com/p/v8/issues/detail?id=2291 +    return value ? objectTypes[typeof value] : false; +  } + +  /** +   * Checks if `value` is `NaN`. +   * +   * Note: This is not the same as native `isNaN`, which will return true for +   * `undefined` and other values. See http://es5.github.com/#x15.1.2.4. +   * +   * @deprecated +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is `NaN`, else `false`. +   * @example +   * +   * _.isNaN(NaN); +   * // => true +   * +   * _.isNaN(new Number(NaN)); +   * // => true +   * +   * isNaN(undefined); +   * // => true +   * +   * _.isNaN(undefined); +   * // => false +   */ +  function isNaN(value) { +    // `NaN` as a primitive is the only value that is not equal to itself +    // (perform the [[Class]] check first to avoid errors with some host objects in IE) +    return toString.call(value) == numberClass && value != +value +  } + +  /** +   * Checks if `value` is `null`. +   * +   * @deprecated +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is `null`, else `false`. +   * @example +   * +   * _.isNull(null); +   * // => true +   * +   * _.isNull(undefined); +   * // => false +   */ +  function isNull(value) { +    return value === null; +  } + +  /** +   * Checks if `value` is a number. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is a number, else `false`. +   * @example +   * +   * _.isNumber(8.4 * 5; +   * // => true +   */ +  function isNumber(value) { +    return toString.call(value) == numberClass; +  } + +  /** +   * Checks if `value` is a regular expression. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is a regular expression, else `false`. +   * @example +   * +   * _.isRegExp(/moe/); +   * // => true +   */ +  function isRegExp(value) { +    return toString.call(value) == regexpClass; +  } + +  /** +   * Checks if `value` is a string. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is a string, else `false`. +   * @example +   * +   * _.isString('moe'); +   * // => true +   */ +  function isString(value) { +    return toString.call(value) == stringClass; +  } + +  /** +   * Checks if `value` is `undefined`. +   * +   * @deprecated +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Mixed} value The value to check. +   * @returns {Boolean} Returns `true` if the `value` is `undefined`, else `false`. +   * @example +   * +   * _.isUndefined(void 0); +   * // => true +   */ +  function isUndefined(value) { +    return value === undefined; +  } + +  /** +   * Creates an array composed of the own enumerable property names of `object`. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Object} object The object to inspect. +   * @returns {Array} Returns a new array of property names. +   * @example +   * +   * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); +   * // => ['one', 'two', 'three'] (order is not guaranteed) +   */ +  var keys = !nativeKeys ? shimKeys : function(object) { +    var type = typeof object; + +    // avoid iterating over the `prototype` property +    if (type == 'function' && propertyIsEnumerable.call(object, 'prototype')) { +      return shimKeys(object); +    } +    return object && objectTypes[type] +      ? nativeKeys(object) +      : []; +  }; + +  /** +   * Merges enumerable properties of the source object(s) into the `destination` +   * object. Subsequent sources will overwrite propery assignments of previous +   * sources. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Object} object The destination object. +   * @param {Object} [source1, source2, ...] The source objects. +   * @param {Object} [indicator] Internally used to indicate that the `stack` +   *  argument is an array of traversed objects instead of another source object. +   * @param {Array} [stack=[]] Internally used to keep track of traversed objects +   *  to avoid circular references. +   * @returns {Object} Returns the destination object. +   * @example +   * +   * var stooges = [ +   *   { 'name': 'moe' }, +   *   { 'name': 'larry' } +   * ]; +   * +   * var ages = [ +   *   { 'age': 40 }, +   *   { 'age': 50 } +   * ]; +   * +   * _.merge(stooges, ages); +   * // => [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] +   */ +  var merge = createIterator(extendIteratorOptions, { +    'args': 'object, source, indicator, stack', +    'top': +      'var destValue, found, isArr, stackLength, recursive = indicator == isPlainObject;\n' + +      'if (!recursive) stack = [];\n' + +      'for (var argsIndex = 1, argsLength = recursive ? 2 : arguments.length; argsIndex < argsLength; argsIndex++) {\n' + +      '  if (iteratee = arguments[argsIndex]) {', +    'inLoop': +      'if (value && ((isArr = isArray(value)) || isPlainObject(value))) {\n' + +      '  found = false; stackLength = stack.length;\n' + +      '  while (stackLength--) {\n' + +      '    if (found = stack[stackLength].source == value) break\n' + +      '  }\n' + +      '  if (found) {\n' + +      '    result[index] = stack[stackLength].value\n' + +      '  } else {\n' + +      '    destValue = (destValue = result[index]) && isArr\n' + +      '      ? (isArray(destValue) ? destValue : [])\n' + +      '      : (isPlainObject(destValue) ? destValue : {});\n' + +      '    stack.push({ value: destValue, source: value });\n' + +      '    result[index] = callee(destValue, value, isPlainObject, stack)\n' + +      '  }\n' + +      '} else if (value != null) {\n' + +      '  result[index] = value\n' + +      '}' +  }); + +  /** +   * Creates a shallow clone of `object` composed of the specified properties. +   * Property names may be specified as individual arguments or as arrays of +   * property names. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Object} object The source object. +   * @param {Object} [prop1, prop2, ...] The properties to pick. +   * @returns {Object} Returns an object composed of the picked properties. +   * @example +   * +   * _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age'); +   * // => { 'name': 'moe', 'age': 40 } +   */ +  function pick(object) { +    var result = {}; +    if (!object) { +      return result; +    } +    var prop, +        index = 0, +        props = concat.apply(ArrayProto, arguments), +        length = props.length; + +    // start `index` at `1` to skip `object` +    while (++index < length) { +      prop = props[index]; +      if (prop in object) { +        result[prop] = object[prop]; +      } +    } +    return result; +  } + +  /** +   * Gets the size of `value` by returning `value.length` if `value` is an +   * array, string, or `arguments` object. If `value` is an object, size is +   * determined by returning the number of own enumerable properties it has. +   * +   * @deprecated +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Array|Object|String} value The value to inspect. +   * @returns {Number} Returns `value.length` or number of own enumerable properties. +   * @example +   * +   * _.size([1, 2]); +   * // => 2 +   * +   * _.size({ 'one': 1, 'two': 2, 'three': 3 }); +   * // => 3 +   * +   * _.size('curly'); +   * // => 5 +   */ +  function size(value) { +    if (!value) { +      return 0; +    } +    var className = toString.call(value), +        length = value.length; + +    // return `value.length` for `arguments` objects, arrays, strings, and DOM +    // query collections of libraries like jQuery and MooTools +    // http://code.google.com/p/fbug/source/browse/branches/firebug1.9/content/firebug/chrome/reps.js?r=12614#653 +    // http://trac.webkit.org/browser/trunk/Source/WebCore/inspector/InjectedScriptSource.js?rev=125186#L609 +    if (arrayLikeClasses[className] || (noArgsClass && isArguments(value)) || +        (className == objectClass && length > -1 && length === length >>> 0 && isFunction(value.splice))) { +      return length; +    } +    return keys(value).length; +  } + +  /** +   * Creates an array composed of the own enumerable property values of `object`. +   * +   * @static +   * @memberOf _ +   * @category Objects +   * @param {Object} object The object to inspect. +   * @returns {Array} Returns a new array of property values. +   * @example +   * +   * _.values({ 'one': 1, 'two': 2, 'three': 3 }); +   * // => [1, 2, 3] +   */ +  var values = createIterator({ +    'args': 'object', +    'init': '[]', +    'inLoop': 'result.push(value)' +  }); + +  /*--------------------------------------------------------------------------*/ + +  /** +   * Checks if a given `target` element is present in a `collection` using strict     * equality for comparisons, i.e. `===`.     *     * @static @@ -747,7 +1859,7 @@     * @category Collections     * @param {Array|Object|String} collection The collection to iterate over.     * @param {Mixed} target The value to check for. -   * @returns {Boolean} Returns `true` if `target` value is found, else `false`. +   * @returns {Boolean} Returns `true` if the `target` element is found, else `false`.     * @example     *     * _.contains([1, 2, 3], 3); @@ -766,10 +1878,38 @@      'beforeLoop': {        'array': 'if (toString.call(iteratee) == stringClass) return collection.indexOf(target) > -1'      }, -    'inLoop': 'if (iteratee[index] === target) return true' +    'inLoop': 'if (value === target) return true'    });    /** +   * Creates an object composed of keys returned from running each element of +   * `collection` through a `callback`. The corresponding value of each key is +   * the number of times the key was returned by `callback`. The `callback` is +   * bound to `thisArg` and invoked with 3 arguments; (value, index|key, collection). +   * The `callback` argument may also be the name of a property to count by (e.g. 'length'). +   * +   * @static +   * @memberOf _ +   * @category Collections +   * @param {Array|Object|String} collection The collection to iterate over. +   * @param {Function|String} callback The function called per iteration or +   *  property name to count by. +   * @param {Mixed} [thisArg] The `this` binding for the callback. +   * @returns {Object} Returns the composed aggregate object. +   * @example +   * +   * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); }); +   * // => { '4': 1, '6': 2 } +   * +   * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math); +   * // => { '4': 1, '6': 2 } +   * +   * _.countBy(['one', 'two', 'three'], 'length'); +   * // => { '3': 2, '5': 1 } +   */ +  var countBy = createIterator(baseIteratorOptions, countByIteratorOptions); + +  /**     * Checks if the `callback` returns a truthy value for **all** elements of a     * `collection`. The `callback` is bound to `thisArg` and invoked with 3     * arguments; (value, index|key, collection). @@ -781,7 +1921,7 @@     * @param {Array|Object|String} collection The collection to iterate over.     * @param {Function} [callback=identity] The function called per iteration.     * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Boolean} Returns `true` if all values pass the callback check, else `false`. +   * @returns {Boolean} Returns `true` if all elements pass the callback check, else `false`.     * @example     *     * _.every([true, 1, null, 'yes'], Boolean); @@ -790,8 +1930,8 @@    var every = createIterator(baseIteratorOptions, everyIteratorOptions);    /** -   * Examines each value in a `collection`, returning an array of all values the -   * `callback` returns truthy for. The `callback` is bound to `thisArg` and +   * Examines each element in a `collection`, returning an array of all elements +   * the `callback` returns truthy for. The `callback` is bound to `thisArg` and     * invoked with 3 arguments; (value, index|key, collection).     *     * @static @@ -801,7 +1941,7 @@     * @param {Array|Object|String} collection The collection to iterate over.     * @param {Function} [callback=identity] The function called per iteration.     * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Array} Returns a new array of values that passed callback check. +   * @returns {Array} Returns a new array of elements that passed callback check.     * @example     *     * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); @@ -810,9 +1950,9 @@    var filter = createIterator(baseIteratorOptions, filterIteratorOptions);    /** -   * Examines each value in a `collection`, returning the first one the `callback` +   * Examines each element in a `collection`, returning the first one the `callback`     * returns truthy for. The function returns as soon as it finds an acceptable -   * value, and does not iterate over the entire `collection`. The `callback` is +   * element, and does not iterate over the entire `collection`. The `callback` is     * bound to `thisArg` and invoked with 3 arguments; (value, index|key, collection).     *     * @static @@ -822,7 +1962,7 @@     * @param {Array|Object|String} collection The collection to iterate over.     * @param {Function} callback The function called per iteration.     * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Mixed} Returns the value that passed the callback check, else `undefined`. +   * @returns {Mixed} Returns the element that passed the callback check, else `undefined`.     * @example     *     * var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); @@ -830,13 +1970,14 @@     */    var find = createIterator(baseIteratorOptions, forEachIteratorOptions, {      'init': '', -    'inLoop': 'if (callback(iteratee[index], index, collection)) return iteratee[index]' +    'inLoop': 'if (callback(value, index, collection)) return value'    });    /** -   * Iterates over a `collection`, executing the `callback` for each value in the -   * `collection`. The `callback` is bound to `thisArg` and invoked with 3 -   * arguments; (value, index|key, collection). +   * Iterates over a `collection`, executing the `callback` for each element in +   * the `collection`. The `callback` is bound to `thisArg` and invoked with 3 +   * arguments; (value, index|key, collection). Callbacks may exit iteration +   * early by explicitly returning `false`.     *     * @static     * @memberOf _ @@ -845,7 +1986,7 @@     * @param {Array|Object|String} collection The collection to iterate over.     * @param {Function} callback The function called per iteration.     * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Array|Object} Returns the `collection`. +   * @returns {Array|Object} Returns `collection`.     * @example     *     * _([1, 2, 3]).forEach(alert).join(','); @@ -857,10 +1998,11 @@    var forEach = createIterator(baseIteratorOptions, forEachIteratorOptions);    /** -   * Splits `collection` into sets, grouped by the result of running each value -   * through `callback`. The `callback` is bound to `thisArg` and invoked with -   * 3 arguments; (value, index|key, collection). The `callback` argument may -   * also be the name of a property to group by. +   * Creates an object composed of keys returned from running each element of +   * `collection` through a `callback`. The corresponding value of each key is an +   * array of elements passed to `callback` that returned the key. The `callback` +   * is bound to `thisArg` and invoked with 3 arguments; (value, index|key, collection). +   * The `callback` argument may also be the name of a property to count by (e.g. 'length').     *     * @static     * @memberOf _ @@ -869,28 +2011,22 @@     * @param {Function|String} callback The function called per iteration or     *  property name to group by.     * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Object} Returns an object of grouped values. +   * @returns {Object} Returns the composed aggregate object.     * @example     * -   * _.groupBy([1.3, 2.1, 2.4], function(num) { return Math.floor(num); }); -   * // => { '1': [1.3], '2': [2.1, 2.4] } +   * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); }); +   * // => { '4': [4.2], '6': [6.1, 6.4] }     * -   * _.groupBy([1.3, 2.1, 2.4], function(num) { return this.floor(num); }, Math); -   * // => { '1': [1.3], '2': [2.1, 2.4] } +   * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math); +   * // => { '4': [4.2], '6': [6.1, 6.4] }     *     * _.groupBy(['one', 'two', 'three'], 'length');     * // => { '3': ['one', 'two'], '5': ['three'] }     */ -  var groupBy = createIterator(baseIteratorOptions, { -    'init': '{}', -    'top': -      'var prop, isFunc = typeof callback == \'function\';\n' + -      'if (isFunc && thisArg) callback = iteratorBind(callback, thisArg)', +  var groupBy = createIterator(baseIteratorOptions, countByIteratorOptions, {      'inLoop': -      'prop = isFunc\n' + -      '  ? callback(iteratee[index], index, collection)\n' + -      '  : iteratee[index][callback];\n' + -      '(hasOwnProperty.call(result, prop) ? result[prop] : result[prop] = []).push(iteratee[index])' +      'prop = callback(value, index, collection);\n' + +      '(hasOwnProperty.call(result, prop) ? result[prop] : result[prop] = []).push(value)'    });    /** @@ -922,18 +2058,17 @@        '    isFunc = typeof methodName == \'function\'',      'inLoop': {        'array': -        'result[index] = (isFunc ? methodName : iteratee[index][methodName])' + -        '.apply(iteratee[index], args)', +        'result[index] = (isFunc ? methodName : value[methodName]).apply(value, args)',        'object': -        'result' + (isKeysFast ? '[propIndex] = ' : '.push') + -        '((isFunc ? methodName : iteratee[index][methodName]).apply(iteratee[index], args))' +        'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + +        '((isFunc ? methodName : value[methodName]).apply(value, args))'      }    });    /** -   * Produces a new array of values by mapping each element in the `collection` -   * through a transformation `callback`. The `callback` is bound to `thisArg` -   * and invoked with 3 arguments; (value, index|key, collection). +   * Creates a new array of values by running each element in the `collection` +   * through a `callback`. The `callback` is bound to `thisArg` and invoked with +   * 3 arguments; (value, index|key, collection).     *     * @static     * @memberOf _ @@ -942,7 +2077,7 @@     * @param {Array|Object|String} collection The collection to iterate over.     * @param {Function} [callback=identity] The function called per iteration.     * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Array} Returns a new array of values returned by the callback. +   * @returns {Array} Returns a new array of elements returned by the callback.     * @example     *     * _.map([1, 2, 3], function(num) { return num * 3; }); @@ -977,8 +2112,8 @@    var pluck = createIterator(mapIteratorOptions, {      'args': 'collection, property',      'inLoop': { -      'array':  'result[index] = iteratee[index][property]', -      'object': 'result' + (isKeysFast ? '[propIndex] = ' : '.push') + '(iteratee[index][property])' +      'array':  'result[index] = value[property]', +      'object': 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '(value[property])'      }    }); @@ -1013,11 +2148,11 @@      },      'inLoop': {        'array': -        'result = callback(result, iteratee[index], index, collection)', +        'result = callback(result, value, index, collection)',        'object':          'result = noaccum\n' + -        '  ? (noaccum = false, iteratee[index])\n' + -        '  : callback(result, iteratee[index], index, collection)' +        '  ? (noaccum = false, value)\n' + +        '  : callback(result, value, index, collection)'      }    }); @@ -1050,7 +2185,8 @@      if(thisArg) {        callback = iteratorBind(callback, thisArg);      } -    if (length === length >>> 0) { +    // Opera 10.53-10.60 JITted `length >>> 0` returns the wrong value for negative numbers +    if (length > -1 && length === length >>> 0) {        var iteratee = noCharByIndex && toString.call(collection) == stringClass          ? collection.split('')          : collection; @@ -1088,7 +2224,7 @@     * @param {Array|Object|String} collection The collection to iterate over.     * @param {Function} [callback=identity] The function called per iteration.     * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Array} Returns a new array of values that did **not** pass the callback check. +   * @returns {Array} Returns a new array of elements that did **not** pass the callback check.     * @example     *     * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); @@ -1111,7 +2247,7 @@     * @param {Array|Object|String} collection The collection to iterate over.     * @param {Function} [callback=identity] The function called per iteration.     * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Boolean} Returns `true` if any value passes the callback check, else `false`. +   * @returns {Boolean} Returns `true` if any element passes the callback check, else `false`.     * @example     *     * _.some([null, 0, 'yes', false]); @@ -1122,13 +2258,11 @@      'inLoop': everyIteratorOptions.inLoop.replace('!', '')    }); -    /** -   * Produces a new sorted array, sorted in ascending order by the results of -   * running each element of `collection` through a transformation `callback`. -   * The `callback` is bound to `thisArg` and invoked with 3 arguments; -   * (value, index|key, collection). The `callback` argument may also be the -   * name of a property to sort by (e.g. 'length'). +   * Creates a new array, stable sorted in ascending order by the results of +   * running each element of `collection` through a `callback`. The `callback` +   * is bound to `thisArg` and invoked with 3 arguments; (value, index|key, collection). +   * The `callback` argument may also be the name of a property to sort by (e.g. 'length').     *     * @static     * @memberOf _ @@ -1137,7 +2271,7 @@     * @param {Function|String} callback The function called per iteration or     *  property name to sort by.     * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Array} Returns a new array of sorted values. +   * @returns {Array} Returns a new array of sorted elements.     * @example     *     * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); }); @@ -1149,25 +2283,19 @@     * _.sortBy(['larry', 'brendan', 'moe'], 'length');     * // => ['moe', 'larry', 'brendan']     */ -  var sortBy = createIterator(baseIteratorOptions, mapIteratorOptions, { -    'top': -      'if (typeof callback == \'string\') {\n' + -      '  var prop = callback;\n' + -      '  callback = function(collection) { return collection[prop] }\n' + -      '}\n' + -      'else if (thisArg) {\n' + -      '  callback = iteratorBind(callback, thisArg)\n' + -      '}', +  var sortBy = createIterator(baseIteratorOptions, countByIteratorOptions, mapIteratorOptions, {      'inLoop': {        'array':          'result[index] = {\n' + -        '  criteria: callback(iteratee[index], index, collection),\n' + -        '  value: iteratee[index]\n' + +        '  criteria: callback(value, index, collection),\n' + +        '  index: index,\n' + +        '  value: value\n' +          '}',        'object': -        'result' + (isKeysFast ? '[propIndex] = ' : '.push') + '({\n' + -        '  criteria: callback(iteratee[index], index, collection),\n' + -        '  value: iteratee[index]\n' + +        'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '({\n' + +        '  criteria: callback(value, index, collection),\n' + +        '  index: index,\n' + +        '  value: value\n' +          '})'      },      'bottom': @@ -1179,7 +2307,7 @@    });    /** -   * Converts the `collection`, into an array. Useful for converting the +   * Converts the `collection`, to an array. Useful for converting the     * `arguments` object.     *     * @static @@ -1196,11 +2324,11 @@      if (!collection) {        return [];      } -    if (collection.toArray && toString.call(collection.toArray) == funcClass) { +    if (collection.toArray && isFunction(collection.toArray)) {        return collection.toArray();      }      var length = collection.length; -    if (length === length >>> 0) { +    if (length > -1 && length === length >>> 0) {        return (noArraySliceOnStrings ? toString.call(collection) == stringClass : typeof collection == 'string')          ? collection.split('')          : slice.call(collection); @@ -1208,10 +2336,45 @@      return values(collection);    } +  /** +   * Examines each element in a `collection`, returning an array of all elements +   * that contain the given `properties`. +   * +   * @static +   * @memberOf _ +   * @category Collections +   * @param {Array|Object|String} collection The collection to iterate over. +   * @param {Object} properties The object of properties/values to filter by. +   * @returns {Array} Returns a new array of elements that contain the given `properties`. +   * @example +   * +   * var stooges = [ +   *   { 'name': 'moe', 'age': 40 }, +   *   { 'name': 'larry', 'age': 50 }, +   *   { 'name': 'curly', 'age': 60 } +   * ]; +   * +   * _.where(stooges, { 'age': 40 }); +   * // => [{ 'name': 'moe', 'age': 40 }] +   */ +  var where = createIterator(filterIteratorOptions, { +    'args': 'collection, properties', +    'top': +      'var pass, prop, propIndex, props = [];\n' + +      'forIn(properties, function(value, prop) { props.push(prop) });\n' + +      'var propsLength = props.length', +    'inLoop': +      'for (pass = true, propIndex = 0; propIndex < propsLength; propIndex++) {\n' + +      '  prop = props[propIndex];\n' + +      '  if (!(pass = value[prop] === properties[prop])) break\n' + +      '}\n' + +      'if (pass) result.push(value)' +  }); +    /*--------------------------------------------------------------------------*/    /** -   * Produces a new array with all falsey values of `array` removed. The values +   * Creates a new array with all falsey values of `array` removed. The values     * `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey.     *     * @static @@ -1241,7 +2404,7 @@    }    /** -   * Produces a new array of `array` values not present in the other arrays +   * Creates a new array of `array` elements not present in the other arrays     * using strict equality for comparisons, i.e. `===`.     *     * @static @@ -1249,7 +2412,7 @@     * @category Arrays     * @param {Array} array The array to process.     * @param {Array} [array1, array2, ...] Arrays to check. -   * @returns {Array} Returns a new array of `array` values not present in the +   * @returns {Array} Returns a new array of `array` elements not present in the     *  other arrays.     * @example     * @@ -1275,8 +2438,8 @@    }    /** -   * Gets the first value of the `array`. Pass `n` to return the first `n` values -   * of the `array`. +   * Gets the first element of the `array`. Pass `n` to return the first `n` +   * elements of the `array`.     *     * @static     * @memberOf _ @@ -1286,8 +2449,8 @@     * @param {Number} [n] The number of elements to return.     * @param {Object} [guard] Internally used to allow this method to work with     *  others like `_.map` without using their callback `index` argument for `n`. -   * @returns {Mixed} Returns the first value or an array of the first `n` values -   *  of `array`. +   * @returns {Mixed} Returns the first element or an array of the first `n` +   *  elements of `array`.     * @example     *     * _.first([5, 4, 3, 2, 1]); @@ -1385,8 +2548,8 @@    }    /** -   * Gets all but the last value of `array`. Pass `n` to exclude the last `n` -   * values from the result. +   * Gets all but the last element of `array`. Pass `n` to exclude the last `n` +   * elements from the result.     *     * @static     * @memberOf _ @@ -1395,7 +2558,7 @@     * @param {Number} [n] The number of elements to return.     * @param {Object} [guard] Internally used to allow this method to work with     *  others like `_.map` without using their callback `index` argument for `n`. -   * @returns {Array} Returns all but the last value or `n` values of `array`. +   * @returns {Array} Returns all but the last element or `n` elements of `array`.     * @example     *     * _.initial([3, 2, 1]); @@ -1409,13 +2572,14 @@    }    /** -   * Computes the intersection of all the passed-in arrays. +   * Computes the intersection of all the passed-in arrays using strict equality +   * for comparisons, i.e. `===`.     *     * @static     * @memberOf _     * @category Arrays     * @param {Array} [array1, array2, ...] Arrays to process. -   * @returns {Array} Returns a new array of unique values, in order, that are +   * @returns {Array} Returns a new array of unique elements, in order, that are     *  present in **all** of the arrays.     * @example     * @@ -1446,8 +2610,8 @@    }    /** -   * Gets the last value of the `array`. Pass `n` to return the lasy `n` values -   * of the `array`. +   * Gets the last element of the `array`. Pass `n` to return the lasy `n` +   * elementsvof the `array`.     *     * @static     * @memberOf _ @@ -1456,8 +2620,8 @@     * @param {Number} [n] The number of elements to return.     * @param {Object} [guard] Internally used to allow this method to work with     *  others like `_.map` without using their callback `index` argument for `n`. -   * @returns {Mixed} Returns the last value or an array of the last `n` values -   *  of `array`. +   * @returns {Mixed} Returns the last element or an array of the last `n` +   *  elements of `array`.     * @example     *     * _.last([3, 2, 1]); @@ -1641,9 +2805,11 @@     * // => []     */    function range(start, end, step) { -    step || (step = 1); +    start = +start || 0; +    step = +step || 1; +      if (end == null) { -      end = start || 0; +      end = start;        start = 0;      }      // use `Array(length)` so V8 will avoid the slower "dictionary" mode @@ -1685,7 +2851,7 @@    }    /** -   * Produces a new array of shuffled `array` values, using a version of the +   * Creates a new array of shuffled `array` values, using a version of the     * Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.     *     * @static @@ -1777,7 +2943,8 @@    }    /** -   * Computes the union of the passed-in arrays. +   * Computes the union of the passed-in arrays using strict equality for +   * comparisons, i.e. `===`.     *     * @static     * @memberOf _ @@ -1805,12 +2972,11 @@    }    /** -   * Produces a duplicate-value-free version of the `array` using strict equality +   * Creates a duplicate-value-free version of the `array` using strict equality     * for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` -   * for `isSorted` will run a faster algorithm. If `callback` is passed, -   * each value of `array` is passed through a transformation `callback` before -   * uniqueness is computed. The `callback` is bound to `thisArg` and invoked -   * with 3 arguments; (value, index, array). +   * for `isSorted` will run a faster algorithm. If `callback` is passed, each +   * element of `array` is passed through a callback` before uniqueness is computed. +   * The `callback` is bound to `thisArg` and invoked with 3 arguments; (value, index, array).     *     * @static     * @memberOf _ @@ -1870,7 +3036,7 @@    }    /** -   * Produces a new array with all occurrences of the passed values removed using +   * Creates a new array with all occurrences of the passed values removed using     * strict equality for comparisons, i.e. `===`.     *     * @static @@ -1902,7 +3068,7 @@    }    /** -   * Merges the elements of each array at their corresponding indexes. Useful for +   * Groups the elements of each array at their corresponding indexes. Useful for     * separate data sources that are coordinated through matching array indexes.     * For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix     * in a similar fashion. @@ -1911,7 +3077,7 @@     * @memberOf _     * @category Arrays     * @param {Array} [array1, array2, ...] Arrays to process. -   * @returns {Array} Returns a new array of merged arrays. +   * @returns {Array} Returns a new array of grouped elements.     * @example     *     * _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); @@ -1932,7 +3098,7 @@    }    /** -   * Merges an array of `keys` and an array of `values` into a single object. +   * Creates an object composed from an array of `keys` and an array of `values`.     *     * @static     * @memberOf _ @@ -2038,7 +3204,7 @@     */    function bind(func, thisArg) {      var methodName, -        isFunc = toString.call(func) == funcClass; +        isFunc = isFunction(func);      // juggle arguments      if (!isFunc) { @@ -2064,7 +3230,7 @@        }        if (partialArgs.length) {          args = args.length -          ? concat.apply(partialArgs, args) +          ? partialArgs.concat(slice.call(args))            : partialArgs;        }        if (this instanceof bound) { @@ -2094,7 +3260,7 @@     * @category Functions     * @param {Object} object The object to bind and assign the bound methods to.     * @param {String} [methodName1, methodName2, ...] Method names on the object to bind. -   * @returns {Object} Returns the `object`. +   * @returns {Object} Returns `object`.     * @example     *     * var buttonView = { @@ -2115,13 +3281,15 @@        'var funcs = arguments,\n' +        '    length = funcs.length;\n' +        'if (length > 1) {\n' + -      '  for (var index = 1; index < length; index++)\n' + -      '    result[funcs[index]] = bind(result[funcs[index]], result);\n' + +      '  for (var index = 1; index < length; index++) {\n' + +      '    result[funcs[index]] = bind(result[funcs[index]], result)\n' + +      '  }\n' +        '  return result\n' +        '}',      'inLoop': -      'if (toString.call(result[index]) == funcClass)' + -      ' result[index] = bind(result[index], result)' +      'if (isFunction(result[index])) {\n' + +      '  result[index] = bind(result[index], result)\n' + +      '}'    });    /** @@ -2205,7 +3373,7 @@    /**     * Executes the `func` function after `wait` milliseconds. Additional arguments -   * are passed to `func` when it is invoked. +   * will be passed to `func` when it is invoked.     *     * @static     * @memberOf _ @@ -2227,7 +3395,7 @@    /**     * Defers executing the `func` function until the current call stack has cleared. -   * Additional arguments are passed to `func` when it is invoked. +   * Additional arguments will be passed to `func` when it is invoked.     *     * @static     * @memberOf _ @@ -2299,15 +3467,17 @@        }        ran = true;        result = func.apply(this, arguments); + +      // clear the `func` variable so the function may be garbage collected +      func = null;        return result;      };    }    /**     * Creates a new function that, when called, invokes `func` with any additional -   * `partial` arguments prepended to those passed to the partially applied -   * function. This method is similar `bind`, except it does **not** alter the -   * `this` binding. +   * `partial` arguments prepended to those passed to the new function. This method +   * is similar `bind`, except it does **not** alter the `this` binding.     *     * @static     * @memberOf _ @@ -2390,16 +3560,15 @@    }    /** -   * Create a new function that passes the `func` function to the `wrapper` -   * function as its first argument. Additional arguments are appended to those -   * passed to the `wrapper` function. +   * Creates a new function that passes `value` to the `wrapper` function as its +   * first argument. Additional arguments passed to the new function are appended +   * to those passed to the `wrapper` function.     *     * @static     * @memberOf _     * @category Functions -   * @param {Function} func The function to wrap. +   * @param {Mixed} value The value to wrap.     * @param {Function} wrapper The wrapper function. -   * @param {Mixed} [arg1, arg2, ...] Arguments to append to those passed to the wrapper.     * @returns {Function} Returns the new function.     * @example     * @@ -2410,9 +3579,9 @@     * hello();     * // => 'before, hello: moe, after'     */ -  function wrap(func, wrapper) { +  function wrap(value, wrapper) {      return function() { -      var args = [func]; +      var args = [value];        if (arguments.length) {          push.apply(args, arguments);        } @@ -2423,740 +3592,6 @@    /*--------------------------------------------------------------------------*/    /** -   * Create a shallow clone of the `value`. Any nested objects or arrays will be -   * assigned by reference and not cloned. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to clone. -   * @returns {Mixed} Returns the cloned `value`. -   * @example -   * -   * _.clone({ 'name': 'moe' }); -   * // => { 'name': 'moe' }; -   */ -  function clone(value) { -    return value && objectTypes[typeof value] -      ? (isArray(value) ? value.slice() : extend({}, value)) -      : value; -  } - -  /** -   * Assigns missing properties on `object` with default values from the defaults -   * objects. Once a property is set, additional defaults of the same property -   * will be ignored. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to populate. -   * @param {Object} [defaults1, defaults2, ...] The defaults objects to apply to `object`. -   * @returns {Object} Returns `object`. -   * @example -   * -   * var iceCream = { 'flavor': 'chocolate' }; -   * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' }); -   * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' } -   */ -  var defaults = createIterator(extendIteratorOptions, { -    'inLoop': 'if (result[index] == null) ' + extendIteratorOptions.inLoop -  }); - -  /** -   * Copies enumerable properties from the source objects to the `destination` object. -   * Subsequent sources will overwrite propery assignments of previous sources. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The destination object. -   * @param {Object} [source1, source2, ...] The source objects. -   * @returns {Object} Returns the destination object. -   * @example -   * -   * _.extend({ 'name': 'moe' }, { 'age': 40 }); -   * // => { 'name': 'moe', 'age': 40 } -   */ -  var extend = createIterator(extendIteratorOptions); - -  /** -   * Iterates over `object`'s own and inherited enumerable properties, executing -   * the `callback` for each property. The `callback` is bound to `thisArg` and -   * invoked with 3 arguments; (value, key, object). -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to iterate over. -   * @param {Function} callback The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Object} Returns the `object`. -   * @example -   * -   * function Dog(name) { -   *   this.name = name; -   * } -   * -   * Dog.prototype.bark = function() { -   *   alert('Woof, woof!'); -   * }; -   * -   * _.forIn(new Dog('Dagny'), function(value, key) { -   *   alert(key); -   * }); -   * // => alerts 'name' and 'bark' (order is not guaranteed) -   */ -  var forIn = createIterator(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions, { -    'useHas': false -  }); - -  /** -   * Iterates over `object`'s own enumerable properties, executing the `callback` -   * for each property. The `callback` is bound to `thisArg` and invoked with 3 -   * arguments; (value, key, object). -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to iterate over. -   * @param {Function} callback The function called per iteration. -   * @param {Mixed} [thisArg] The `this` binding for the callback. -   * @returns {Object} Returns the `object`. -   * @example -   * -   * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { -   *   alert(key); -   * }); -   * // => alerts '0', '1', and 'length' (order is not guaranteed) -   */ -  var forOwn = createIterator(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions); - -  /** -   * Produces a sorted array of the enumerable properties, own and inherited, -   * of `object` that have function values. -   * -   * @static -   * @memberOf _ -   * @alias methods -   * @category Objects -   * @param {Object} object The object to inspect. -   * @returns {Array} Returns a new array of property names that have function values. -   * @example -   * -   * _.functions(_); -   * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] -   */ -  var functions = createIterator({ -    'useHas': false, -    'args': 'object', -    'init': '[]', -    'inLoop': 'if (toString.call(iteratee[index]) == funcClass) result.push(index)', -    'bottom': 'result.sort()' -  }); - -  /** -   * Checks if the specified object `property` exists and is a direct property, -   * instead of an inherited property. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to check. -   * @param {String} property The property to check for. -   * @returns {Boolean} Returns `true` if key is a direct property, else `false`. -   * @example -   * -   * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); -   * // => true -   */ -  function has(object, property) { -    return hasOwnProperty.call(object, property); -  } - -  /** -   * Checks if `value` is an `arguments` object. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is an `arguments` object, else `false`. -   * @example -   * -   * (function() { return _.isArguments(arguments); })(1, 2, 3); -   * // => true -   * -   * _.isArguments([1, 2, 3]); -   * // => false -   */ -  var isArguments = function(value) { -    return toString.call(value) == '[object Arguments]'; -  }; -  // fallback for browser like Firefox < 4 and IE < 9 which detect -  // `arguments` as `[object Object]` -  if (!isArguments(arguments)) { -    isArguments = function(value) { -      return !!(value && hasOwnProperty.call(value, 'callee')); -    }; -  } - -  /** -   * Checks if `value` is an array. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is an array, else `false`. -   * @example -   * -   * (function() { return _.isArray(arguments); })(); -   * // => false -   * -   * _.isArray([1, 2, 3]); -   * // => true -   */ -  var isArray = nativeIsArray || function(value) { -    return toString.call(value) == arrayClass; -  }; - -  /** -   * Checks if `value` is a boolean (`true` or `false`) value. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a boolean value, else `false`. -   * @example -   * -   * _.isBoolean(null); -   * // => false -   */ -  function isBoolean(value) { -    return value === true || value === false || toString.call(value) == boolClass; -  } - -  /** -   * Checks if `value` is a date. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a date, else `false`. -   * @example -   * -   * _.isDate(new Date); -   * // => true -   */ -  function isDate(value) { -    return toString.call(value) == dateClass; -  } - -  /** -   * Checks if `value` is a DOM element. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a DOM element, else `false`. -   * @example -   * -   * _.isElement(document.body); -   * // => true -   */ -  function isElement(value) { -    return !!(value && value.nodeType == 1); -  } - -  /** -   * Checks if `value` is empty. Arrays or strings with a length of `0` and -   * objects with no own enumerable properties are considered "empty". -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Array|Object|String} value The value to inspect. -   * @returns {Boolean} Returns `true` if the `value` is empty, else `false`. -   * @example -   * -   * _.isEmpty([1, 2, 3]); -   * // => false -   * -   * _.isEmpty({}); -   * // => true -   * -   * _.isEmpty(''); -   * // => true -   */ -  var isEmpty = createIterator({ -    'args': 'value', -    'init': 'true', -    'top': -      'var className = toString.call(value);\n' + -      'if (className == arrayClass || className == stringClass) return !value.length', -    'inLoop': { -      'object': 'return false' -    } -  }); - -  /** -   * Performs a deep comparison between two values to determine if they are -   * equivalent to each other. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} a The value to compare. -   * @param {Mixed} b The other value to compare. -   * @param {Array} [stack] Internally used to keep track of "seen" objects to -   *  avoid circular references. -   * @returns {Boolean} Returns `true` if the values are equvalent, else `false`. -   * @example -   * -   * var moe = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; -   * var clone = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; -   * -   * moe == clone; -   * // => false -   * -   * _.isEqual(moe, clone); -   * // => true -   */ -  function isEqual(a, b, stack) { -    stack || (stack = []); - -    // exit early for identical values -    if (a === b) { -      // treat `+0` vs. `-0` as not equal -      return a !== 0 || (1 / a == 1 / b); -    } -    // a strict comparison is necessary because `undefined == null` -    if (a == null || b == null) { -      return a === b; -    } -    // unwrap any wrapped objects -    if (a._chain) { -      a = a._wrapped; -    } -    if (b._chain) { -      b = b._wrapped; -    } -    // invoke a custom `isEqual` method if one is provided -    if (a.isEqual && toString.call(a.isEqual) == funcClass) { -      return a.isEqual(b); -    } -    if (b.isEqual && toString.call(b.isEqual) == funcClass) { -      return b.isEqual(a); -    } -    // compare [[Class]] names -    var className = toString.call(a); -    if (className != toString.call(b)) { -      return false; -    } -    switch (className) { -      // strings, numbers, dates, and booleans are compared by value -      case stringClass: -        // primitives and their corresponding object instances are equivalent; -        // thus, `'5'` is quivalent to `new String('5')` -        return a == String(b); - -      case numberClass: -        // treat `NaN` vs. `NaN` as equal -        return a != +a -          ? b != +b -          // but treat `+0` vs. `-0` as not equal -          : (a == 0 ? (1 / a == 1 / b) : a == +b); - -      case boolClass: -      case dateClass: -        // coerce dates and booleans to numeric values, dates to milliseconds and -        // booleans to 1 or 0; treat invalid dates coerced to `NaN` as not equal -        return +a == +b; - -      // regexps are compared by their source and flags -      case regexpClass: -        return a.source == b.source && -               a.global == b.global && -               a.multiline == b.multiline && -               a.ignoreCase == b.ignoreCase; -    } -    if (typeof a != 'object' || typeof b != 'object') { -      return false; -    } -    // Assume equality for cyclic structures. The algorithm for detecting cyclic -    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. -    var length = stack.length; -    while (length--) { -      // Linear search. Performance is inversely proportional to the number of -      // unique nested structures. -      if (stack[length] == a) { -        return true; -      } -    } - -    var index = -1, -        result = true, -        size = 0; - -    // add the first collection to the stack of traversed objects -    stack.push(a); - -    // recursively compare objects and arrays -    if (className == arrayClass) { -      // compare array lengths to determine if a deep comparison is necessary -      size = a.length; -      result = size == b.length; - -      if (result) { -        // deep compare the contents, ignoring non-numeric properties -        while (size--) { -          if (!(result = isEqual(a[size], b[size], stack))) { -            break; -          } -        } -      } -    } -    else { -      // objects with different constructors are not equivalent -      if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) { -        return false; -      } -      // deep compare objects. -      for (var prop in a) { -        if (hasOwnProperty.call(a, prop)) { -          // count the number of properties. -          size++; -          // deep compare each property value. -          if (!(result = hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stack))) { -            break; -          } -        } -      } -      // ensure both objects have the same number of properties -      if (result) { -        for (prop in b) { -          // Adobe's JS engine, embedded in applications like InDesign, has a -          // bug that causes `!size--` to throw an error so it must be wrapped -          // in parentheses. -          // https://github.com/documentcloud/underscore/issues/355 -          if (hasOwnProperty.call(b, prop) && !(size--)) { -            break; -          } -        } -        result = !size; -      } -      // handle JScript [[DontEnum]] bug -      if (result && hasDontEnumBug) { -        while (++index < 7) { -          prop = shadowed[index]; -          if (hasOwnProperty.call(a, prop)) { -            if (!(result = hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stack))) { -              break; -            } -          } -        } -      } -    } -    // remove the first collection from the stack of traversed objects -    stack.pop(); -    return result; -  } - -  /** -   * Checks if `value` is a finite number. -   * Note: This is not the same as native `isFinite`, which will return true for -   * booleans and other values. See http://es5.github.com/#x15.1.2.5. -   * -   * @deprecated -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a finite number, else `false`. -   * @example -   * -   * _.isFinite(-101); -   * // => true -   * -   * _.isFinite('10'); -   * // => false -   * -   * _.isFinite(Infinity); -   * // => false -   */ -  function isFinite(value) { -    return nativeIsFinite(value) && toString.call(value) == numberClass; -  } - -  /** -   * Checks if `value` is a function. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a function, else `false`. -   * @example -   * -   * _.isFunction(''.concat); -   * // => true -   */ -  function isFunction(value) { -    return toString.call(value) == funcClass; -  } - -  /** -   * Checks if `value` is the language type of Object. -   * (e.g. arrays, functions, objects, regexps, `new Number(0)`, and `new String('')`) -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is an object, else `false`. -   * @example -   * -   * _.isObject({}); -   * // => true -   * -   * _.isObject(1); -   * // => false -   */ -  function isObject(value) { -    // check if the value is the ECMAScript language type of Object -    // http://es5.github.com/#x8 -    return value && objectTypes[typeof value]; -  } - -  /** -   * Checks if `value` is `NaN`. -   * Note: This is not the same as native `isNaN`, which will return true for -   * `undefined` and other values. See http://es5.github.com/#x15.1.2.4. -   * -   * @deprecated -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is `NaN`, else `false`. -   * @example -   * -   * _.isNaN(NaN); -   * // => true -   * -   * _.isNaN(new Number(NaN)); -   * // => true -   * -   * isNaN(undefined); -   * // => true -   * -   * _.isNaN(undefined); -   * // => false -   */ -  function isNaN(value) { -    // `NaN` as a primitive is the only value that is not equal to itself -    // (perform the [[Class]] check first to avoid errors with some host objects in IE) -    return toString.call(value) == numberClass && value != +value -  } - -  /** -   * Checks if `value` is `null`. -   * -   * @deprecated -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is `null`, else `false`. -   * @example -   * -   * _.isNull(null); -   * // => true -   * -   * _.isNull(undefined); -   * // => false -   */ -  function isNull(value) { -    return value === null; -  } - -  /** -   * Checks if `value` is a number. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a number, else `false`. -   * @example -   * -   * _.isNumber(8.4 * 5; -   * // => true -   */ -  function isNumber(value) { -    return toString.call(value) == numberClass; -  } - -  /** -   * Checks if `value` is a regular expression. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a regular expression, else `false`. -   * @example -   * -   * _.isRegExp(/moe/); -   * // => true -   */ -  function isRegExp(value) { -    return toString.call(value) == regexpClass; -  } - -  /** -   * Checks if `value` is a string. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is a string, else `false`. -   * @example -   * -   * _.isString('moe'); -   * // => true -   */ -  function isString(value) { -    return toString.call(value) == stringClass; -  } - -  /** -   * Checks if `value` is `undefined`. -   * -   * @deprecated -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Mixed} value The value to check. -   * @returns {Boolean} Returns `true` if the `value` is `undefined`, else `false`. -   * @example -   * -   * _.isUndefined(void 0); -   * // => true -   */ -  function isUndefined(value) { -    return value === undefined; -  } - -  /** -   * Produces an array of object`'s own enumerable property names. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to inspect. -   * @returns {Array} Returns a new array of property names. -   * @example -   * -   * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); -   * // => ['one', 'two', 'three'] (order is not guaranteed) -   */ -  var keys = !nativeKeys ? shimKeys : function(object) { -    // avoid iterating over the `prototype` property -    return typeof object == 'function' && propertyIsEnumerable.call(object, 'prototype') -      ? shimKeys(object) -      : nativeKeys(object); -  }; - -  /** -   * Creates an object composed of the specified properties. Property names may -   * be specified as individual arguments or as arrays of property names. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to pluck. -   * @param {Object} [prop1, prop2, ...] The properties to pick. -   * @returns {Object} Returns an object composed of the picked properties. -   * @example -   * -   * _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age'); -   * // => { 'name': 'moe', 'age': 40 } -   */ -  function pick(object) { -    var prop, -        index = 0, -        props = concat.apply(ArrayProto, arguments), -        length = props.length, -        result = {}; - -    // start `index` at `1` to skip `object` -    while (++index < length) { -      prop = props[index]; -      if (prop in object) { -        result[prop] = object[prop]; -      } -    } -    return result; -  } - -  /** -   * Gets the size of `value` by returning `value.length` if `value` is a string -   * or array, or the number of own enumerable properties if `value` is an object. -   * -   * @deprecated -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Array|Object|String} value The value to inspect. -   * @returns {Number} Returns `value.length` if `value` is a string or array, -   *  or the number of own enumerable properties if `value` is an object. -   * @example -   * -   * _.size([1, 2]); -   * // => 2 -   * -   * _.size({ 'one': 1, 'two': 2, 'three': 3 }); -   * // => 3 -   * -   * _.size('curly'); -   * // => 5 -   */ -  function size(value) { -    if (!value) { -      return 0; -    } -    var length = value.length; -    return length === length >>> 0 ? value.length : keys(value).length; -  } - -  /** -   * Produces an array of `object`'s own enumerable property values. -   * -   * @static -   * @memberOf _ -   * @category Objects -   * @param {Object} object The object to inspect. -   * @returns {Array} Returns a new array of property values. -   * @example -   * -   * _.values({ 'one': 1, 'two': 2, 'three': 3 }); -   * // => [1, 2, 3] -   */ -  var values = createIterator({ -    'args': 'object', -    'init': '[]', -    'inLoop': 'result.push(iteratee[index])' -  }); - -  /*--------------------------------------------------------------------------*/ - -  /**     * Escapes a string for inclusion in HTML, replacing `&`, `<`, `"`, and `'`     * characters.     * @@ -3167,8 +3602,8 @@     * @returns {String} Returns the escaped string.     * @example     * -   * _.escape('Curly, Larry & Moe'); -   * // => "Curly, Larry & Moe" +   * _.escape('Moe, Larry & Curly'); +   * // => "Moe, Larry & Curly"     */    function escape(string) {      return string == null ? '' : (string + '').replace(reUnescapedHtml, escapeHtmlChar); @@ -3176,6 +3611,7 @@    /**     * This function returns the first argument passed to it. +   *     * Note: It is used throughout Lo-Dash as a default callback.     *     * @static @@ -3209,11 +3645,11 @@     *   }     * });     * -   * _.capitalize('curly'); -   * // => 'Curly' -   * -   * _('larry').capitalize(); +   * _.capitalize('larry');     * // => 'Larry' +   * +   * _('curly').capitalize(); +   * // => 'Curly'     */    function mixin(object) {      forEach(functions(object), function(methodName) { @@ -3285,13 +3721,20 @@        return null;      }      var value = object[property]; -    return toString.call(value) == funcClass ? object[property]() : value; +    return isFunction(value) ? object[property]() : value;    }    /**     * A micro-templating method that handles arbitrary delimiters, preserves     * whitespace, and correctly escapes quotes within interpolated code.     * +   * Note: In the development build `_.template` utilizes sourceURLs for easier +   * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl +   * +   * Note: Lo-Dash may be used in Chrome extensions by either creating a `lodash csp` +   * build and avoiding `_.template` use, or loading Lo-Dash in a sandboxed page. +   * See http://developer.chrome.com/trunk/extensions/sandboxingEval.html +   *     * @static     * @memberOf _     * @category Utilities @@ -3302,41 +3745,47 @@     *  is given, else it returns the interpolated text.     * @example     * -   * // using compiled template +   * // using a compiled template     * var compiled = _.template('hello: <%= name %>');     * compiled({ 'name': 'moe' });     * // => 'hello: moe'     *     * var list = '<% _.forEach(people, function(name) { %> <li><%= name %></li> <% }); %>'; -   * _.template(list, { 'people': ['moe', 'curly', 'larry'] }); -   * // => '<li>moe</li><li>curly</li><li>larry</li>' +   * _.template(list, { 'people': ['moe', 'larry', 'curly'] }); +   * // => '<li>moe</li><li>larry</li><li>curly</li>'     * -   * var template = _.template('<b><%- value %></b>'); -   * template({ 'value': '<script>' }); +   * // using the "escape" delimiter to escape HTML in data property values +   * _.template('<b><%- value %></b>', { 'value': '<script>' });     * // => '<b><script></b>'     * -   * // using `print` -   * var compiled = _.template('<% print("Hello " + epithet); %>'); -   * compiled({ 'epithet': 'stooge' }); +   * // using the internal `print` function in "evaluate" delimiters +   * _.template('<% print("Hello " + epithet); %>', { 'epithet': 'stooge' });     * // => 'Hello stooge.'     * -   * // using custom template settings +   * // using custom template delimiter settings     * _.templateSettings = {     *   'interpolate': /\{\{(.+?)\}\}/g     * };     * -   * var template = _.template('Hello {{ name }}!'); -   * template({ 'name': 'Mustache' }); +   * _.template('Hello {{ name }}!', { 'name': 'Mustache' });     * // => 'Hello Mustache!'     * -   * // using the `variable` option -   * _.template('<%= data.hasWith %>', { 'hasWith': 'no' }, { 'variable': 'data' }); -   * // => 'no' +   * // using the `variable` option to ensure a with-statement isn't used in the compiled template +   * var compiled = _.template('hello: <%= data.name %>', null, { 'variable': 'data' }); +   * compiled.source; +   * // => function(data) { +   *   var __t, __p = '', __e = _.escape; +   *   __p += 'hello: ' + ((__t = ( data.name )) == null ? '' : __t); +   *   return __p; +   * }     * -   * // using the `source` property -   * <script> -   *   JST.project = <%= _.template(jstText).source %>; -   * </script> +   * // using the `source` property to inline compiled templates for meaningful +   * // line numbers in error messages and a stack trace +   * fs.writeFileSync(path.join(cwd, 'jst.js'), '\ +   *   var JST = {\ +   *     "main": ' + _.template(mainText).source + '\ +   *   };\ +   * ');     */    function template(text, data, options) {      // based on John Resig's `tmpl` implementation @@ -3344,6 +3793,7 @@      // and Laura Doktorova's doT.js      // https://github.com/olado/doT      options || (options = {}); +    text += '';      var isEvaluating,          result, @@ -3351,14 +3801,17 @@          evaluateDelimiter = options.evaluate,          interpolateDelimiter = options.interpolate,          settings = lodash.templateSettings, -        variable = options.variable; +        variable = options.variable || settings.variable, +        hasVariable = variable;      // use default settings if no options object is provided      if (escapeDelimiter == null) {        escapeDelimiter = settings.escape;      }      if (evaluateDelimiter == null) { -      evaluateDelimiter = settings.evaluate; +      // use `false` as the fallback value, instead of leaving it `undefined`, +      // so the initial assignment of `reEvaluateDelimiter` will still occur +      evaluateDelimiter = settings.evaluate || false;      }      if (interpolateDelimiter == null) {        interpolateDelimiter = settings.interpolate; @@ -3376,8 +3829,8 @@        // and internal `<e%- %>`, `<e%= %>` delimiters        lastEvaluateDelimiter = evaluateDelimiter;        reEvaluateDelimiter = RegExp( -        (evaluateDelimiter ? evaluateDelimiter.source : '($^)') + -        '|<e%-([\\s\\S]+?)%>|<e%=([\\s\\S]+?)%>' +        '<e%-([\\s\\S]+?)%>|<e%=([\\s\\S]+?)%>' + +        (evaluateDelimiter ? '|' + evaluateDelimiter.source : '')        , 'g');      }      isEvaluating = tokenized.length; @@ -3393,11 +3846,11 @@      // clear stored code snippets      tokenized.length = 0; -    // if `options.variable` is not specified and the template contains "evaluate" +    // if `variable` is not specified and the template contains "evaluate"      // delimiters, wrap a with-statement around the generated code to add the      // data object to the top of the scope chain -    if (!variable) { -      variable = settings.variable || lastVariable || 'obj'; +    if (!hasVariable) { +      variable = lastVariable || 'obj';        if (isEvaluating) {          text = 'with (' + variable + ') {\n' + text + '\n}\n'; @@ -3423,12 +3876,12 @@      // frame code as the function body      text = 'function(' + variable + ') {\n' + -      variable + ' || (' + variable + ' = {});\n' + +      (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +        'var __t, __p = \'\', __e = _.escape' +        (isEvaluating          ? ', __j = Array.prototype.join;\n' +            'function print() { __p += __j.call(arguments, \'\') }\n' -        : ', __d = ' + variable + '.' + variable + ' || ' + variable + ';\n' +        : (hasVariable ? '' : ', __d = ' + variable + '.' + variable + ' || ' + variable) + ';\n'        ) +        text +        'return __p\n}'; @@ -3442,6 +3895,9 @@      try {        result = Function('_', 'return ' + text)(lodash);      } catch(e) { +      // defer syntax errors until the compiled template is executed to allow +      // examining the `source` property beforehand and for consistency, +      // because other template related errors occur at execution        result = function() { throw e; };      } @@ -3450,7 +3906,7 @@      }      // provide the compiled function's source via its `toString` method, in      // supported environments, or the `source` property as a convenience for -    // build time precompilation +    // inlining compiled templates during the build process      result.source = text;      return result;    } @@ -3544,7 +4000,7 @@     * @static     * @memberOf _     * @category Chaining -   * @param {Mixed} value The value to pass to `callback`. +   * @param {Mixed} value The value to pass to `interceptor`.     * @param {Function} interceptor The function to invoke.     * @returns {Mixed} Returns `value`.     * @example @@ -3605,7 +4061,7 @@     * @memberOf _     * @type String     */ -  lodash.VERSION = '0.4.2'; +  lodash.VERSION = '0.5.2';    // assign static methods    lodash.after = after; @@ -3616,11 +4072,13 @@    lodash.compact = compact;    lodash.compose = compose;    lodash.contains = contains; +  lodash.countBy = countBy;    lodash.debounce = debounce;    lodash.defaults = defaults;    lodash.defer = defer;    lodash.delay = delay;    lodash.difference = difference; +  lodash.drop = drop;    lodash.escape = escape;    lodash.every = every;    lodash.extend = extend; @@ -3661,6 +4119,7 @@    lodash.map = map;    lodash.max = max;    lodash.memoize = memoize; +  lodash.merge = merge;    lodash.min = min;    lodash.mixin = mixin;    lodash.noConflict = noConflict; @@ -3688,6 +4147,7 @@    lodash.uniq = uniq;    lodash.uniqueId = uniqueId;    lodash.values = values; +  lodash.where = where;    lodash.without = without;    lodash.wrap = wrap;    lodash.zip = zip; @@ -3800,4 +4260,4 @@      // in a browser or Rhino      window._ = lodash;    } -}(this));
\ No newline at end of file +}(this)); diff --git a/module/web/static/js/libs/require-2.0.5.js b/module/web/static/js/libs/require-2.0.6.js index 16bded58a..b592d5f22 100644 --- a/module/web/static/js/libs/require-2.0.5.js +++ b/module/web/static/js/libs/require-2.0.6.js @@ -1,5 +1,5 @@  /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.0.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.0.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.   * Available via the MIT or new BSD license.   * see: http://github.com/jrburke/requirejs for details   */ @@ -12,7 +12,7 @@ var requirejs, require, define;  (function (global) {      var req, s, head, baseElement, dataMain, src,          interactiveScript, currentlyAddingScript, mainScript, subPath, -        version = '2.0.5', +        version = '2.0.6',          commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,          cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,          jsSuffixRegExp = /\.js$/, @@ -612,7 +612,7 @@ var requirejs, require, define;              });          } -        function findCycle(mod, traced) { +        function findCycle(mod, traced, processed) {              var id = mod.map.id,                  depArray = mod.depMaps,                  foundModule; @@ -635,28 +635,16 @@ var requirejs, require, define;                  var depId = depMap.id,                      depMod = registry[depId]; -                if (!depMod) { +                if (!depMod || processed[depId] || +                        !depMod.inited || !depMod.enabled) {                      return;                  } -                if (!depMod.inited || !depMod.enabled) { -                    //Dependency is not inited, so this cannot -                    //be used to determine a cycle. -                    foundModule = null; -                    delete traced[id]; -                    return true; -                } - -                //mixin traced to a new object for each dependency, so that -                //sibling dependencies in this object to not generate a -                //false positive match on a cycle. Ideally an Object.create -                //type of prototype delegation would be used here, but -                //optimizing for file size vs. execution speed since hopefully -                //the trees are small for circular dependency scans relative -                //to the full app perf. -                return (foundModule = findCycle(depMod, mixin({}, traced))); +                return (foundModule = findCycle(depMod, traced, processed));              }); +            processed[id] = true; +              return foundModule;          } @@ -779,7 +767,7 @@ var requirejs, require, define;                          return;                      } -                    var cycleMod = findCycle(mod, {}), +                    var cycleMod = findCycle(mod, {}, {}),                          traced = {};                      if (cycleMod) { @@ -2050,4 +2038,4 @@ var requirejs, require, define;      //Set up with config info.      req(cfg); -}(this));
\ No newline at end of file +}(this)); diff --git a/module/web/static/js/models/model.js b/module/web/static/js/models/model.js index 2ea2db616..cd92e2644 100644 --- a/module/web/static/js/models/model.js +++ b/module/web/static/js/models/model.js @@ -3,7 +3,7 @@ define(['jquery', 'backbone'], function($, Backbone) {      var Model = Backbone.Model.extend({              defaults: { -	            message: "You are now using Backbone, Lodash, Require, Modernizr, and jQuery! (Click Me)" +                message: "You are now using Backbone, Lodash, Require, Modernizr, and jQuery! (Click Me)"              },              // Model Constructor diff --git a/module/web/static/js/plugins/text-2.0.3.js b/module/web/static/js/plugins/text-2.0.3.js new file mode 100644 index 000000000..bf61a3fe4 --- /dev/null +++ b/module/web/static/js/plugins/text-2.0.3.js @@ -0,0 +1,308 @@ +/** + * @license RequireJS text 2.0.3 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/requirejs/text for details + */ +/*jslint regexp: true */ +/*global require: false, XMLHttpRequest: false, ActiveXObject: false, +  define: false, window: false, process: false, Packages: false, +  java: false, location: false */ + +define(['module'], function (module) { +    'use strict'; + +    var text, fs, +        progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], +        xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, +        bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im, +        hasLocation = typeof location !== 'undefined' && location.href, +        defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), +        defaultHostName = hasLocation && location.hostname, +        defaultPort = hasLocation && (location.port || undefined), +        buildMap = [], +        masterConfig = (module.config && module.config()) || {}; + +    text = { +        version: '2.0.3', + +        strip: function (content) { +            //Strips <?xml ...?> declarations so that external SVG and XML +            //documents can be added to a document without worry. Also, if the string +            //is an HTML document, only the part inside the body tag is returned. +            if (content) { +                content = content.replace(xmlRegExp, ""); +                var matches = content.match(bodyRegExp); +                if (matches) { +                    content = matches[1]; +                } +            } else { +                content = ""; +            } +            return content; +        }, + +        jsEscape: function (content) { +            return content.replace(/(['\\])/g, '\\$1') +                .replace(/[\f]/g, "\\f") +                .replace(/[\b]/g, "\\b") +                .replace(/[\n]/g, "\\n") +                .replace(/[\t]/g, "\\t") +                .replace(/[\r]/g, "\\r") +                .replace(/[\u2028]/g, "\\u2028") +                .replace(/[\u2029]/g, "\\u2029"); +        }, + +        createXhr: masterConfig.createXhr || function () { +            //Would love to dump the ActiveX crap in here. Need IE 6 to die first. +            var xhr, i, progId; +            if (typeof XMLHttpRequest !== "undefined") { +                return new XMLHttpRequest(); +            } else if (typeof ActiveXObject !== "undefined") { +                for (i = 0; i < 3; i += 1) { +                    progId = progIds[i]; +                    try { +                        xhr = new ActiveXObject(progId); +                    } catch (e) {} + +                    if (xhr) { +                        progIds = [progId];  // so faster next time +                        break; +                    } +                } +            } + +            return xhr; +        }, + +        /** +         * Parses a resource name into its component parts. Resource names +         * look like: module/name.ext!strip, where the !strip part is +         * optional. +         * @param {String} name the resource name +         * @returns {Object} with properties "moduleName", "ext" and "strip" +         * where strip is a boolean. +         */ +        parseName: function (name) { +            var strip = false, index = name.indexOf("."), +                modName = name.substring(0, index), +                ext = name.substring(index + 1, name.length); + +            index = ext.indexOf("!"); +            if (index !== -1) { +                //Pull off the strip arg. +                strip = ext.substring(index + 1, ext.length); +                strip = strip === "strip"; +                ext = ext.substring(0, index); +            } + +            return { +                moduleName: modName, +                ext: ext, +                strip: strip +            }; +        }, + +        xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, + +        /** +         * Is an URL on another domain. Only works for browser use, returns +         * false in non-browser environments. Only used to know if an +         * optimized .js version of a text resource should be loaded +         * instead. +         * @param {String} url +         * @returns Boolean +         */ +        useXhr: function (url, protocol, hostname, port) { +            var uProtocol, uHostName, uPort, +                match = text.xdRegExp.exec(url); +            if (!match) { +                return true; +            } +            uProtocol = match[2]; +            uHostName = match[3]; + +            uHostName = uHostName.split(':'); +            uPort = uHostName[1]; +            uHostName = uHostName[0]; + +            return (!uProtocol || uProtocol === protocol) && +                   (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && +                   ((!uPort && !uHostName) || uPort === port); +        }, + +        finishLoad: function (name, strip, content, onLoad) { +            content = strip ? text.strip(content) : content; +            if (masterConfig.isBuild) { +                buildMap[name] = content; +            } +            onLoad(content); +        }, + +        load: function (name, req, onLoad, config) { +            //Name has format: some.module.filext!strip +            //The strip part is optional. +            //if strip is present, then that means only get the string contents +            //inside a body tag in an HTML string. For XML/SVG content it means +            //removing the <?xml ...?> declarations so the content can be inserted +            //into the current doc without problems. + +            // Do not bother with the work if a build and text will +            // not be inlined. +            if (config.isBuild && !config.inlineText) { +                onLoad(); +                return; +            } + +            masterConfig.isBuild = config.isBuild; + +            var parsed = text.parseName(name), +                nonStripName = parsed.moduleName + '.' + parsed.ext, +                url = req.toUrl(nonStripName), +                useXhr = (masterConfig.useXhr) || +                         text.useXhr; + +            //Load the text. Use XHR if possible and in a browser. +            if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { +                text.get(url, function (content) { +                    text.finishLoad(name, parsed.strip, content, onLoad); +                }, function (err) { +                    if (onLoad.error) { +                        onLoad.error(err); +                    } +                }); +            } else { +                //Need to fetch the resource across domains. Assume +                //the resource has been optimized into a JS module. Fetch +                //by the module name + extension, but do not include the +                //!strip part to avoid file system issues. +                req([nonStripName], function (content) { +                    text.finishLoad(parsed.moduleName + '.' + parsed.ext, +                                    parsed.strip, content, onLoad); +                }); +            } +        }, + +        write: function (pluginName, moduleName, write, config) { +            if (buildMap.hasOwnProperty(moduleName)) { +                var content = text.jsEscape(buildMap[moduleName]); +                write.asModule(pluginName + "!" + moduleName, +                               "define(function () { return '" + +                                   content + +                               "';});\n"); +            } +        }, + +        writeFile: function (pluginName, moduleName, req, write, config) { +            var parsed = text.parseName(moduleName), +                nonStripName = parsed.moduleName + '.' + parsed.ext, +                //Use a '.js' file name so that it indicates it is a +                //script that can be loaded across domains. +                fileName = req.toUrl(parsed.moduleName + '.' + +                                     parsed.ext) + '.js'; + +            //Leverage own load() method to load plugin value, but only +            //write out values that do not have the strip argument, +            //to avoid any potential issues with ! in file names. +            text.load(nonStripName, req, function (value) { +                //Use own write() method to construct full module value. +                //But need to create shell that translates writeFile's +                //write() to the right interface. +                var textWrite = function (contents) { +                    return write(fileName, contents); +                }; +                textWrite.asModule = function (moduleName, contents) { +                    return write.asModule(moduleName, fileName, contents); +                }; + +                text.write(pluginName, nonStripName, textWrite, config); +            }, config); +        } +    }; + +    if (masterConfig.env === 'node' || (!masterConfig.env && +            typeof process !== "undefined" && +            process.versions && +            !!process.versions.node)) { +        //Using special require.nodeRequire, something added by r.js. +        fs = require.nodeRequire('fs'); + +        text.get = function (url, callback) { +            var file = fs.readFileSync(url, 'utf8'); +            //Remove BOM (Byte Mark Order) from utf8 files if it is there. +            if (file.indexOf('\uFEFF') === 0) { +                file = file.substring(1); +            } +            callback(file); +        }; +    } else if (masterConfig.env === 'xhr' || (!masterConfig.env && +            text.createXhr())) { +        text.get = function (url, callback, errback) { +            var xhr = text.createXhr(); +            xhr.open('GET', url, true); + +            //Allow overrides specified in config +            if (masterConfig.onXhr) { +                masterConfig.onXhr(xhr, url); +            } + +            xhr.onreadystatechange = function (evt) { +                var status, err; +                //Do not explicitly handle errors, those should be +                //visible via console output in the browser. +                if (xhr.readyState === 4) { +                    status = xhr.status; +                    if (status > 399 && status < 600) { +                        //An http 4xx or 5xx error. Signal an error. +                        err = new Error(url + ' HTTP status: ' + status); +                        err.xhr = xhr; +                        errback(err); +                    } else { +                        callback(xhr.responseText); +                    } +                } +            }; +            xhr.send(null); +        }; +    } else if (masterConfig.env === 'rhino' || (!masterConfig.env && +            typeof Packages !== 'undefined' && typeof java !== 'undefined')) { +        //Why Java, why is this so awkward? +        text.get = function (url, callback) { +            var stringBuffer, line, +                encoding = "utf-8", +                file = new java.io.File(url), +                lineSeparator = java.lang.System.getProperty("line.separator"), +                input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), +                content = ''; +            try { +                stringBuffer = new java.lang.StringBuffer(); +                line = input.readLine(); + +                // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 +                // http://www.unicode.org/faq/utf_bom.html + +                // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: +                // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 +                if (line && line.length() && line.charAt(0) === 0xfeff) { +                    // Eat the BOM, since we've already found the encoding on this file, +                    // and we plan to concatenating this buffer with others; the BOM should +                    // only appear at the top of a file. +                    line = line.substring(1); +                } + +                stringBuffer.append(line); + +                while ((line = input.readLine()) !== null) { +                    stringBuffer.append(lineSeparator); +                    stringBuffer.append(line); +                } +                //Make sure we return a JavaScript string and not a Java string. +                content = String(stringBuffer.toString()); //String +            } finally { +                input.close(); +            } +            callback(content); +        }; +    } + +    return text; +}); diff --git a/module/web/templates/default/base.html b/module/web/templates/default/base.html index 411d7e2bb..f611596d8 100644 --- a/module/web/templates/default/base.html +++ b/module/web/templates/default/base.html @@ -1,7 +1,11 @@  <!DOCTYPE html>
  <html>
  <head>
 -    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 +    <meta charset="utf-8">
 +    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
 +    <title>{% block title %}pyLoad {{ _("Webinterface") }}{% endblock %}</title>
 +    <meta name="description" content="pyLoad {{ _("Webinterface") }}">
 +    <meta name="viewport" content="width=device-width">
      <!-- TODO Include this font -->
      <link href="http://fonts.googleapis.com/css?family=Abel" rel="stylesheet" type="text/css"/>
 @@ -11,15 +15,13 @@      <link href="static/css/jquery.qtip.min.css" rel="stylesheet" type="text/css" media="screen"/>
      <link href="static/css/omniwindow.css" rel="stylesheet" type="text/css" media="screen"/>
 -    <script type="text/javascript" data-main="static/js/default" src="static/js/libs/require-2.0.5.js"></script>
 +    <script type="text/javascript" data-main="static/js/default" src="static/js/libs/require-2.0.6.js"></script>
      <script>
          require(['default'], function (App) {
              App.init();
          });
      </script>
 -    <title>{% block title %}pyLoad {{ _("Webinterface") }}{% endblock %}</title>
 -
      {% block head %}
      {% endblock %}
  </head>
 @@ -67,7 +69,6 @@              <h1>Close me!</h1>
              <a class='close-button' href='#'>X</a>
          </div>
 -        <a id="dialog_open" href="#">Show Dialog</a>
          {% block content %}
          {% endblock content %}
      </div>
 | 
