Completed
Push — master ( c853f7...ca1a51 )
by Craig
46:06 queued 30:37
created

underscore.js ➔ ... ➔ _.unique   C

Complexity

Conditions 11
Paths 28

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 11
nc 28
nop 4
dl 0
loc 26
rs 5.2653
c 1
b 1
f 0

How to fix   Complexity   

Complexity

Complex classes like underscore.js ➔ ... ➔ _.unique often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
//     Underscore.js 1.8.3
2
//     http://underscorejs.org
3
//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4
//     Underscore may be freely distributed under the MIT license.
5
6
(function() {
7
8
  // Baseline setup
9
  // --------------
10
11
  // Establish the root object, `window` in the browser, or `exports` on the server.
12
  var root = this;
13
14
  // Save the previous value of the `_` variable.
15
  var previousUnderscore = root._;
16
17
  // Save bytes in the minified (but not gzipped) version:
18
  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
19
20
  // Create quick reference variables for speed access to core prototypes.
21
  var
22
    push             = ArrayProto.push,
23
    slice            = ArrayProto.slice,
24
    toString         = ObjProto.toString,
25
    hasOwnProperty   = ObjProto.hasOwnProperty;
26
27
  // All **ECMAScript 5** native function implementations that we hope to use
28
  // are declared here.
29
  var
30
    nativeIsArray      = Array.isArray,
31
    nativeKeys         = Object.keys,
32
    nativeBind         = FuncProto.bind,
33
    nativeCreate       = Object.create;
34
35
  // Naked function reference for surrogate-prototype-swapping.
36
  var Ctor = function(){};
37
38
  // Create a safe reference to the Underscore object for use below.
39
  var _ = function(obj) {
40
    if (obj instanceof _) return obj;
41
    if (!(this instanceof _)) return new _(obj);
42
    this._wrapped = obj;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
43
  };
44
45
  // Export the Underscore object for **Node.js**, with
46
  // backwards-compatibility for the old `require()` API. If we're in
47
  // the browser, add `_` as a global object.
48
  if (typeof exports !== 'undefined') {
49
    if (typeof module !== 'undefined' && module.exports) {
50
      exports = module.exports = _;
51
    }
52
    exports._ = _;
53
  } else {
54
    root._ = _;
55
  }
56
57
  // Current version.
58
  _.VERSION = '1.8.3';
59
60
  // Internal function that returns an efficient (for current engines) version
61
  // of the passed-in callback, to be repeatedly applied in other Underscore
62
  // functions.
63
  var optimizeCb = function(func, context, argCount) {
64
    if (context === void 0) return func;
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
65
    switch (argCount == null ? 3 : argCount) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
66
      case 1: return function(value) {
67
        return func.call(context, value);
68
      };
69
      case 2: return function(value, other) {
70
        return func.call(context, value, other);
71
      };
72
      case 3: return function(value, index, collection) {
73
        return func.call(context, value, index, collection);
74
      };
75
      case 4: return function(accumulator, value, index, collection) {
76
        return func.call(context, accumulator, value, index, collection);
77
      };
78
    }
79
    return function() {
80
      return func.apply(context, arguments);
81
    };
82
  };
83
84
  // A mostly-internal function to generate callbacks that can be applied
85
  // to each element in a collection, returning the desired result — either
86
  // identity, an arbitrary callback, a property matcher, or a property accessor.
87
  var cb = function(value, context, argCount) {
88
    if (value == null) return _.identity;
89
    if (_.isFunction(value)) return optimizeCb(value, context, argCount);
90
    if (_.isObject(value)) return _.matcher(value);
91
    return _.property(value);
92
  };
93
  _.iteratee = function(value, context) {
94
    return cb(value, context, Infinity);
95
  };
96
97
  // An internal function for creating assigner functions.
98
  var createAssigner = function(keysFunc, undefinedOnly) {
99
    return function(obj) {
100
      var length = arguments.length;
101
      if (length < 2 || obj == null) return obj;
102
      for (var index = 1; index < length; index++) {
103
        var source = arguments[index],
104
            keys = keysFunc(source),
105
            l = keys.length;
106
        for (var i = 0; i < l; i++) {
107
          var key = keys[i];
108
          if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
109
        }
110
      }
111
      return obj;
112
    };
113
  };
114
115
  // An internal function for creating a new object that inherits from another.
116
  var baseCreate = function(prototype) {
117
    if (!_.isObject(prototype)) return {};
118
    if (nativeCreate) return nativeCreate(prototype);
119
    Ctor.prototype = prototype;
120
    var result = new Ctor;
121
    Ctor.prototype = null;
122
    return result;
123
  };
124
125
  var property = function(key) {
126
    return function(obj) {
127
      return obj == null ? void 0 : obj[key];
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
128
    };
129
  };
130
131
  // Helper for collection methods to determine whether a collection
132
  // should be iterated as an array or as an object
133
  // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
134
  // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
135
  var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
136
  var getLength = property('length');
137
  var isArrayLike = function(collection) {
138
    var length = getLength(collection);
139
    return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
140
  };
141
142
  // Collection Functions
143
  // --------------------
144
145
  // The cornerstone, an `each` implementation, aka `forEach`.
146
  // Handles raw objects in addition to array-likes. Treats all
147
  // sparse array-likes as if they were dense.
148
  _.each = _.forEach = function(obj, iteratee, context) {
149
    iteratee = optimizeCb(iteratee, context);
150
    var i, length;
151
    if (isArrayLike(obj)) {
152
      for (i = 0, length = obj.length; i < length; i++) {
153
        iteratee(obj[i], i, obj);
154
      }
155
    } else {
156
      var keys = _.keys(obj);
157
      for (i = 0, length = keys.length; i < length; i++) {
158
        iteratee(obj[keys[i]], keys[i], obj);
159
      }
160
    }
161
    return obj;
162
  };
163
164
  // Return the results of applying the iteratee to each element.
165
  _.map = _.collect = function(obj, iteratee, context) {
166
    iteratee = cb(iteratee, context);
167
    var keys = !isArrayLike(obj) && _.keys(obj),
168
        length = (keys || obj).length,
169
        results = Array(length);
170
    for (var index = 0; index < length; index++) {
171
      var currentKey = keys ? keys[index] : index;
172
      results[index] = iteratee(obj[currentKey], currentKey, obj);
173
    }
174
    return results;
175
  };
176
177
  // Create a reducing function iterating left or right.
178
  function createReduce(dir) {
179
    // Optimized iterator function as using arguments.length
180
    // in the main function will deoptimize the, see #1991.
181
    function iterator(obj, iteratee, memo, keys, index, length) {
182
      for (; index >= 0 && index < length; index += dir) {
183
        var currentKey = keys ? keys[index] : index;
184
        memo = iteratee(memo, obj[currentKey], currentKey, obj);
185
      }
186
      return memo;
187
    }
188
189
    return function(obj, iteratee, memo, context) {
190
      iteratee = optimizeCb(iteratee, context, 4);
191
      var keys = !isArrayLike(obj) && _.keys(obj),
192
          length = (keys || obj).length,
193
          index = dir > 0 ? 0 : length - 1;
194
      // Determine the initial value if none is provided.
195
      if (arguments.length < 3) {
196
        memo = obj[keys ? keys[index] : index];
197
        index += dir;
198
      }
199
      return iterator(obj, iteratee, memo, keys, index, length);
200
    };
201
  }
202
203
  // **Reduce** builds up a single result from a list of values, aka `inject`,
204
  // or `foldl`.
205
  _.reduce = _.foldl = _.inject = createReduce(1);
206
207
  // The right-associative version of reduce, also known as `foldr`.
208
  _.reduceRight = _.foldr = createReduce(-1);
209
210
  // Return the first value which passes a truth test. Aliased as `detect`.
211
  _.find = _.detect = function(obj, predicate, context) {
212
    var key;
213
    if (isArrayLike(obj)) {
214
      key = _.findIndex(obj, predicate, context);
215
    } else {
216
      key = _.findKey(obj, predicate, context);
217
    }
218
    if (key !== void 0 && key !== -1) return obj[key];
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
Complexity Best Practice introduced by
There is no return statement if key !== void(0) && key !== -1 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
219
  };
220
221
  // Return all the elements that pass a truth test.
222
  // Aliased as `select`.
223
  _.filter = _.select = function(obj, predicate, context) {
224
    var results = [];
225
    predicate = cb(predicate, context);
226
    _.each(obj, function(value, index, list) {
227
      if (predicate(value, index, list)) results.push(value);
228
    });
229
    return results;
230
  };
231
232
  // Return all the elements for which a truth test fails.
233
  _.reject = function(obj, predicate, context) {
234
    return _.filter(obj, _.negate(cb(predicate)), context);
235
  };
236
237
  // Determine whether all of the elements match a truth test.
238
  // Aliased as `all`.
239
  _.every = _.all = function(obj, predicate, context) {
240
    predicate = cb(predicate, context);
241
    var keys = !isArrayLike(obj) && _.keys(obj),
242
        length = (keys || obj).length;
243
    for (var index = 0; index < length; index++) {
244
      var currentKey = keys ? keys[index] : index;
245
      if (!predicate(obj[currentKey], currentKey, obj)) return false;
246
    }
247
    return true;
248
  };
249
250
  // Determine if at least one element in the object matches a truth test.
251
  // Aliased as `any`.
252
  _.some = _.any = function(obj, predicate, context) {
253
    predicate = cb(predicate, context);
254
    var keys = !isArrayLike(obj) && _.keys(obj),
255
        length = (keys || obj).length;
256
    for (var index = 0; index < length; index++) {
257
      var currentKey = keys ? keys[index] : index;
258
      if (predicate(obj[currentKey], currentKey, obj)) return true;
259
    }
260
    return false;
261
  };
262
263
  // Determine if the array or object contains a given item (using `===`).
264
  // Aliased as `includes` and `include`.
265
  _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
266
    if (!isArrayLike(obj)) obj = _.values(obj);
267
    if (typeof fromIndex != 'number' || guard) fromIndex = 0;
268
    return _.indexOf(obj, item, fromIndex) >= 0;
269
  };
270
271
  // Invoke a method (with arguments) on every item in a collection.
272
  _.invoke = function(obj, method) {
273
    var args = slice.call(arguments, 2);
274
    var isFunc = _.isFunction(method);
275
    return _.map(obj, function(value) {
276
      var func = isFunc ? method : value[method];
277
      return func == null ? func : func.apply(value, args);
278
    });
279
  };
280
281
  // Convenience version of a common use case of `map`: fetching a property.
282
  _.pluck = function(obj, key) {
283
    return _.map(obj, _.property(key));
284
  };
285
286
  // Convenience version of a common use case of `filter`: selecting only objects
287
  // containing specific `key:value` pairs.
288
  _.where = function(obj, attrs) {
289
    return _.filter(obj, _.matcher(attrs));
290
  };
291
292
  // Convenience version of a common use case of `find`: getting the first object
293
  // containing specific `key:value` pairs.
294
  _.findWhere = function(obj, attrs) {
295
    return _.find(obj, _.matcher(attrs));
296
  };
297
298
  // Return the maximum element (or element-based computation).
299
  _.max = function(obj, iteratee, context) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
300
    var result = -Infinity, lastComputed = -Infinity,
301
        value, computed;
302
    if (iteratee == null && obj != null) {
303
      obj = isArrayLike(obj) ? obj : _.values(obj);
304
      for (var i = 0, length = obj.length; i < length; i++) {
305
        value = obj[i];
306
        if (value > result) {
307
          result = value;
308
        }
309
      }
310
    } else {
311
      iteratee = cb(iteratee, context);
312
      _.each(obj, function(value, index, list) {
313
        computed = iteratee(value, index, list);
314
        if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
315
          result = value;
316
          lastComputed = computed;
317
        }
318
      });
319
    }
320
    return result;
321
  };
322
323
  // Return the minimum element (or element-based computation).
324
  _.min = function(obj, iteratee, context) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
325
    var result = Infinity, lastComputed = Infinity,
0 ignored issues
show
Comprehensibility Best Practice introduced by
You seem to be aliasing the built-in name Infinity as result. This makes your code very difficult to follow, consider using the built-in name directly.
Loading history...
326
        value, computed;
327
    if (iteratee == null && obj != null) {
328
      obj = isArrayLike(obj) ? obj : _.values(obj);
329
      for (var i = 0, length = obj.length; i < length; i++) {
330
        value = obj[i];
331
        if (value < result) {
332
          result = value;
333
        }
334
      }
335
    } else {
336
      iteratee = cb(iteratee, context);
337
      _.each(obj, function(value, index, list) {
338
        computed = iteratee(value, index, list);
339
        if (computed < lastComputed || computed === Infinity && result === Infinity) {
340
          result = value;
341
          lastComputed = computed;
342
        }
343
      });
344
    }
345
    return result;
346
  };
347
348
  // Shuffle a collection, using the modern version of the
349
  // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
350
  _.shuffle = function(obj) {
351
    var set = isArrayLike(obj) ? obj : _.values(obj);
352
    var length = set.length;
353
    var shuffled = Array(length);
354
    for (var index = 0, rand; index < length; index++) {
355
      rand = _.random(0, index);
356
      if (rand !== index) shuffled[index] = shuffled[rand];
357
      shuffled[rand] = set[index];
358
    }
359
    return shuffled;
360
  };
361
362
  // Sample **n** random values from a collection.
363
  // If **n** is not specified, returns a single random element.
364
  // The internal `guard` argument allows it to work with `map`.
365
  _.sample = function(obj, n, guard) {
366
    if (n == null || guard) {
367
      if (!isArrayLike(obj)) obj = _.values(obj);
368
      return obj[_.random(obj.length - 1)];
369
    }
370
    return _.shuffle(obj).slice(0, Math.max(0, n));
371
  };
372
373
  // Sort the object's values by a criterion produced by an iteratee.
374
  _.sortBy = function(obj, iteratee, context) {
375
    iteratee = cb(iteratee, context);
376
    return _.pluck(_.map(obj, function(value, index, list) {
377
      return {
378
        value: value,
379
        index: index,
380
        criteria: iteratee(value, index, list)
381
      };
382
    }).sort(function(left, right) {
383
      var a = left.criteria;
384
      var b = right.criteria;
385
      if (a !== b) {
386
        if (a > b || a === void 0) return 1;
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
387
        if (a < b || b === void 0) return -1;
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
388
      }
389
      return left.index - right.index;
390
    }), 'value');
391
  };
392
393
  // An internal function used for aggregate "group by" operations.
394
  var group = function(behavior) {
395
    return function(obj, iteratee, context) {
396
      var result = {};
397
      iteratee = cb(iteratee, context);
398
      _.each(obj, function(value, index) {
399
        var key = iteratee(value, index, obj);
400
        behavior(result, value, key);
401
      });
402
      return result;
403
    };
404
  };
405
406
  // Groups the object's values by a criterion. Pass either a string attribute
407
  // to group by, or a function that returns the criterion.
408
  _.groupBy = group(function(result, value, key) {
409
    if (_.has(result, key)) result[key].push(value); else result[key] = [value];
410
  });
411
412
  // Indexes the object's values by a criterion, similar to `groupBy`, but for
413
  // when you know that your index values will be unique.
414
  _.indexBy = group(function(result, value, key) {
415
    result[key] = value;
416
  });
417
418
  // Counts instances of an object that group by a certain criterion. Pass
419
  // either a string attribute to count by, or a function that returns the
420
  // criterion.
421
  _.countBy = group(function(result, value, key) {
422
    if (_.has(result, key)) result[key]++; else result[key] = 1;
423
  });
424
425
  // Safely create a real, live array from anything iterable.
426
  _.toArray = function(obj) {
427
    if (!obj) return [];
428
    if (_.isArray(obj)) return slice.call(obj);
429
    if (isArrayLike(obj)) return _.map(obj, _.identity);
430
    return _.values(obj);
431
  };
432
433
  // Return the number of elements in an object.
434
  _.size = function(obj) {
435
    if (obj == null) return 0;
436
    return isArrayLike(obj) ? obj.length : _.keys(obj).length;
437
  };
438
439
  // Split a collection into two arrays: one whose elements all satisfy the given
440
  // predicate, and one whose elements all do not satisfy the predicate.
441
  _.partition = function(obj, predicate, context) {
442
    predicate = cb(predicate, context);
443
    var pass = [], fail = [];
444
    _.each(obj, function(value, key, obj) {
445
      (predicate(value, key, obj) ? pass : fail).push(value);
446
    });
447
    return [pass, fail];
448
  };
449
450
  // Array Functions
451
  // ---------------
452
453
  // Get the first element of an array. Passing **n** will return the first N
454
  // values in the array. Aliased as `head` and `take`. The **guard** check
455
  // allows it to work with `_.map`.
456
  _.first = _.head = _.take = function(array, n, guard) {
457
    if (array == null) return void 0;
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
458
    if (n == null || guard) return array[0];
459
    return _.initial(array, array.length - n);
460
  };
461
462
  // Returns everything but the last entry of the array. Especially useful on
463
  // the arguments object. Passing **n** will return all the values in
464
  // the array, excluding the last N.
465
  _.initial = function(array, n, guard) {
466
    return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
467
  };
468
469
  // Get the last element of an array. Passing **n** will return the last N
470
  // values in the array.
471
  _.last = function(array, n, guard) {
472
    if (array == null) return void 0;
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
473
    if (n == null || guard) return array[array.length - 1];
474
    return _.rest(array, Math.max(0, array.length - n));
475
  };
476
477
  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
478
  // Especially useful on the arguments object. Passing an **n** will return
479
  // the rest N values in the array.
480
  _.rest = _.tail = _.drop = function(array, n, guard) {
481
    return slice.call(array, n == null || guard ? 1 : n);
482
  };
483
484
  // Trim out all falsy values from an array.
485
  _.compact = function(array) {
486
    return _.filter(array, _.identity);
487
  };
488
489
  // Internal implementation of a recursive `flatten` function.
490
  var flatten = function(input, shallow, strict, startIndex) {
491
    var output = [], idx = 0;
492
    for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
493
      var value = input[i];
494
      if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
495
        //flatten current level of array or arguments object
496
        if (!shallow) value = flatten(value, shallow, strict);
497
        var j = 0, len = value.length;
498
        output.length += len;
499
        while (j < len) {
500
          output[idx++] = value[j++];
501
        }
502
      } else if (!strict) {
503
        output[idx++] = value;
504
      }
505
    }
506
    return output;
507
  };
508
509
  // Flatten out an array, either recursively (by default), or just one level.
510
  _.flatten = function(array, shallow) {
511
    return flatten(array, shallow, false);
512
  };
513
514
  // Return a version of the array that does not contain the specified value(s).
515
  _.without = function(array) {
516
    return _.difference(array, slice.call(arguments, 1));
517
  };
518
519
  // Produce a duplicate-free version of the array. If the array has already
520
  // been sorted, you have the option of using a faster algorithm.
521
  // Aliased as `unique`.
522
  _.uniq = _.unique = function(array, isSorted, iteratee, context) {
523
    if (!_.isBoolean(isSorted)) {
524
      context = iteratee;
525
      iteratee = isSorted;
526
      isSorted = false;
527
    }
528
    if (iteratee != null) iteratee = cb(iteratee, context);
529
    var result = [];
530
    var seen = [];
531
    for (var i = 0, length = getLength(array); i < length; i++) {
532
      var value = array[i],
533
          computed = iteratee ? iteratee(value, i, array) : value;
534
      if (isSorted) {
535
        if (!i || seen !== computed) result.push(value);
536
        seen = computed;
537
      } else if (iteratee) {
538
        if (!_.contains(seen, computed)) {
539
          seen.push(computed);
540
          result.push(value);
541
        }
542
      } else if (!_.contains(result, value)) {
543
        result.push(value);
544
      }
545
    }
546
    return result;
547
  };
548
549
  // Produce an array that contains the union: each distinct element from all of
550
  // the passed-in arrays.
551
  _.union = function() {
552
    return _.uniq(flatten(arguments, true, true));
553
  };
554
555
  // Produce an array that contains every item shared between all the
556
  // passed-in arrays.
557
  _.intersection = function(array) {
558
    var result = [];
559
    var argsLength = arguments.length;
560
    for (var i = 0, length = getLength(array); i < length; i++) {
561
      var item = array[i];
562
      if (_.contains(result, item)) continue;
563
      for (var j = 1; j < argsLength; j++) {
564
        if (!_.contains(arguments[j], item)) break;
565
      }
566
      if (j === argsLength) result.push(item);
567
    }
568
    return result;
569
  };
570
571
  // Take the difference between one array and a number of other arrays.
572
  // Only the elements present in just the first array will remain.
573
  _.difference = function(array) {
574
    var rest = flatten(arguments, true, true, 1);
575
    return _.filter(array, function(value){
576
      return !_.contains(rest, value);
577
    });
578
  };
579
580
  // Zip together multiple lists into a single array -- elements that share
581
  // an index go together.
582
  _.zip = function() {
583
    return _.unzip(arguments);
584
  };
585
586
  // Complement of _.zip. Unzip accepts an array of arrays and groups
587
  // each array's elements on shared indices
588
  _.unzip = function(array) {
589
    var length = array && _.max(array, getLength).length || 0;
590
    var result = Array(length);
591
592
    for (var index = 0; index < length; index++) {
593
      result[index] = _.pluck(array, index);
594
    }
595
    return result;
596
  };
597
598
  // Converts lists into objects. Pass either a single array of `[key, value]`
599
  // pairs, or two parallel arrays of the same length -- one of keys, and one of
600
  // the corresponding values.
601
  _.object = function(list, values) {
602
    var result = {};
603
    for (var i = 0, length = getLength(list); i < length; i++) {
604
      if (values) {
605
        result[list[i]] = values[i];
606
      } else {
607
        result[list[i][0]] = list[i][1];
608
      }
609
    }
610
    return result;
611
  };
612
613
  // Generator function to create the findIndex and findLastIndex functions
614
  function createPredicateIndexFinder(dir) {
615
    return function(array, predicate, context) {
616
      predicate = cb(predicate, context);
617
      var length = getLength(array);
618
      var index = dir > 0 ? 0 : length - 1;
619
      for (; index >= 0 && index < length; index += dir) {
620
        if (predicate(array[index], index, array)) return index;
621
      }
622
      return -1;
623
    };
624
  }
625
626
  // Returns the first index on an array-like that passes a predicate test
627
  _.findIndex = createPredicateIndexFinder(1);
628
  _.findLastIndex = createPredicateIndexFinder(-1);
629
630
  // Use a comparator function to figure out the smallest index at which
631
  // an object should be inserted so as to maintain order. Uses binary search.
632
  _.sortedIndex = function(array, obj, iteratee, context) {
633
    iteratee = cb(iteratee, context, 1);
634
    var value = iteratee(obj);
635
    var low = 0, high = getLength(array);
636
    while (low < high) {
637
      var mid = Math.floor((low + high) / 2);
638
      if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
639
    }
640
    return low;
641
  };
642
643
  // Generator function to create the indexOf and lastIndexOf functions
644
  function createIndexFinder(dir, predicateFind, sortedIndex) {
645
    return function(array, item, idx) {
646
      var i = 0, length = getLength(array);
647
      if (typeof idx == 'number') {
648
        if (dir > 0) {
649
            i = idx >= 0 ? idx : Math.max(idx + length, i);
650
        } else {
651
            length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
652
        }
653
      } else if (sortedIndex && idx && length) {
654
        idx = sortedIndex(array, item);
655
        return array[idx] === item ? idx : -1;
656
      }
657
      if (item !== item) {
658
        idx = predicateFind(slice.call(array, i, length), _.isNaN);
659
        return idx >= 0 ? idx + i : -1;
660
      }
661
      for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
662
        if (array[idx] === item) return idx;
663
      }
664
      return -1;
665
    };
666
  }
667
668
  // Return the position of the first occurrence of an item in an array,
669
  // or -1 if the item is not included in the array.
670
  // If the array is large and already in sort order, pass `true`
671
  // for **isSorted** to use binary search.
672
  _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
673
  _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
674
675
  // Generate an integer Array containing an arithmetic progression. A port of
676
  // the native Python `range()` function. See
677
  // [the Python documentation](http://docs.python.org/library/functions.html#range).
678
  _.range = function(start, stop, step) {
679
    if (stop == null) {
680
      stop = start || 0;
681
      start = 0;
682
    }
683
    step = step || 1;
684
685
    var length = Math.max(Math.ceil((stop - start) / step), 0);
686
    var range = Array(length);
687
688
    for (var idx = 0; idx < length; idx++, start += step) {
689
      range[idx] = start;
690
    }
691
692
    return range;
693
  };
694
695
  // Function (ahem) Functions
696
  // ------------------
697
698
  // Determines whether to execute a function as a constructor
699
  // or a normal function with the provided arguments
700
  var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
701
    if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
702
    var self = baseCreate(sourceFunc.prototype);
703
    var result = sourceFunc.apply(self, args);
704
    if (_.isObject(result)) return result;
705
    return self;
706
  };
707
708
  // Create a function bound to a given object (assigning `this`, and arguments,
709
  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
710
  // available.
711
  _.bind = function(func, context) {
712
    if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
713
    if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
714
    var args = slice.call(arguments, 2);
715
    var bound = function() {
716
      return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
717
    };
718
    return bound;
719
  };
720
721
  // Partially apply a function by creating a version that has had some of its
722
  // arguments pre-filled, without changing its dynamic `this` context. _ acts
723
  // as a placeholder, allowing any combination of arguments to be pre-filled.
724
  _.partial = function(func) {
725
    var boundArgs = slice.call(arguments, 1);
726
    var bound = function() {
727
      var position = 0, length = boundArgs.length;
728
      var args = Array(length);
729
      for (var i = 0; i < length; i++) {
730
        args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
731
      }
732
      while (position < arguments.length) args.push(arguments[position++]);
733
      return executeBound(func, bound, this, this, args);
734
    };
735
    return bound;
736
  };
737
738
  // Bind a number of an object's methods to that object. Remaining arguments
739
  // are the method names to be bound. Useful for ensuring that all callbacks
740
  // defined on an object belong to it.
741
  _.bindAll = function(obj) {
742
    var i, length = arguments.length, key;
743
    if (length <= 1) throw new Error('bindAll must be passed function names');
744
    for (i = 1; i < length; i++) {
745
      key = arguments[i];
746
      obj[key] = _.bind(obj[key], obj);
747
    }
748
    return obj;
749
  };
750
751
  // Memoize an expensive function by storing its results.
752
  _.memoize = function(func, hasher) {
753
    var memoize = function(key) {
754
      var cache = memoize.cache;
755
      var address = '' + (hasher ? hasher.apply(this, arguments) : key);
756
      if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
757
      return cache[address];
758
    };
759
    memoize.cache = {};
760
    return memoize;
761
  };
762
763
  // Delays a function for the given number of milliseconds, and then calls
764
  // it with the arguments supplied.
765
  _.delay = function(func, wait) {
766
    var args = slice.call(arguments, 2);
767
    return setTimeout(function(){
768
      return func.apply(null, args);
769
    }, wait);
770
  };
771
772
  // Defers a function, scheduling it to run after the current call stack has
773
  // cleared.
774
  _.defer = _.partial(_.delay, _, 1);
775
776
  // Returns a function, that, when invoked, will only be triggered at most once
777
  // during a given window of time. Normally, the throttled function will run
778
  // as much as it can, without ever going more than once per `wait` duration;
779
  // but if you'd like to disable the execution on the leading edge, pass
780
  // `{leading: false}`. To disable execution on the trailing edge, ditto.
781
  _.throttle = function(func, wait, options) {
782
    var context, args, result;
783
    var timeout = null;
784
    var previous = 0;
785
    if (!options) options = {};
786
    var later = function() {
787
      previous = options.leading === false ? 0 : _.now();
788
      timeout = null;
789
      result = func.apply(context, args);
790
      if (!timeout) context = args = null;
791
    };
792
    return function() {
793
      var now = _.now();
794
      if (!previous && options.leading === false) previous = now;
795
      var remaining = wait - (now - previous);
796
      context = this;
797
      args = arguments;
798
      if (remaining <= 0 || remaining > wait) {
799
        if (timeout) {
800
          clearTimeout(timeout);
801
          timeout = null;
802
        }
803
        previous = now;
804
        result = func.apply(context, args);
805
        if (!timeout) context = args = null;
806
      } else if (!timeout && options.trailing !== false) {
807
        timeout = setTimeout(later, remaining);
808
      }
809
      return result;
0 ignored issues
show
Bug introduced by
The variable result seems to not be initialized for all possible execution paths.
Loading history...
810
    };
811
  };
812
813
  // Returns a function, that, as long as it continues to be invoked, will not
814
  // be triggered. The function will be called after it stops being called for
815
  // N milliseconds. If `immediate` is passed, trigger the function on the
816
  // leading edge, instead of the trailing.
817
  _.debounce = function(func, wait, immediate) {
818
    var timeout, args, context, timestamp, result;
819
820
    var later = function() {
821
      var last = _.now() - timestamp;
822
823
      if (last < wait && last >= 0) {
824
        timeout = setTimeout(later, wait - last);
825
      } else {
826
        timeout = null;
827
        if (!immediate) {
828
          result = func.apply(context, args);
829
          if (!timeout) context = args = null;
830
        }
831
      }
832
    };
833
834
    return function() {
835
      context = this;
836
      args = arguments;
837
      timestamp = _.now();
838
      var callNow = immediate && !timeout;
839
      if (!timeout) timeout = setTimeout(later, wait);
840
      if (callNow) {
841
        result = func.apply(context, args);
842
        context = args = null;
843
      }
844
845
      return result;
0 ignored issues
show
Bug introduced by
The variable result does not seem to be initialized in case callNow on line 840 is false. Are you sure this can never be the case?
Loading history...
846
    };
847
  };
848
849
  // Returns the first function passed as an argument to the second,
850
  // allowing you to adjust arguments, run code before and after, and
851
  // conditionally execute the original function.
852
  _.wrap = function(func, wrapper) {
853
    return _.partial(wrapper, func);
854
  };
855
856
  // Returns a negated version of the passed-in predicate.
857
  _.negate = function(predicate) {
858
    return function() {
859
      return !predicate.apply(this, arguments);
860
    };
861
  };
862
863
  // Returns a function that is the composition of a list of functions, each
864
  // consuming the return value of the function that follows.
865
  _.compose = function() {
866
    var args = arguments;
867
    var start = args.length - 1;
868
    return function() {
869
      var i = start;
870
      var result = args[start].apply(this, arguments);
871
      while (i--) result = args[i].call(this, result);
872
      return result;
873
    };
874
  };
875
876
  // Returns a function that will only be executed on and after the Nth call.
877
  _.after = function(times, func) {
878
    return function() {
879
      if (--times < 1) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if --times < 1 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
880
        return func.apply(this, arguments);
881
      }
882
    };
883
  };
884
885
  // Returns a function that will only be executed up to (but not including) the Nth call.
886
  _.before = function(times, func) {
887
    var memo;
888
    return function() {
889
      if (--times > 0) {
890
        memo = func.apply(this, arguments);
891
      }
892
      if (times <= 1) func = null;
893
      return memo;
0 ignored issues
show
Bug introduced by
The variable memo does not seem to be initialized in case --times > 0 on line 889 is false. Are you sure this can never be the case?
Loading history...
894
    };
895
  };
896
897
  // Returns a function that will be executed at most one time, no matter how
898
  // often you call it. Useful for lazy initialization.
899
  _.once = _.partial(_.before, 2);
900
901
  // Object Functions
902
  // ----------------
903
904
  // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
905
  var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
906
  var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
907
                      'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
908
909
  function collectNonEnumProps(obj, keys) {
910
    var nonEnumIdx = nonEnumerableProps.length;
911
    var constructor = obj.constructor;
912
    var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
913
914
    // Constructor is a special case.
915
    var prop = 'constructor';
916
    if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
917
918
    while (nonEnumIdx--) {
919
      prop = nonEnumerableProps[nonEnumIdx];
920
      if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
921
        keys.push(prop);
922
      }
923
    }
924
  }
925
926
  // Retrieve the names of an object's own properties.
927
  // Delegates to **ECMAScript 5**'s native `Object.keys`
928
  _.keys = function(obj) {
929
    if (!_.isObject(obj)) return [];
930
    if (nativeKeys) return nativeKeys(obj);
931
    var keys = [];
932
    for (var key in obj) if (_.has(obj, key)) keys.push(key);
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
933
    // Ahem, IE < 9.
934
    if (hasEnumBug) collectNonEnumProps(obj, keys);
935
    return keys;
936
  };
937
938
  // Retrieve all the property names of an object.
939
  _.allKeys = function(obj) {
940
    if (!_.isObject(obj)) return [];
941
    var keys = [];
942
    for (var key in obj) keys.push(key);
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
943
    // Ahem, IE < 9.
944
    if (hasEnumBug) collectNonEnumProps(obj, keys);
945
    return keys;
946
  };
947
948
  // Retrieve the values of an object's properties.
949
  _.values = function(obj) {
950
    var keys = _.keys(obj);
951
    var length = keys.length;
952
    var values = Array(length);
953
    for (var i = 0; i < length; i++) {
954
      values[i] = obj[keys[i]];
955
    }
956
    return values;
957
  };
958
959
  // Returns the results of applying the iteratee to each element of the object
960
  // In contrast to _.map it returns an object
961
  _.mapObject = function(obj, iteratee, context) {
962
    iteratee = cb(iteratee, context);
963
    var keys =  _.keys(obj),
964
          length = keys.length,
965
          results = {},
966
          currentKey;
967
      for (var index = 0; index < length; index++) {
968
        currentKey = keys[index];
969
        results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
970
      }
971
      return results;
972
  };
973
974
  // Convert an object into a list of `[key, value]` pairs.
975
  _.pairs = function(obj) {
976
    var keys = _.keys(obj);
977
    var length = keys.length;
978
    var pairs = Array(length);
979
    for (var i = 0; i < length; i++) {
980
      pairs[i] = [keys[i], obj[keys[i]]];
981
    }
982
    return pairs;
983
  };
984
985
  // Invert the keys and values of an object. The values must be serializable.
986
  _.invert = function(obj) {
987
    var result = {};
988
    var keys = _.keys(obj);
989
    for (var i = 0, length = keys.length; i < length; i++) {
990
      result[obj[keys[i]]] = keys[i];
991
    }
992
    return result;
993
  };
994
995
  // Return a sorted list of the function names available on the object.
996
  // Aliased as `methods`
997
  _.functions = _.methods = function(obj) {
998
    var names = [];
999
    for (var key in obj) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
1000
      if (_.isFunction(obj[key])) names.push(key);
1001
    }
1002
    return names.sort();
1003
  };
1004
1005
  // Extend a given object with all the properties in passed-in object(s).
1006
  _.extend = createAssigner(_.allKeys);
1007
1008
  // Assigns a given object with all the own properties in the passed-in object(s)
1009
  // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
1010
  _.extendOwn = _.assign = createAssigner(_.keys);
1011
1012
  // Returns the first key on an object that passes a predicate test
1013
  _.findKey = function(obj, predicate, context) {
1014
    predicate = cb(predicate, context);
1015
    var keys = _.keys(obj), key;
1016
    for (var i = 0, length = keys.length; i < length; i++) {
1017
      key = keys[i];
1018
      if (predicate(obj[key], key, obj)) return key;
1019
    }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1020
  };
1021
1022
  // Return a copy of the object only containing the whitelisted properties.
1023
  _.pick = function(object, oiteratee, context) {
1024
    var result = {}, obj = object, iteratee, keys;
1025
    if (obj == null) return result;
1026
    if (_.isFunction(oiteratee)) {
1027
      keys = _.allKeys(obj);
1028
      iteratee = optimizeCb(oiteratee, context);
1029
    } else {
1030
      keys = flatten(arguments, false, false, 1);
1031
      iteratee = function(value, key, obj) { return key in obj; };
1032
      obj = Object(obj);
1033
    }
1034
    for (var i = 0, length = keys.length; i < length; i++) {
1035
      var key = keys[i];
1036
      var value = obj[key];
1037
      if (iteratee(value, key, obj)) result[key] = value;
1038
    }
1039
    return result;
1040
  };
1041
1042
   // Return a copy of the object without the blacklisted properties.
1043
  _.omit = function(obj, iteratee, context) {
1044
    if (_.isFunction(iteratee)) {
1045
      iteratee = _.negate(iteratee);
1046
    } else {
1047
      var keys = _.map(flatten(arguments, false, false, 1), String);
1048
      iteratee = function(value, key) {
1049
        return !_.contains(keys, key);
1050
      };
1051
    }
1052
    return _.pick(obj, iteratee, context);
1053
  };
1054
1055
  // Fill in a given object with default properties.
1056
  _.defaults = createAssigner(_.allKeys, true);
1057
1058
  // Creates an object that inherits from the given prototype object.
1059
  // If additional properties are provided then they will be added to the
1060
  // created object.
1061
  _.create = function(prototype, props) {
1062
    var result = baseCreate(prototype);
1063
    if (props) _.extendOwn(result, props);
1064
    return result;
1065
  };
1066
1067
  // Create a (shallow-cloned) duplicate of an object.
1068
  _.clone = function(obj) {
1069
    if (!_.isObject(obj)) return obj;
1070
    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
1071
  };
1072
1073
  // Invokes interceptor with the obj, and then returns obj.
1074
  // The primary purpose of this method is to "tap into" a method chain, in
1075
  // order to perform operations on intermediate results within the chain.
1076
  _.tap = function(obj, interceptor) {
1077
    interceptor(obj);
1078
    return obj;
1079
  };
1080
1081
  // Returns whether an object has a given set of `key:value` pairs.
1082
  _.isMatch = function(object, attrs) {
1083
    var keys = _.keys(attrs), length = keys.length;
1084
    if (object == null) return !length;
1085
    var obj = Object(object);
1086
    for (var i = 0; i < length; i++) {
1087
      var key = keys[i];
1088
      if (attrs[key] !== obj[key] || !(key in obj)) return false;
1089
    }
1090
    return true;
1091
  };
1092
1093
1094
  // Internal recursive comparison function for `isEqual`.
1095
  var eq = function(a, b, aStack, bStack) {
1096
    // Identical objects are equal. `0 === -0`, but they aren't identical.
1097
    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
1098
    if (a === b) return a !== 0 || 1 / a === 1 / b;
1099
    // A strict comparison is necessary because `null == undefined`.
1100
    if (a == null || b == null) return a === b;
1101
    // Unwrap any wrapped objects.
1102
    if (a instanceof _) a = a._wrapped;
1103
    if (b instanceof _) b = b._wrapped;
1104
    // Compare `[[Class]]` names.
1105
    var className = toString.call(a);
1106
    if (className !== toString.call(b)) return false;
1107
    switch (className) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
1108
      // Strings, numbers, regular expressions, dates, and booleans are compared by value.
1109
      case '[object RegExp]':
1110
      // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
1111
      case '[object String]':
1112
        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
1113
        // equivalent to `new String("5")`.
1114
        return '' + a === '' + b;
1115
      case '[object Number]':
1116
        // `NaN`s are equivalent, but non-reflexive.
1117
        // Object(NaN) is equivalent to NaN
1118
        if (+a !== +a) return +b !== +b;
1119
        // An `egal` comparison is performed for other numeric values.
1120
        return +a === 0 ? 1 / +a === 1 / b : +a === +b;
1121
      case '[object Date]':
1122
      case '[object Boolean]':
1123
        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
1124
        // millisecond representations. Note that invalid dates with millisecond representations
1125
        // of `NaN` are not equivalent.
1126
        return +a === +b;
1127
    }
1128
1129
    var areArrays = className === '[object Array]';
1130
    if (!areArrays) {
1131
      if (typeof a != 'object' || typeof b != 'object') return false;
1132
1133
      // Objects with different constructors are not equivalent, but `Object`s or `Array`s
1134
      // from different frames are.
1135
      var aCtor = a.constructor, bCtor = b.constructor;
1136
      if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
1137
                               _.isFunction(bCtor) && bCtor instanceof bCtor)
1138
                          && ('constructor' in a && 'constructor' in b)) {
1139
        return false;
1140
      }
1141
    }
1142
    // Assume equality for cyclic structures. The algorithm for detecting cyclic
1143
    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
1144
1145
    // Initializing stack of traversed objects.
1146
    // It's done here since we only need them for objects and arrays comparison.
1147
    aStack = aStack || [];
1148
    bStack = bStack || [];
1149
    var length = aStack.length;
1150
    while (length--) {
1151
      // Linear search. Performance is inversely proportional to the number of
1152
      // unique nested structures.
1153
      if (aStack[length] === a) return bStack[length] === b;
1154
    }
1155
1156
    // Add the first object to the stack of traversed objects.
1157
    aStack.push(a);
1158
    bStack.push(b);
1159
1160
    // Recursively compare objects and arrays.
1161
    if (areArrays) {
1162
      // Compare array lengths to determine if a deep comparison is necessary.
1163
      length = a.length;
1164
      if (length !== b.length) return false;
1165
      // Deep compare the contents, ignoring non-numeric properties.
1166
      while (length--) {
1167
        if (!eq(a[length], b[length], aStack, bStack)) return false;
1168
      }
1169
    } else {
1170
      // Deep compare objects.
1171
      var keys = _.keys(a), key;
1172
      length = keys.length;
1173
      // Ensure that both objects contain the same number of properties before comparing deep equality.
1174
      if (_.keys(b).length !== length) return false;
1175
      while (length--) {
1176
        // Deep compare each member
1177
        key = keys[length];
1178
        if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
1179
      }
1180
    }
1181
    // Remove the first object from the stack of traversed objects.
1182
    aStack.pop();
1183
    bStack.pop();
1184
    return true;
1185
  };
1186
1187
  // Perform a deep comparison to check if two objects are equal.
1188
  _.isEqual = function(a, b) {
1189
    return eq(a, b);
1190
  };
1191
1192
  // Is a given array, string, or object empty?
1193
  // An "empty" object has no enumerable own-properties.
1194
  _.isEmpty = function(obj) {
1195
    if (obj == null) return true;
1196
    if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
1197
    return _.keys(obj).length === 0;
1198
  };
1199
1200
  // Is a given value a DOM element?
1201
  _.isElement = function(obj) {
1202
    return !!(obj && obj.nodeType === 1);
1203
  };
1204
1205
  // Is a given value an array?
1206
  // Delegates to ECMA5's native Array.isArray
1207
  _.isArray = nativeIsArray || function(obj) {
1208
    return toString.call(obj) === '[object Array]';
1209
  };
1210
1211
  // Is a given variable an object?
1212
  _.isObject = function(obj) {
1213
    var type = typeof obj;
1214
    return type === 'function' || type === 'object' && !!obj;
1215
  };
1216
1217
  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
1218
  _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
1219
    _['is' + name] = function(obj) {
1220
      return toString.call(obj) === '[object ' + name + ']';
1221
    };
1222
  });
1223
1224
  // Define a fallback version of the method in browsers (ahem, IE < 9), where
1225
  // there isn't any inspectable "Arguments" type.
1226
  if (!_.isArguments(arguments)) {
1227
    _.isArguments = function(obj) {
1228
      return _.has(obj, 'callee');
1229
    };
1230
  }
1231
1232
  // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
1233
  // IE 11 (#1621), and in Safari 8 (#1929).
1234
  if (typeof /./ != 'function' && typeof Int8Array != 'object') {
1235
    _.isFunction = function(obj) {
1236
      return typeof obj == 'function' || false;
1237
    };
1238
  }
1239
1240
  // Is a given object a finite number?
1241
  _.isFinite = function(obj) {
1242
    return isFinite(obj) && !isNaN(parseFloat(obj));
1243
  };
1244
1245
  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
1246
  _.isNaN = function(obj) {
1247
    return _.isNumber(obj) && obj !== +obj;
1248
  };
1249
1250
  // Is a given value a boolean?
1251
  _.isBoolean = function(obj) {
1252
    return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
1253
  };
1254
1255
  // Is a given value equal to null?
1256
  _.isNull = function(obj) {
1257
    return obj === null;
1258
  };
1259
1260
  // Is a given variable undefined?
1261
  _.isUndefined = function(obj) {
1262
    return obj === void 0;
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
1263
  };
1264
1265
  // Shortcut function for checking if an object has a given property directly
1266
  // on itself (in other words, not on a prototype).
1267
  _.has = function(obj, key) {
1268
    return obj != null && hasOwnProperty.call(obj, key);
1269
  };
1270
1271
  // Utility Functions
1272
  // -----------------
1273
1274
  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
1275
  // previous owner. Returns a reference to the Underscore object.
1276
  _.noConflict = function() {
1277
    root._ = previousUnderscore;
1278
    return this;
1279
  };
1280
1281
  // Keep the identity function around for default iteratees.
1282
  _.identity = function(value) {
1283
    return value;
1284
  };
1285
1286
  // Predicate-generating functions. Often useful outside of Underscore.
1287
  _.constant = function(value) {
1288
    return function() {
1289
      return value;
1290
    };
1291
  };
1292
1293
  _.noop = function(){};
1294
1295
  _.property = property;
1296
1297
  // Generates a function for a given object that returns a given property.
1298
  _.propertyOf = function(obj) {
1299
    return obj == null ? function(){} : function(key) {
1300
      return obj[key];
1301
    };
1302
  };
1303
1304
  // Returns a predicate for checking whether an object has a given set of
1305
  // `key:value` pairs.
1306
  _.matcher = _.matches = function(attrs) {
1307
    attrs = _.extendOwn({}, attrs);
1308
    return function(obj) {
1309
      return _.isMatch(obj, attrs);
1310
    };
1311
  };
1312
1313
  // Run a function **n** times.
1314
  _.times = function(n, iteratee, context) {
1315
    var accum = Array(Math.max(0, n));
1316
    iteratee = optimizeCb(iteratee, context, 1);
1317
    for (var i = 0; i < n; i++) accum[i] = iteratee(i);
1318
    return accum;
1319
  };
1320
1321
  // Return a random integer between min and max (inclusive).
1322
  _.random = function(min, max) {
1323
    if (max == null) {
1324
      max = min;
1325
      min = 0;
1326
    }
1327
    return min + Math.floor(Math.random() * (max - min + 1));
1328
  };
1329
1330
  // A (possibly faster) way to get the current timestamp as an integer.
1331
  _.now = Date.now || function() {
1332
    return new Date().getTime();
1333
  };
1334
1335
   // List of HTML entities for escaping.
1336
  var escapeMap = {
1337
    '&': '&amp;',
1338
    '<': '&lt;',
1339
    '>': '&gt;',
1340
    '"': '&quot;',
1341
    "'": '&#x27;',
1342
    '`': '&#x60;'
1343
  };
1344
  var unescapeMap = _.invert(escapeMap);
1345
1346
  // Functions for escaping and unescaping strings to/from HTML interpolation.
1347
  var createEscaper = function(map) {
1348
    var escaper = function(match) {
1349
      return map[match];
1350
    };
1351
    // Regexes for identifying a key that needs to be escaped
1352
    var source = '(?:' + _.keys(map).join('|') + ')';
1353
    var testRegexp = RegExp(source);
1354
    var replaceRegexp = RegExp(source, 'g');
1355
    return function(string) {
1356
      string = string == null ? '' : '' + string;
1357
      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
1358
    };
1359
  };
1360
  _.escape = createEscaper(escapeMap);
1361
  _.unescape = createEscaper(unescapeMap);
1362
1363
  // If the value of the named `property` is a function then invoke it with the
1364
  // `object` as context; otherwise, return it.
1365
  _.result = function(object, property, fallback) {
1366
    var value = object == null ? void 0 : object[property];
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
1367
    if (value === void 0) {
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
1368
      value = fallback;
1369
    }
1370
    return _.isFunction(value) ? value.call(object) : value;
1371
  };
1372
1373
  // Generate a unique integer id (unique within the entire client session).
1374
  // Useful for temporary DOM ids.
1375
  var idCounter = 0;
1376
  _.uniqueId = function(prefix) {
1377
    var id = ++idCounter + '';
1378
    return prefix ? prefix + id : id;
1379
  };
1380
1381
  // By default, Underscore uses ERB-style template delimiters, change the
1382
  // following template settings to use alternative delimiters.
1383
  _.templateSettings = {
1384
    evaluate    : /<%([\s\S]+?)%>/g,
1385
    interpolate : /<%=([\s\S]+?)%>/g,
1386
    escape      : /<%-([\s\S]+?)%>/g
1387
  };
1388
1389
  // When customizing `templateSettings`, if you don't want to define an
1390
  // interpolation, evaluation or escaping regex, we need one that is
1391
  // guaranteed not to match.
1392
  var noMatch = /(.)^/;
1393
1394
  // Certain characters need to be escaped so that they can be put into a
1395
  // string literal.
1396
  var escapes = {
1397
    "'":      "'",
1398
    '\\':     '\\',
1399
    '\r':     'r',
1400
    '\n':     'n',
1401
    '\u2028': 'u2028',
1402
    '\u2029': 'u2029'
1403
  };
1404
1405
  var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
1406
1407
  var escapeChar = function(match) {
1408
    return '\\' + escapes[match];
1409
  };
1410
1411
  // JavaScript micro-templating, similar to John Resig's implementation.
1412
  // Underscore templating handles arbitrary delimiters, preserves whitespace,
1413
  // and correctly escapes quotes within interpolated code.
1414
  // NB: `oldSettings` only exists for backwards compatibility.
1415
  _.template = function(text, settings, oldSettings) {
1416
    if (!settings && oldSettings) settings = oldSettings;
1417
    settings = _.defaults({}, settings, _.templateSettings);
1418
1419
    // Combine delimiters into one regular expression via alternation.
1420
    var matcher = RegExp([
1421
      (settings.escape || noMatch).source,
1422
      (settings.interpolate || noMatch).source,
1423
      (settings.evaluate || noMatch).source
1424
    ].join('|') + '|$', 'g');
1425
1426
    // Compile the template source, escaping string literals appropriately.
1427
    var index = 0;
1428
    var source = "__p+='";
1429
    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
1430
      source += text.slice(index, offset).replace(escaper, escapeChar);
1431
      index = offset + match.length;
1432
1433
      if (escape) {
1434
        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
1435
      } else if (interpolate) {
1436
        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
1437
      } else if (evaluate) {
1438
        source += "';\n" + evaluate + "\n__p+='";
1439
      }
1440
1441
      // Adobe VMs need the match returned to produce the correct offest.
1442
      return match;
1443
    });
1444
    source += "';\n";
1445
1446
    // If a variable is not specified, place data values in local scope.
1447
    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
1448
1449
    source = "var __t,__p='',__j=Array.prototype.join," +
1450
      "print=function(){__p+=__j.call(arguments,'');};\n" +
1451
      source + 'return __p;\n';
1452
1453
    try {
1454
      var render = new Function(settings.variable || 'obj', '_', source);
0 ignored issues
show
Performance Best Practice introduced by
Using new Function() to create a function is slow and difficult to debug. Such functions do not create a closure. Consider using another way to define your function.
Loading history...
1455
    } catch (e) {
1456
      e.source = source;
1457
      throw e;
1458
    }
1459
1460
    var template = function(data) {
1461
      return render.call(this, data, _);
1462
    };
1463
1464
    // Provide the compiled source as a convenience for precompilation.
1465
    var argument = settings.variable || 'obj';
1466
    template.source = 'function(' + argument + '){\n' + source + '}';
1467
1468
    return template;
1469
  };
1470
1471
  // Add a "chain" function. Start chaining a wrapped Underscore object.
1472
  _.chain = function(obj) {
1473
    var instance = _(obj);
1474
    instance._chain = true;
1475
    return instance;
1476
  };
1477
1478
  // OOP
1479
  // ---------------
1480
  // If Underscore is called as a function, it returns a wrapped object that
1481
  // can be used OO-style. This wrapper holds altered versions of all the
1482
  // underscore functions. Wrapped objects may be chained.
1483
1484
  // Helper function to continue chaining intermediate results.
1485
  var result = function(instance, obj) {
1486
    return instance._chain ? _(obj).chain() : obj;
1487
  };
1488
1489
  // Add your own custom functions to the Underscore object.
1490
  _.mixin = function(obj) {
1491
    _.each(_.functions(obj), function(name) {
1492
      var func = _[name] = obj[name];
1493
      _.prototype[name] = function() {
1494
        var args = [this._wrapped];
1495
        push.apply(args, arguments);
1496
        return result(this, func.apply(_, args));
1497
      };
1498
    });
1499
  };
1500
1501
  // Add all of the Underscore functions to the wrapper object.
1502
  _.mixin(_);
1503
1504
  // Add all mutator Array functions to the wrapper.
1505
  _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1506
    var method = ArrayProto[name];
1507
    _.prototype[name] = function() {
1508
      var obj = this._wrapped;
1509
      method.apply(obj, arguments);
1510
      if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
1511
      return result(this, obj);
1512
    };
1513
  });
1514
1515
  // Add all accessor Array functions to the wrapper.
1516
  _.each(['concat', 'join', 'slice'], function(name) {
1517
    var method = ArrayProto[name];
1518
    _.prototype[name] = function() {
1519
      return result(this, method.apply(this._wrapped, arguments));
1520
    };
1521
  });
1522
1523
  // Extracts the result from a wrapped and chained object.
1524
  _.prototype.value = function() {
1525
    return this._wrapped;
1526
  };
1527
1528
  // Provide unwrapping proxy for some methods used in engine operations
1529
  // such as arithmetic and JSON stringification.
1530
  _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
1531
1532
  _.prototype.toString = function() {
1533
    return '' + this._wrapped;
1534
  };
1535
1536
  // AMD registration happens at the end for compatibility with AMD loaders
1537
  // that may not enforce next-turn semantics on modules. Even though general
1538
  // practice for AMD registration is to be anonymous, underscore registers
1539
  // as a named module because, like jQuery, it is a base library that is
1540
  // popular enough to be bundled in a third party lib, but not be part of
1541
  // an AMD load request. Those cases could generate an error when an
1542
  // anonymous define() is called outside of a loader request.
1543
  if (typeof define === 'function' && define.amd) {
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1544
    define('underscore', [], function() {
1545
      return _;
1546
    });
1547
  }
1548
}.call(this));
1549