character 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +4 -0
  3. data/README.md +20 -0
  4. data/Rakefile +7 -0
  5. data/app/controllers/character/posts_controller.rb +27 -0
  6. data/app/models/character/post.rb +20 -0
  7. data/character.gemspec +24 -0
  8. data/lib/character.rb +3 -0
  9. data/lib/character/engine.rb +5 -0
  10. data/lib/character/routing.rb +11 -0
  11. data/lib/character/version.rb +3 -0
  12. data/lib/generators/character/install_generator.rb +42 -0
  13. data/lib/generators/character/templates/README +1 -0
  14. data/lib/generators/character/templates/admin/character.rb +3 -0
  15. data/vendor/assets/fonts/general_foundicons.eot +0 -0
  16. data/vendor/assets/fonts/general_foundicons.svg +15 -0
  17. data/vendor/assets/fonts/general_foundicons.ttf +0 -0
  18. data/vendor/assets/fonts/general_foundicons.woff +0 -0
  19. data/vendor/assets/javascripts/backbone.js +1431 -0
  20. data/vendor/assets/javascripts/character/index.js.coffee +53 -0
  21. data/vendor/assets/javascripts/character/models/post.js.coffee +39 -0
  22. data/vendor/assets/javascripts/character/views/app.js.coffee +81 -0
  23. data/vendor/assets/javascripts/character/views/editor.js.coffee +231 -0
  24. data/vendor/assets/javascripts/character/views/editor_settings.js.coffee +44 -0
  25. data/vendor/assets/javascripts/character/views/index.js.coffee +116 -0
  26. data/vendor/assets/javascripts/character/views/preview.js.coffee +49 -0
  27. data/vendor/assets/javascripts/jquery.smartresize.js +30 -0
  28. data/vendor/assets/javascripts/lodash.js +4258 -0
  29. data/vendor/assets/javascripts/showdown.js +62 -0
  30. data/vendor/assets/javascripts/underscore.string.js +600 -0
  31. data/vendor/assets/stylesheets/character/_base.css.scss +84 -0
  32. data/vendor/assets/stylesheets/character/_icons.css.scss.erb +96 -0
  33. data/vendor/assets/stylesheets/character/_view_editor.css.scss +115 -0
  34. data/vendor/assets/stylesheets/character/_view_index.css.scss +73 -0
  35. data/vendor/assets/stylesheets/character/_view_preview.css.scss +49 -0
  36. data/vendor/assets/stylesheets/character/index.css.scss +32 -0
  37. metadata +103 -0
@@ -0,0 +1,116 @@
1
+ ##############################
2
+ ### CHARACTER :: IndexView ###
3
+ ##############################
4
+
5
+ class PostIndexItemView extends Backbone.View
6
+ tagName: 'li'
7
+
8
+ render: ->
9
+ post = @model.toJSON()
10
+ id = @model.id
11
+ views = if post.published then post.views else ''
12
+ date = @model.date_formatted()
13
+
14
+ image = @model.featured_image()
15
+ img_tag = if image then """<img class='featured' src='#{image}' />""" else ''
16
+
17
+ html = """<a href='#/preview/#{id}'>
18
+ #{img_tag}
19
+ <div class='left'>
20
+ <span class='title'>#{post.title}</span>
21
+ <span class='meta'>#{@model.state()}</span>
22
+ </div>
23
+ <div class='right'>
24
+ <span class='date'>#{date}</span>
25
+ <span class='views'>#{views}</span>
26
+ </div>
27
+ </a>"""
28
+ $(this.el).html html
29
+ return this
30
+
31
+
32
+ class IndexView extends Backbone.View
33
+ tagName: 'div'
34
+ className: 'chr-panel left index'
35
+ id: 'blog_index'
36
+
37
+
38
+ render: ->
39
+ html = """<section class='container'>
40
+ <header>
41
+ <span class='title'>Posts</span>
42
+ <span class='buttons'>
43
+ <a href='#/new' title='Create new post' class='foundicon-add-doc'></a>
44
+ <!--<span class='split'></span><a href='#' title='Search for post' class='foundicon-search'></a>-->
45
+ </span>
46
+ </header>
47
+ <ul id='list'></ul>
48
+ </section>"""
49
+ $(this.el).html html
50
+ return this
51
+
52
+
53
+ render_item: (post) ->
54
+ item = new PostIndexItemView model: post
55
+ html = item.render().el
56
+ $(@list).append html
57
+
58
+ @item_views[post.id] = item
59
+
60
+ render_items_placeholder: ->
61
+ html = """<li class='placeholder'>Hey there! You don't have any posts yet, so go ahead and create the first one!</li>"""
62
+ $(@list).append html
63
+
64
+ render_items: ->
65
+ posts = window.posts.toArray()
66
+ if posts.length > 0
67
+ @render_item(post) for post in posts
68
+ else
69
+ @render_items_placeholder()
70
+
71
+
72
+ initialize: ->
73
+ html = @render().el
74
+ $('#main').append(html)
75
+
76
+ @list = document.getElementById('list')
77
+ @item_views = {}
78
+
79
+ @render_items()
80
+
81
+
82
+ scroll_to_active: ->
83
+ if window.index_scroll_y > 0
84
+ window.scroll(0, window.index_scroll_y)
85
+ else
86
+ top_offset = $('#blog_index a.active').offset().top
87
+ if top_offset - window.scrollY > $(window).height()
88
+ window.scroll(0, top_offset - 100)
89
+
90
+
91
+ set_active: (id) ->
92
+ @unset_active()
93
+ $("#blog_index a[href='#/preview/#{id}']").addClass('active')
94
+ @scroll_to_active()
95
+
96
+
97
+ unset_active: ->
98
+ $('#blog_index a.active').removeClass('active')
99
+
100
+
101
+ lock: ->
102
+ window.index_scroll_y = window.scrollY
103
+ $(@el).css('top', -window.scrollY + 40).addClass('fixed') # 40 is an active admin header height
104
+
105
+
106
+ unlock: ->
107
+ $(@el).css('top', '').removeClass('fixed')
108
+ window.scroll(0, window.index_scroll_y)
109
+
110
+
111
+ window.IndexView = IndexView
112
+
113
+
114
+
115
+
116
+
@@ -0,0 +1,49 @@
1
+ ####################################
2
+ ### CHARACTER :: PostPreviewView ###
3
+ ####################################
4
+
5
+ class PostPreviewView extends Backbone.View
6
+ tagName: 'div'
7
+ className: 'chr-panel right quickview'
8
+ id: 'blog_quickview'
9
+
10
+
11
+ delete_post: (e) ->
12
+ e.preventDefault()
13
+ if confirm('Do you really want to remove this post?')
14
+ # this event could be probably tighted to collection event or model destory event
15
+ window.app.index_view.item_views[@model.id].remove()
16
+ @model.destroy()
17
+ router.navigate('#/', {trigger: true})
18
+
19
+
20
+ events:
21
+ 'click #delete_post': 'delete_post'
22
+
23
+ render: ->
24
+ post = @model.toJSON()
25
+ state = @model.state()
26
+ id = @model.id
27
+
28
+ html = """<section class='container'>
29
+ <header>
30
+ <span class='title'>#{state}</span>
31
+ <span class='buttons'>
32
+ <a href='#' title='Delete this post' class='foundicon-trash' id='delete_post'></a>
33
+ <span class='split'></span>
34
+ <a href='#/edit/#{id}' title='Edit this post' class='foundicon-edit'></a>
35
+ <span class='split'></span>
36
+ <a href='#/' title='Close Preview' class='foundicon-remove'></a>
37
+ </span>
38
+ </header>
39
+
40
+ <article>
41
+ <section class='content'>
42
+ #{post.html}
43
+ </section>
44
+ </article>
45
+ </section>"""
46
+ $(this.el).html html
47
+ return this
48
+
49
+ window.PostPreviewView = PostPreviewView
@@ -0,0 +1,30 @@
1
+ /*
2
+ * Smartresize
3
+ */
4
+ (function($,sr){
5
+
6
+ // debouncing function from John Hann
7
+ // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
8
+ var debounce = function (func, threshold, execAsap) {
9
+ var timeout;
10
+
11
+ return function debounced () {
12
+ var obj = this, args = arguments;
13
+ function delayed () {
14
+ if (!execAsap)
15
+ func.apply(obj, args);
16
+ timeout = null;
17
+ };
18
+
19
+ if (timeout)
20
+ clearTimeout(timeout);
21
+ else if (execAsap)
22
+ func.apply(obj, args);
23
+
24
+ timeout = setTimeout(delayed, threshold || 100);
25
+ };
26
+ }
27
+ // smartresize
28
+ jQuery.fn[sr] = function(fn){ return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
29
+
30
+ })(jQuery,'smartresize');
@@ -0,0 +1,4258 @@
1
+ /*!
2
+ * Lo-Dash v0.9.2 <http://lodash.com>
3
+ * (c) 2012 John-David Dalton <http://allyoucanleet.com/>
4
+ * Based on Underscore.js 1.4.2 <http://underscorejs.org>
5
+ * (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
6
+ * Available under MIT license <http://lodash.com/license>
7
+ */
8
+ ;(function(window, undefined) {
9
+
10
+ /** Detect free variable `exports` */
11
+ var freeExports = typeof exports == 'object' && exports;
12
+
13
+ /** Detect free variable `global` and use it as `window` */
14
+ var freeGlobal = typeof global == 'object' && global;
15
+ if (freeGlobal.global === freeGlobal) {
16
+ window = freeGlobal;
17
+ }
18
+
19
+ /** Used for array and object method references */
20
+ var arrayRef = [],
21
+ // avoid a Closure Compiler bug by creatively creating an object
22
+ objectRef = new function(){};
23
+
24
+ /** Used to generate unique IDs */
25
+ var idCounter = 0;
26
+
27
+ /** Used internally to indicate various things */
28
+ var indicatorObject = objectRef;
29
+
30
+ /** Used by `cachedContains` as the default size when optimizations are enabled for large arrays */
31
+ var largeArraySize = 30;
32
+
33
+ /** Used to restore the original `_` reference in `noConflict` */
34
+ var oldDash = window._;
35
+
36
+ /** Used to detect template delimiter values that require a with-statement */
37
+ var reComplexDelimiter = /[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/;
38
+
39
+ /** Used to match HTML entities */
40
+ var reEscapedHtml = /&(?:amp|lt|gt|quot|#x27);/g;
41
+
42
+ /** Used to match empty string literals in compiled template source */
43
+ var reEmptyStringLeading = /\b__p \+= '';/g,
44
+ reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
45
+ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
46
+
47
+ /** Used to match regexp flags from their coerced string values */
48
+ var reFlags = /\w*$/;
49
+
50
+ /** Used to insert the data object variable into compiled template source */
51
+ var reInsertVariable = /(?:__e|__t = )\(\s*(?![\d\s"']|this\.)/g;
52
+
53
+ /** Used to detect if a method is native */
54
+ var reNative = RegExp('^' +
55
+ (objectRef.valueOf + '')
56
+ .replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&')
57
+ .replace(/valueOf|for [^\]]+/g, '.+?') + '$'
58
+ );
59
+
60
+ /**
61
+ * Used to match ES6 template delimiters
62
+ * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6
63
+ */
64
+ var reEsTemplate = /\$\{((?:(?=\\?)\\?[\s\S])*?)}/g;
65
+
66
+ /** Used to match "interpolate" template delimiters */
67
+ var reInterpolate = /<%=([\s\S]+?)%>/g;
68
+
69
+ /** Used to ensure capturing order of template delimiters */
70
+ var reNoMatch = /($^)/;
71
+
72
+ /** Used to match HTML characters */
73
+ var reUnescapedHtml = /[&<>"']/g;
74
+
75
+ /** Used to match unescaped characters in compiled string literals */
76
+ var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
77
+
78
+ /** Used to fix the JScript [[DontEnum]] bug */
79
+ var shadowed = [
80
+ 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
81
+ 'toLocaleString', 'toString', 'valueOf'
82
+ ];
83
+
84
+ /** Used to make template sourceURLs easier to identify */
85
+ var templateCounter = 0;
86
+
87
+ /** Native method shortcuts */
88
+ var ceil = Math.ceil,
89
+ concat = arrayRef.concat,
90
+ floor = Math.floor,
91
+ getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
92
+ hasOwnProperty = objectRef.hasOwnProperty,
93
+ push = arrayRef.push,
94
+ propertyIsEnumerable = objectRef.propertyIsEnumerable,
95
+ slice = arrayRef.slice,
96
+ toString = objectRef.toString;
97
+
98
+ /* Native method shortcuts for methods with the same name as other `lodash` methods */
99
+ var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind,
100
+ nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
101
+ nativeIsFinite = window.isFinite,
102
+ nativeIsNaN = window.isNaN,
103
+ nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys,
104
+ nativeMax = Math.max,
105
+ nativeMin = Math.min,
106
+ nativeRandom = Math.random;
107
+
108
+ /** `Object#toString` result shortcuts */
109
+ var argsClass = '[object Arguments]',
110
+ arrayClass = '[object Array]',
111
+ boolClass = '[object Boolean]',
112
+ dateClass = '[object Date]',
113
+ funcClass = '[object Function]',
114
+ numberClass = '[object Number]',
115
+ objectClass = '[object Object]',
116
+ regexpClass = '[object RegExp]',
117
+ stringClass = '[object String]';
118
+
119
+ /**
120
+ * Detect the JScript [[DontEnum]] bug:
121
+ *
122
+ * In IE < 9 an objects own properties, shadowing non-enumerable ones, are
123
+ * made non-enumerable as well.
124
+ */
125
+ var hasDontEnumBug;
126
+
127
+ /** Detect if own properties are iterated after inherited properties (IE < 9) */
128
+ var iteratesOwnLast;
129
+
130
+ /**
131
+ * Detect if `Array#shift` and `Array#splice` augment array-like objects
132
+ * incorrectly:
133
+ *
134
+ * Firefox < 10, IE compatibility mode, and IE < 9 have buggy Array `shift()`
135
+ * and `splice()` functions that fail to remove the last element, `value[0]`,
136
+ * of array-like objects even though the `length` property is set to `0`.
137
+ * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()`
138
+ * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9.
139
+ */
140
+ var hasObjectSpliceBug = (hasObjectSpliceBug = { '0': 1, 'length': 1 },
141
+ arrayRef.splice.call(hasObjectSpliceBug, 0, 1), hasObjectSpliceBug[0]);
142
+
143
+ /** Detect if an `arguments` object's indexes are non-enumerable (IE < 9) */
144
+ var noArgsEnum = true;
145
+
146
+ (function() {
147
+ var props = [];
148
+ function ctor() { this.x = 1; }
149
+ ctor.prototype = { 'valueOf': 1, 'y': 1 };
150
+ for (var prop in new ctor) { props.push(prop); }
151
+ for (prop in arguments) { noArgsEnum = !prop; }
152
+
153
+ hasDontEnumBug = !/valueOf/.test(props);
154
+ iteratesOwnLast = props[0] != 'x';
155
+ }(1));
156
+
157
+ /** Detect if an `arguments` object's [[Class]] is unresolvable (Firefox < 4, IE < 9) */
158
+ var noArgsClass = !isArguments(arguments);
159
+
160
+ /** Detect if `Array#slice` cannot be used to convert strings to arrays (Opera < 10.52) */
161
+ var noArraySliceOnStrings = slice.call('x')[0] != 'x';
162
+
163
+ /**
164
+ * Detect lack of support for accessing string characters by index:
165
+ *
166
+ * IE < 8 can't access characters by index and IE 8 can only access
167
+ * characters by index on string literals.
168
+ */
169
+ var noCharByIndex = ('x'[0] + Object('x')[0]) != 'xx';
170
+
171
+ /**
172
+ * Detect if a node's [[Class]] is unresolvable (IE < 9)
173
+ * and that the JS engine won't error when attempting to coerce an object to
174
+ * a string without a `toString` property value of `typeof` "function".
175
+ */
176
+ try {
177
+ var noNodeClass = ({ 'toString': 0 } + '', toString.call(window.document || 0) == objectClass);
178
+ } catch(e) { }
179
+
180
+ /* Detect if `Function#bind` exists and is inferred to be fast (all but V8) */
181
+ var isBindFast = nativeBind && /\n|Opera/.test(nativeBind + toString.call(window.opera));
182
+
183
+ /* Detect if `Object.keys` exists and is inferred to be fast (IE, Opera, V8) */
184
+ var isKeysFast = nativeKeys && /^.+$|true/.test(nativeKeys + !!window.attachEvent);
185
+
186
+ /**
187
+ * Detect if sourceURL syntax is usable without erroring:
188
+ *
189
+ * The JS engine in Adobe products, like InDesign, will throw a syntax error
190
+ * when it encounters a single line comment beginning with the `@` symbol.
191
+ *
192
+ * The JS engine in Narwhal will generate the function `function anonymous(){//}`
193
+ * and throw a syntax error.
194
+ *
195
+ * Avoid comments beginning `@` symbols in IE because they are part of its
196
+ * non-standard conditional compilation support.
197
+ * http://msdn.microsoft.com/en-us/library/121hztk3(v=vs.94).aspx
198
+ */
199
+ try {
200
+ var useSourceURL = (Function('//@')(), !window.attachEvent);
201
+ } catch(e) { }
202
+
203
+ /** Used to identify object classifications that `_.clone` supports */
204
+ var cloneableClasses = {};
205
+ cloneableClasses[argsClass] = cloneableClasses[funcClass] = false;
206
+ cloneableClasses[arrayClass] = cloneableClasses[boolClass] = cloneableClasses[dateClass] =
207
+ cloneableClasses[numberClass] = cloneableClasses[objectClass] = cloneableClasses[regexpClass] =
208
+ cloneableClasses[stringClass] = true;
209
+
210
+ /** Used to determine if values are of the language type Object */
211
+ var objectTypes = {
212
+ 'boolean': false,
213
+ 'function': true,
214
+ 'object': true,
215
+ 'number': false,
216
+ 'string': false,
217
+ 'undefined': false
218
+ };
219
+
220
+ /** Used to escape characters for inclusion in compiled string literals */
221
+ var stringEscapes = {
222
+ '\\': '\\',
223
+ "'": "'",
224
+ '\n': 'n',
225
+ '\r': 'r',
226
+ '\t': 't',
227
+ '\u2028': 'u2028',
228
+ '\u2029': 'u2029'
229
+ };
230
+
231
+ /*--------------------------------------------------------------------------*/
232
+
233
+ /**
234
+ * The `lodash` function.
235
+ *
236
+ * @name _
237
+ * @constructor
238
+ * @category Chaining
239
+ * @param {Mixed} value The value to wrap in a `lodash` instance.
240
+ * @returns {Object} Returns a `lodash` instance.
241
+ */
242
+ function lodash(value) {
243
+ // exit early if already wrapped
244
+ if (value && value.__wrapped__) {
245
+ return value;
246
+ }
247
+ // allow invoking `lodash` without the `new` operator
248
+ if (!(this instanceof lodash)) {
249
+ return new lodash(value);
250
+ }
251
+ this.__wrapped__ = value;
252
+ }
253
+
254
+ /**
255
+ * By default, the template delimiters used by Lo-Dash are similar to those in
256
+ * embedded Ruby (ERB). Change the following template settings to use alternative
257
+ * delimiters.
258
+ *
259
+ * @static
260
+ * @memberOf _
261
+ * @type Object
262
+ */
263
+ lodash.templateSettings = {
264
+
265
+ /**
266
+ * Used to detect `data` property values to be HTML-escaped.
267
+ *
268
+ * @static
269
+ * @memberOf _.templateSettings
270
+ * @type RegExp
271
+ */
272
+ 'escape': /<%-([\s\S]+?)%>/g,
273
+
274
+ /**
275
+ * Used to detect code to be evaluated.
276
+ *
277
+ * @static
278
+ * @memberOf _.templateSettings
279
+ * @type RegExp
280
+ */
281
+ 'evaluate': /<%([\s\S]+?)%>/g,
282
+
283
+ /**
284
+ * Used to detect `data` property values to inject.
285
+ *
286
+ * @static
287
+ * @memberOf _.templateSettings
288
+ * @type RegExp
289
+ */
290
+ 'interpolate': reInterpolate,
291
+
292
+ /**
293
+ * Used to reference the data object in the template text.
294
+ *
295
+ * @static
296
+ * @memberOf _.templateSettings
297
+ * @type String
298
+ */
299
+ 'variable': ''
300
+ };
301
+
302
+ /*--------------------------------------------------------------------------*/
303
+
304
+ /**
305
+ * The template used to create iterator functions.
306
+ *
307
+ * @private
308
+ * @param {Obect} data The data object used to populate the text.
309
+ * @returns {String} Returns the interpolated text.
310
+ */
311
+ var iteratorTemplate = template(
312
+ // conditional strict mode
313
+ '<% if (obj.useStrict) { %>\'use strict\';\n<% } %>' +
314
+
315
+ // the `iteratee` may be reassigned by the `top` snippet
316
+ 'var index, value, iteratee = <%= firstArg %>, ' +
317
+ // assign the `result` variable an initial value
318
+ 'result = <%= firstArg %>;\n' +
319
+ // exit early if the first argument is falsey
320
+ 'if (!<%= firstArg %>) return result;\n' +
321
+ // add code before the iteration branches
322
+ '<%= top %>;\n' +
323
+
324
+ // array-like iteration:
325
+ '<% if (arrayLoop) { %>' +
326
+ 'var length = iteratee.length; index = -1;\n' +
327
+ 'if (typeof length == \'number\') {' +
328
+
329
+ // add support for accessing string characters by index if needed
330
+ ' <% if (noCharByIndex) { %>\n' +
331
+ ' if (isString(iteratee)) {\n' +
332
+ ' iteratee = iteratee.split(\'\')\n' +
333
+ ' }' +
334
+ ' <% } %>\n' +
335
+
336
+ // iterate over the array-like value
337
+ ' while (++index < length) {\n' +
338
+ ' value = iteratee[index];\n' +
339
+ ' <%= arrayLoop %>\n' +
340
+ ' }\n' +
341
+ '}\n' +
342
+ 'else {' +
343
+
344
+ // object iteration:
345
+ // add support for iterating over `arguments` objects if needed
346
+ ' <% } else if (noArgsEnum) { %>\n' +
347
+ ' var length = iteratee.length; index = -1;\n' +
348
+ ' if (length && isArguments(iteratee)) {\n' +
349
+ ' while (++index < length) {\n' +
350
+ ' value = iteratee[index += \'\'];\n' +
351
+ ' <%= objectLoop %>\n' +
352
+ ' }\n' +
353
+ ' } else {' +
354
+ ' <% } %>' +
355
+
356
+ // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
357
+ // (if the prototype or a property on the prototype has been set)
358
+ // incorrectly sets a function's `prototype` property [[Enumerable]]
359
+ // value to `true`. Because of this Lo-Dash standardizes on skipping
360
+ // the the `prototype` property of functions regardless of its
361
+ // [[Enumerable]] value.
362
+ ' <% if (!hasDontEnumBug) { %>\n' +
363
+ ' var skipProto = typeof iteratee == \'function\' && \n' +
364
+ ' propertyIsEnumerable.call(iteratee, \'prototype\');\n' +
365
+ ' <% } %>' +
366
+
367
+ // iterate own properties using `Object.keys` if it's fast
368
+ ' <% if (isKeysFast && useHas) { %>\n' +
369
+ ' var ownIndex = -1,\n' +
370
+ ' ownProps = objectTypes[typeof iteratee] ? nativeKeys(iteratee) : [],\n' +
371
+ ' length = ownProps.length;\n\n' +
372
+ ' while (++ownIndex < length) {\n' +
373
+ ' index = ownProps[ownIndex];\n' +
374
+ ' <% if (!hasDontEnumBug) { %>if (!(skipProto && index == \'prototype\')) {\n <% } %>' +
375
+ ' value = iteratee[index];\n' +
376
+ ' <%= objectLoop %>\n' +
377
+ ' <% if (!hasDontEnumBug) { %>}\n<% } %>' +
378
+ ' }' +
379
+
380
+ // else using a for-in loop
381
+ ' <% } else { %>\n' +
382
+ ' for (index in iteratee) {<%' +
383
+ ' if (!hasDontEnumBug || useHas) { %>\n if (<%' +
384
+ ' if (!hasDontEnumBug) { %>!(skipProto && index == \'prototype\')<% }' +
385
+ ' if (!hasDontEnumBug && useHas) { %> && <% }' +
386
+ ' if (useHas) { %>hasOwnProperty.call(iteratee, index)<% }' +
387
+ ' %>) {' +
388
+ ' <% } %>\n' +
389
+ ' value = iteratee[index];\n' +
390
+ ' <%= objectLoop %>;' +
391
+ ' <% if (!hasDontEnumBug || useHas) { %>\n }<% } %>\n' +
392
+ ' }' +
393
+ ' <% } %>' +
394
+
395
+ // Because IE < 9 can't set the `[[Enumerable]]` attribute of an
396
+ // existing property and the `constructor` property of a prototype
397
+ // defaults to non-enumerable, Lo-Dash skips the `constructor`
398
+ // property when it infers it's iterating over a `prototype` object.
399
+ ' <% if (hasDontEnumBug) { %>\n\n' +
400
+ ' var ctor = iteratee.constructor;\n' +
401
+ ' <% for (var k = 0; k < 7; k++) { %>\n' +
402
+ ' index = \'<%= shadowed[k] %>\';\n' +
403
+ ' if (<%' +
404
+ ' if (shadowed[k] == \'constructor\') {' +
405
+ ' %>!(ctor && ctor.prototype === iteratee) && <%' +
406
+ ' } %>hasOwnProperty.call(iteratee, index)) {\n' +
407
+ ' value = iteratee[index];\n' +
408
+ ' <%= objectLoop %>\n' +
409
+ ' }' +
410
+ ' <% } %>' +
411
+ ' <% } %>' +
412
+ ' <% if (arrayLoop || noArgsEnum) { %>\n}<% } %>\n' +
413
+
414
+ // add code to the bottom of the iteration function
415
+ '<%= bottom %>;\n' +
416
+ // finally, return the `result`
417
+ 'return result'
418
+ );
419
+
420
+ /**
421
+ * Reusable iterator options shared by `forEach`, `forIn`, and `forOwn`.
422
+ */
423
+ var forEachIteratorOptions = {
424
+ 'args': 'collection, callback, thisArg',
425
+ 'top': 'callback = createCallback(callback, thisArg)',
426
+ 'arrayLoop': 'if (callback(value, index, collection) === false) return result',
427
+ 'objectLoop': 'if (callback(value, index, collection) === false) return result'
428
+ };
429
+
430
+ /** Reusable iterator options for `defaults`, and `extend` */
431
+ var extendIteratorOptions = {
432
+ 'useHas': false,
433
+ 'args': 'object',
434
+ 'top':
435
+ 'for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {\n' +
436
+ ' if (iteratee = arguments[argsIndex]) {',
437
+ 'objectLoop': 'result[index] = value',
438
+ 'bottom': ' }\n}'
439
+ };
440
+
441
+ /** Reusable iterator options for `forIn` and `forOwn` */
442
+ var forOwnIteratorOptions = {
443
+ 'arrayLoop': null
444
+ };
445
+
446
+ /*--------------------------------------------------------------------------*/
447
+
448
+ /**
449
+ * Creates a function optimized to search large arrays for a given `value`,
450
+ * starting at `fromIndex`, using strict equality for comparisons, i.e. `===`.
451
+ *
452
+ * @private
453
+ * @param {Array} array The array to search.
454
+ * @param {Mixed} value The value to search for.
455
+ * @param {Number} [fromIndex=0] The index to search from.
456
+ * @param {Number} [largeSize=30] The length at which an array is considered large.
457
+ * @returns {Boolean} Returns `true` if `value` is found, else `false`.
458
+ */
459
+ function cachedContains(array, fromIndex, largeSize) {
460
+ fromIndex || (fromIndex = 0);
461
+
462
+ var length = array.length,
463
+ isLarge = (length - fromIndex) >= (largeSize || largeArraySize);
464
+
465
+ if (isLarge) {
466
+ var cache = {},
467
+ index = fromIndex - 1;
468
+
469
+ while (++index < length) {
470
+ // manually coerce `value` to a string because `hasOwnProperty`, in some
471
+ // older versions of Firefox, coerces objects incorrectly
472
+ var key = array[index] + '';
473
+ (hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = [])).push(array[index]);
474
+ }
475
+ }
476
+ return function(value) {
477
+ if (isLarge) {
478
+ var key = value + '';
479
+ return hasOwnProperty.call(cache, key) && indexOf(cache[key], value) > -1;
480
+ }
481
+ return indexOf(array, value, fromIndex) > -1;
482
+ }
483
+ }
484
+
485
+ /**
486
+ * Used by `_.max` and `_.min` as the default `callback` when a given
487
+ * `collection` is a string value.
488
+ *
489
+ * @private
490
+ * @param {String} value The character to inspect.
491
+ * @returns {Number} Returns the code unit of given character.
492
+ */
493
+ function charAtCallback(value) {
494
+ return value.charCodeAt(0);
495
+ }
496
+
497
+ /**
498
+ * Used by `sortBy` to compare transformed `collection` values, stable sorting
499
+ * them in ascending order.
500
+ *
501
+ * @private
502
+ * @param {Object} a The object to compare to `b`.
503
+ * @param {Object} b The object to compare to `a`.
504
+ * @returns {Number} Returns the sort order indicator of `1` or `-1`.
505
+ */
506
+ function compareAscending(a, b) {
507
+ var ai = a.index,
508
+ bi = b.index;
509
+
510
+ a = a.criteria;
511
+ b = b.criteria;
512
+
513
+ // ensure a stable sort in V8 and other engines
514
+ // http://code.google.com/p/v8/issues/detail?id=90
515
+ if (a !== b) {
516
+ if (a > b || a === undefined) {
517
+ return 1;
518
+ }
519
+ if (a < b || b === undefined) {
520
+ return -1;
521
+ }
522
+ }
523
+ return ai < bi ? -1 : 1;
524
+ }
525
+
526
+ /**
527
+ * Creates a function that, when called, invokes `func` with the `this`
528
+ * binding of `thisArg` and prepends any `partailArgs` to the arguments passed
529
+ * to the bound function.
530
+ *
531
+ * @private
532
+ * @param {Function|String} func The function to bind or the method name.
533
+ * @param {Mixed} [thisArg] The `this` binding of `func`.
534
+ * @param {Array} partialArgs An array of arguments to be partially applied.
535
+ * @returns {Function} Returns the new bound function.
536
+ */
537
+ function createBound(func, thisArg, partialArgs) {
538
+ var isFunc = isFunction(func),
539
+ isPartial = !partialArgs,
540
+ methodName = func;
541
+
542
+ // juggle arguments
543
+ if (isPartial) {
544
+ partialArgs = thisArg;
545
+ }
546
+
547
+ function bound() {
548
+ // `Function#bind` spec
549
+ // http://es5.github.com/#x15.3.4.5
550
+ var args = arguments,
551
+ thisBinding = isPartial ? this : thisArg;
552
+
553
+ if (!isFunc) {
554
+ func = thisArg[methodName];
555
+ }
556
+ if (partialArgs.length) {
557
+ args = args.length
558
+ ? partialArgs.concat(slice.call(args))
559
+ : partialArgs;
560
+ }
561
+ if (this instanceof bound) {
562
+ // get `func` instance if `bound` is invoked in a `new` expression
563
+ noop.prototype = func.prototype;
564
+ thisBinding = new noop;
565
+
566
+ // mimic the constructor's `return` behavior
567
+ // http://es5.github.com/#x13.2.2
568
+ var result = func.apply(thisBinding, args);
569
+ return isObject(result)
570
+ ? result
571
+ : thisBinding
572
+ }
573
+ return func.apply(thisBinding, args);
574
+ }
575
+ return bound;
576
+ }
577
+
578
+ /**
579
+ * Produces an iteration callback bound to an optional `thisArg`. If `func` is
580
+ * a property name, the callback will return the property value for a given element.
581
+ *
582
+ * @private
583
+ * @param {Function|String} [func=identity|property] The function called per
584
+ * iteration or property name to query.
585
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
586
+ * @returns {Function} Returns a callback function.
587
+ */
588
+ function createCallback(func, thisArg) {
589
+ if (!func) {
590
+ return identity;
591
+ }
592
+ if (typeof func != 'function') {
593
+ return function(object) {
594
+ return object[func];
595
+ };
596
+ }
597
+ if (thisArg !== undefined) {
598
+ return function(value, index, object) {
599
+ return func.call(thisArg, value, index, object);
600
+ };
601
+ }
602
+ return func;
603
+ }
604
+
605
+ /**
606
+ * Creates compiled iteration functions.
607
+ *
608
+ * @private
609
+ * @param {Object} [options1, options2, ...] The compile options object(s).
610
+ * useHas - A boolean to specify using `hasOwnProperty` checks in the object loop.
611
+ * args - A string of comma separated arguments the iteration function will accept.
612
+ * top - A string of code to execute before the iteration branches.
613
+ * arrayLoop - A string of code to execute in the array loop.
614
+ * objectLoop - A string of code to execute in the object loop.
615
+ * bottom - A string of code to execute after the iteration branches.
616
+ *
617
+ * @returns {Function} Returns the compiled function.
618
+ */
619
+ function createIterator() {
620
+ var data = {
621
+ 'arrayLoop': '',
622
+ 'bottom': '',
623
+ 'hasDontEnumBug': hasDontEnumBug,
624
+ 'isKeysFast': isKeysFast,
625
+ 'objectLoop': '',
626
+ 'noArgsEnum': noArgsEnum,
627
+ 'noCharByIndex': noCharByIndex,
628
+ 'shadowed': shadowed,
629
+ 'top': '',
630
+ 'useHas': true
631
+ };
632
+
633
+ // merge options into a template data object
634
+ for (var object, index = 0; object = arguments[index]; index++) {
635
+ for (var key in object) {
636
+ data[key] = object[key];
637
+ }
638
+ }
639
+ var args = data.args;
640
+ data.firstArg = /^[^,]+/.exec(args)[0];
641
+
642
+ // create the function factory
643
+ var factory = Function(
644
+ 'createCallback, hasOwnProperty, isArguments, isString, objectTypes, ' +
645
+ 'nativeKeys, propertyIsEnumerable',
646
+ 'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}'
647
+ );
648
+ // return the compiled function
649
+ return factory(
650
+ createCallback, hasOwnProperty, isArguments, isString, objectTypes,
651
+ nativeKeys, propertyIsEnumerable
652
+ );
653
+ }
654
+
655
+ /**
656
+ * Used by `template` to escape characters for inclusion in compiled
657
+ * string literals.
658
+ *
659
+ * @private
660
+ * @param {String} match The matched character to escape.
661
+ * @returns {String} Returns the escaped character.
662
+ */
663
+ function escapeStringChar(match) {
664
+ return '\\' + stringEscapes[match];
665
+ }
666
+
667
+ /**
668
+ * Used by `escape` to convert characters to HTML entities.
669
+ *
670
+ * @private
671
+ * @param {String} match The matched character to escape.
672
+ * @returns {String} Returns the escaped character.
673
+ */
674
+ function escapeHtmlChar(match) {
675
+ return htmlEscapes[match];
676
+ }
677
+
678
+ /**
679
+ * A no-operation function.
680
+ *
681
+ * @private
682
+ */
683
+ function noop() {
684
+ // no operation performed
685
+ }
686
+
687
+ /**
688
+ * Used by `unescape` to convert HTML entities to characters.
689
+ *
690
+ * @private
691
+ * @param {String} match The matched character to unescape.
692
+ * @returns {String} Returns the unescaped character.
693
+ */
694
+ function unescapeHtmlChar(match) {
695
+ return htmlUnescapes[match];
696
+ }
697
+
698
+ /*--------------------------------------------------------------------------*/
699
+
700
+ /**
701
+ * Checks if `value` is an `arguments` object.
702
+ *
703
+ * @static
704
+ * @memberOf _
705
+ * @category Objects
706
+ * @param {Mixed} value The value to check.
707
+ * @returns {Boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
708
+ * @example
709
+ *
710
+ * (function() { return _.isArguments(arguments); })(1, 2, 3);
711
+ * // => true
712
+ *
713
+ * _.isArguments([1, 2, 3]);
714
+ * // => false
715
+ */
716
+ function isArguments(value) {
717
+ return toString.call(value) == argsClass;
718
+ }
719
+ // fallback for browsers that can't detect `arguments` objects by [[Class]]
720
+ if (noArgsClass) {
721
+ isArguments = function(value) {
722
+ return value ? hasOwnProperty.call(value, 'callee') : false;
723
+ };
724
+ }
725
+
726
+ /**
727
+ * Iterates over `object`'s own and inherited enumerable properties, executing
728
+ * the `callback` for each property. The `callback` is bound to `thisArg` and
729
+ * invoked with three arguments; (value, key, object). Callbacks may exit iteration
730
+ * early by explicitly returning `false`.
731
+ *
732
+ * @static
733
+ * @memberOf _
734
+ * @category Objects
735
+ * @param {Object} object The object to iterate over.
736
+ * @param {Function} callback The function called per iteration.
737
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
738
+ * @returns {Object} Returns `object`.
739
+ * @example
740
+ *
741
+ * function Dog(name) {
742
+ * this.name = name;
743
+ * }
744
+ *
745
+ * Dog.prototype.bark = function() {
746
+ * alert('Woof, woof!');
747
+ * };
748
+ *
749
+ * _.forIn(new Dog('Dagny'), function(value, key) {
750
+ * alert(key);
751
+ * });
752
+ * // => alerts 'name' and 'bark' (order is not guaranteed)
753
+ */
754
+ var forIn = createIterator(forEachIteratorOptions, forOwnIteratorOptions, {
755
+ 'useHas': false
756
+ });
757
+
758
+ /**
759
+ * Iterates over `object`'s own enumerable properties, executing the `callback`
760
+ * for each property. The `callback` is bound to `thisArg` and invoked with three
761
+ * arguments; (value, key, object). Callbacks may exit iteration early by explicitly
762
+ * returning `false`.
763
+ *
764
+ * @static
765
+ * @memberOf _
766
+ * @category Objects
767
+ * @param {Object} object The object to iterate over.
768
+ * @param {Function} callback The function called per iteration.
769
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
770
+ * @returns {Object} Returns `object`.
771
+ * @example
772
+ *
773
+ * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
774
+ * alert(key);
775
+ * });
776
+ * // => alerts '0', '1', and 'length' (order is not guaranteed)
777
+ */
778
+ var forOwn = createIterator(forEachIteratorOptions, forOwnIteratorOptions);
779
+
780
+ /**
781
+ * A fallback implementation of `isPlainObject` that checks if a given `value`
782
+ * is an object created by the `Object` constructor, assuming objects created
783
+ * by the `Object` constructor have no inherited enumerable properties and that
784
+ * there are no `Object.prototype` extensions.
785
+ *
786
+ * @private
787
+ * @param {Mixed} value The value to check.
788
+ * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`.
789
+ */
790
+ function shimIsPlainObject(value) {
791
+ // avoid non-objects and false positives for `arguments` objects
792
+ var result = false;
793
+ if (!(value && typeof value == 'object') || isArguments(value)) {
794
+ return result;
795
+ }
796
+ // IE < 9 presents DOM nodes as `Object` objects except they have `toString`
797
+ // methods that are `typeof` "string" and still can coerce nodes to strings.
798
+ // Also check that the constructor is `Object` (i.e. `Object instanceof Object`)
799
+ var ctor = value.constructor;
800
+ if ((!noNodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) &&
801
+ (!isFunction(ctor) || ctor instanceof ctor)) {
802
+ // IE < 9 iterates inherited properties before own properties. If the first
803
+ // iterated property is an object's own property then there are no inherited
804
+ // enumerable properties.
805
+ if (iteratesOwnLast) {
806
+ forIn(value, function(value, key, object) {
807
+ result = !hasOwnProperty.call(object, key);
808
+ return false;
809
+ });
810
+ return result === false;
811
+ }
812
+ // In most environments an object's own properties are iterated before
813
+ // its inherited properties. If the last iterated property is an object's
814
+ // own property then there are no inherited enumerable properties.
815
+ forIn(value, function(value, key) {
816
+ result = key;
817
+ });
818
+ return result === false || hasOwnProperty.call(value, result);
819
+ }
820
+ return result;
821
+ }
822
+
823
+ /**
824
+ * A fallback implementation of `Object.keys` that produces an array of the
825
+ * given object's own enumerable property names.
826
+ *
827
+ * @private
828
+ * @param {Object} object The object to inspect.
829
+ * @returns {Array} Returns a new array of property names.
830
+ */
831
+ function shimKeys(object) {
832
+ var result = [];
833
+ forOwn(object, function(value, key) {
834
+ result.push(key);
835
+ });
836
+ return result;
837
+ }
838
+
839
+ /**
840
+ * Used to convert characters to HTML entities:
841
+ *
842
+ * Though the `>` character is escaped for symmetry, characters like `>` and `/`
843
+ * don't require escaping in HTML and have no special meaning unless they're part
844
+ * of a tag or an unquoted attribute value.
845
+ * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
846
+ */
847
+ var htmlEscapes = {
848
+ '&': '&amp;',
849
+ '<': '&lt;',
850
+ '>': '&gt;',
851
+ '"': '&quot;',
852
+ "'": '&#x27;'
853
+ };
854
+
855
+ /** Used to convert HTML entities to characters */
856
+ var htmlUnescapes = invert(htmlEscapes);
857
+
858
+ /*--------------------------------------------------------------------------*/
859
+
860
+ /**
861
+ * Creates a clone of `value`. If `deep` is `true`, all nested objects will
862
+ * also be cloned otherwise they will be assigned by reference. Functions, DOM
863
+ * nodes, `arguments` objects, and objects created by constructors other than
864
+ * `Object` are **not** cloned.
865
+ *
866
+ * @static
867
+ * @memberOf _
868
+ * @category Objects
869
+ * @param {Mixed} value The value to clone.
870
+ * @param {Boolean} deep A flag to indicate a deep clone.
871
+ * @param- {Object} [guard] Internally used to allow this method to work with
872
+ * others like `_.map` without using their callback `index` argument for `deep`.
873
+ * @param- {Array} [stackA=[]] Internally used to track traversed source objects.
874
+ * @param- {Array} [stackB=[]] Internally used to associate clones with their
875
+ * source counterparts.
876
+ * @returns {Mixed} Returns the cloned `value`.
877
+ * @example
878
+ *
879
+ * var stooges = [
880
+ * { 'name': 'moe', 'age': 40 },
881
+ * { 'name': 'larry', 'age': 50 },
882
+ * { 'name': 'curly', 'age': 60 }
883
+ * ];
884
+ *
885
+ * _.clone({ 'name': 'moe' });
886
+ * // => { 'name': 'moe' }
887
+ *
888
+ * var shallow = _.clone(stooges);
889
+ * shallow[0] === stooges[0];
890
+ * // => true
891
+ *
892
+ * var deep = _.clone(stooges, true);
893
+ * shallow[0] === stooges[0];
894
+ * // => false
895
+ */
896
+ function clone(value, deep, guard, stackA, stackB) {
897
+ if (value == null) {
898
+ return value;
899
+ }
900
+ if (guard) {
901
+ deep = false;
902
+ }
903
+ // inspect [[Class]]
904
+ var isObj = isObject(value);
905
+ if (isObj) {
906
+ // don't clone `arguments` objects, functions, or non-object Objects
907
+ var className = toString.call(value);
908
+ if (!cloneableClasses[className] || (noArgsClass && isArguments(value))) {
909
+ return value;
910
+ }
911
+ var isArr = className == arrayClass;
912
+ isObj = isArr || (className == objectClass ? isPlainObject(value) : isObj);
913
+ }
914
+ // shallow clone
915
+ if (!isObj || !deep) {
916
+ // don't clone functions
917
+ return isObj
918
+ ? (isArr ? slice.call(value) : extend({}, value))
919
+ : value;
920
+ }
921
+
922
+ var ctor = value.constructor;
923
+ switch (className) {
924
+ case boolClass:
925
+ case dateClass:
926
+ return new ctor(+value);
927
+
928
+ case numberClass:
929
+ case stringClass:
930
+ return new ctor(value);
931
+
932
+ case regexpClass:
933
+ return ctor(value.source, reFlags.exec(value));
934
+ }
935
+ // check for circular references and return corresponding clone
936
+ stackA || (stackA = []);
937
+ stackB || (stackB = []);
938
+
939
+ var length = stackA.length;
940
+ while (length--) {
941
+ if (stackA[length] == value) {
942
+ return stackB[length];
943
+ }
944
+ }
945
+ // init cloned object
946
+ var result = isArr ? ctor(value.length) : {};
947
+
948
+ // add the source value to the stack of traversed objects
949
+ // and associate it with its clone
950
+ stackA.push(value);
951
+ stackB.push(result);
952
+
953
+ // recursively populate clone (susceptible to call stack limits)
954
+ (isArr ? forEach : forOwn)(value, function(objValue, key) {
955
+ result[key] = clone(objValue, deep, null, stackA, stackB);
956
+ });
957
+
958
+ return result;
959
+ }
960
+
961
+ /**
962
+ * Assigns enumerable properties of the default object(s) to the `destination`
963
+ * object for all `destination` properties that resolve to `null`/`undefined`.
964
+ * Once a property is set, additional defaults of the same property will be
965
+ * ignored.
966
+ *
967
+ * @static
968
+ * @memberOf _
969
+ * @category Objects
970
+ * @param {Object} object The destination object.
971
+ * @param {Object} [default1, default2, ...] The default objects.
972
+ * @returns {Object} Returns the destination object.
973
+ * @example
974
+ *
975
+ * var iceCream = { 'flavor': 'chocolate' };
976
+ * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' });
977
+ * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' }
978
+ */
979
+ var defaults = createIterator(extendIteratorOptions, {
980
+ 'objectLoop': 'if (result[index] == null) ' + extendIteratorOptions.objectLoop
981
+ });
982
+
983
+ /**
984
+ * Assigns enumerable properties of the source object(s) to the `destination`
985
+ * object. Subsequent sources will overwrite propery assignments of previous
986
+ * sources.
987
+ *
988
+ * @static
989
+ * @memberOf _
990
+ * @category Objects
991
+ * @param {Object} object The destination object.
992
+ * @param {Object} [source1, source2, ...] The source objects.
993
+ * @returns {Object} Returns the destination object.
994
+ * @example
995
+ *
996
+ * _.extend({ 'name': 'moe' }, { 'age': 40 });
997
+ * // => { 'name': 'moe', 'age': 40 }
998
+ */
999
+ var extend = createIterator(extendIteratorOptions);
1000
+
1001
+ /**
1002
+ * Creates a sorted array of all enumerable properties, own and inherited,
1003
+ * of `object` that have function values.
1004
+ *
1005
+ * @static
1006
+ * @memberOf _
1007
+ * @alias methods
1008
+ * @category Objects
1009
+ * @param {Object} object The object to inspect.
1010
+ * @returns {Array} Returns a new array of property names that have function values.
1011
+ * @example
1012
+ *
1013
+ * _.functions(_);
1014
+ * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
1015
+ */
1016
+ function functions(object) {
1017
+ var result = [];
1018
+ forIn(object, function(value, key) {
1019
+ if (isFunction(value)) {
1020
+ result.push(key);
1021
+ }
1022
+ });
1023
+ return result.sort();
1024
+ }
1025
+
1026
+ /**
1027
+ * Checks if the specified object `property` exists and is a direct property,
1028
+ * instead of an inherited property.
1029
+ *
1030
+ * @static
1031
+ * @memberOf _
1032
+ * @category Objects
1033
+ * @param {Object} object The object to check.
1034
+ * @param {String} property The property to check for.
1035
+ * @returns {Boolean} Returns `true` if key is a direct property, else `false`.
1036
+ * @example
1037
+ *
1038
+ * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
1039
+ * // => true
1040
+ */
1041
+ function has(object, property) {
1042
+ return object ? hasOwnProperty.call(object, property) : false;
1043
+ }
1044
+
1045
+ /**
1046
+ * Creates an object composed of the inverted keys and values of the given `object`.
1047
+ *
1048
+ * @static
1049
+ * @memberOf _
1050
+ * @category Objects
1051
+ * @param {Object} object The object to invert.
1052
+ * @returns {Object} Returns the created inverted object.
1053
+ * @example
1054
+ *
1055
+ * _.invert({ 'first': 'Moe', 'second': 'Larry', 'third': 'Curly' });
1056
+ * // => { 'Moe': 'first', 'Larry': 'second', 'Curly': 'third' } (order is not guaranteed)
1057
+ */
1058
+ function invert(object) {
1059
+ var result = {};
1060
+ forOwn(object, function(value, key) {
1061
+ result[value] = key;
1062
+ });
1063
+ return result;
1064
+ }
1065
+
1066
+ /**
1067
+ * Checks if `value` is an array.
1068
+ *
1069
+ * @static
1070
+ * @memberOf _
1071
+ * @category Objects
1072
+ * @param {Mixed} value The value to check.
1073
+ * @returns {Boolean} Returns `true` if the `value` is an array, else `false`.
1074
+ * @example
1075
+ *
1076
+ * (function() { return _.isArray(arguments); })();
1077
+ * // => false
1078
+ *
1079
+ * _.isArray([1, 2, 3]);
1080
+ * // => true
1081
+ */
1082
+ var isArray = nativeIsArray || function(value) {
1083
+ return toString.call(value) == arrayClass;
1084
+ };
1085
+
1086
+ /**
1087
+ * Checks if `value` is a boolean (`true` or `false`) value.
1088
+ *
1089
+ * @static
1090
+ * @memberOf _
1091
+ * @category Objects
1092
+ * @param {Mixed} value The value to check.
1093
+ * @returns {Boolean} Returns `true` if the `value` is a boolean value, else `false`.
1094
+ * @example
1095
+ *
1096
+ * _.isBoolean(null);
1097
+ * // => false
1098
+ */
1099
+ function isBoolean(value) {
1100
+ return value === true || value === false || toString.call(value) == boolClass;
1101
+ }
1102
+
1103
+ /**
1104
+ * Checks if `value` is a date.
1105
+ *
1106
+ * @static
1107
+ * @memberOf _
1108
+ * @category Objects
1109
+ * @param {Mixed} value The value to check.
1110
+ * @returns {Boolean} Returns `true` if the `value` is a date, else `false`.
1111
+ * @example
1112
+ *
1113
+ * _.isDate(new Date);
1114
+ * // => true
1115
+ */
1116
+ function isDate(value) {
1117
+ return toString.call(value) == dateClass;
1118
+ }
1119
+
1120
+ /**
1121
+ * Checks if `value` is a DOM element.
1122
+ *
1123
+ * @static
1124
+ * @memberOf _
1125
+ * @category Objects
1126
+ * @param {Mixed} value The value to check.
1127
+ * @returns {Boolean} Returns `true` if the `value` is a DOM element, else `false`.
1128
+ * @example
1129
+ *
1130
+ * _.isElement(document.body);
1131
+ * // => true
1132
+ */
1133
+ function isElement(value) {
1134
+ return value ? value.nodeType === 1 : false;
1135
+ }
1136
+
1137
+ /**
1138
+ * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
1139
+ * length of `0` and objects with no own enumerable properties are considered
1140
+ * "empty".
1141
+ *
1142
+ * @static
1143
+ * @memberOf _
1144
+ * @category Objects
1145
+ * @param {Array|Object|String} value The value to inspect.
1146
+ * @returns {Boolean} Returns `true` if the `value` is empty, else `false`.
1147
+ * @example
1148
+ *
1149
+ * _.isEmpty([1, 2, 3]);
1150
+ * // => false
1151
+ *
1152
+ * _.isEmpty({});
1153
+ * // => true
1154
+ *
1155
+ * _.isEmpty('');
1156
+ * // => true
1157
+ */
1158
+ function isEmpty(value) {
1159
+ var result = true;
1160
+ if (!value) {
1161
+ return result;
1162
+ }
1163
+ var className = toString.call(value),
1164
+ length = value.length;
1165
+
1166
+ if ((className == arrayClass || className == stringClass ||
1167
+ className == argsClass || (noArgsClass && isArguments(value))) ||
1168
+ (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
1169
+ return !length;
1170
+ }
1171
+ forOwn(value, function() {
1172
+ return (result = false);
1173
+ });
1174
+ return result;
1175
+ }
1176
+
1177
+ /**
1178
+ * Performs a deep comparison between two values to determine if they are
1179
+ * equivalent to each other.
1180
+ *
1181
+ * @static
1182
+ * @memberOf _
1183
+ * @category Objects
1184
+ * @param {Mixed} a The value to compare.
1185
+ * @param {Mixed} b The other value to compare.
1186
+ * @param- {Object} [stackA=[]] Internally used track traversed `a` objects.
1187
+ * @param- {Object} [stackB=[]] Internally used track traversed `b` objects.
1188
+ * @returns {Boolean} Returns `true` if the values are equvalent, else `false`.
1189
+ * @example
1190
+ *
1191
+ * var moe = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] };
1192
+ * var clone = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] };
1193
+ *
1194
+ * moe == clone;
1195
+ * // => false
1196
+ *
1197
+ * _.isEqual(moe, clone);
1198
+ * // => true
1199
+ */
1200
+ function isEqual(a, b, stackA, stackB) {
1201
+ // exit early for identical values
1202
+ if (a === b) {
1203
+ // treat `+0` vs. `-0` as not equal
1204
+ return a !== 0 || (1 / a == 1 / b);
1205
+ }
1206
+ // a strict comparison is necessary because `null == undefined`
1207
+ if (a == null || b == null) {
1208
+ return a === b;
1209
+ }
1210
+ // compare [[Class]] names
1211
+ var className = toString.call(a);
1212
+ if (className != toString.call(b)) {
1213
+ return false;
1214
+ }
1215
+ switch (className) {
1216
+ case boolClass:
1217
+ case dateClass:
1218
+ // coerce dates and booleans to numbers, dates to milliseconds and booleans
1219
+ // to `1` or `0`, treating invalid dates coerced to `NaN` as not equal
1220
+ return +a == +b;
1221
+
1222
+ case numberClass:
1223
+ // treat `NaN` vs. `NaN` as equal
1224
+ return a != +a
1225
+ ? b != +b
1226
+ // but treat `+0` vs. `-0` as not equal
1227
+ : (a == 0 ? (1 / a == 1 / b) : a == +b);
1228
+
1229
+ case regexpClass:
1230
+ case stringClass:
1231
+ // coerce regexes to strings (http://es5.github.com/#x15.10.6.4)
1232
+ // treat string primitives and their corresponding object instances as equal
1233
+ return a == b + '';
1234
+ }
1235
+ // exit early, in older browsers, if `a` is array-like but not `b`
1236
+ var isArr = className == arrayClass || className == argsClass;
1237
+ if (noArgsClass && !isArr && (isArr = isArguments(a)) && !isArguments(b)) {
1238
+ return false;
1239
+ }
1240
+ if (!isArr) {
1241
+ // unwrap any `lodash` wrapped values
1242
+ if (a.__wrapped__ || b.__wrapped__) {
1243
+ return isEqual(a.__wrapped__ || a, b.__wrapped__ || b);
1244
+ }
1245
+ // exit for functions and DOM nodes
1246
+ if (className != objectClass || (noNodeClass && (
1247
+ (typeof a.toString != 'function' && typeof (a + '') == 'string') ||
1248
+ (typeof b.toString != 'function' && typeof (b + '') == 'string')))) {
1249
+ return false;
1250
+ }
1251
+ var ctorA = a.constructor,
1252
+ ctorB = b.constructor;
1253
+
1254
+ // non `Object` object instances with different constructors are not equal
1255
+ if (ctorA != ctorB && !(
1256
+ isFunction(ctorA) && ctorA instanceof ctorA &&
1257
+ isFunction(ctorB) && ctorB instanceof ctorB
1258
+ )) {
1259
+ return false;
1260
+ }
1261
+ }
1262
+ // assume cyclic structures are equal
1263
+ // the algorithm for detecting cyclic structures is adapted from ES 5.1
1264
+ // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3)
1265
+ stackA || (stackA = []);
1266
+ stackB || (stackB = []);
1267
+
1268
+ var length = stackA.length;
1269
+ while (length--) {
1270
+ if (stackA[length] == a) {
1271
+ return stackB[length] == b;
1272
+ }
1273
+ }
1274
+
1275
+ var index = -1,
1276
+ result = true,
1277
+ size = 0;
1278
+
1279
+ // add `a` and `b` to the stack of traversed objects
1280
+ stackA.push(a);
1281
+ stackB.push(b);
1282
+
1283
+ // recursively compare objects and arrays (susceptible to call stack limits)
1284
+ if (isArr) {
1285
+ // compare lengths to determine if a deep comparison is necessary
1286
+ size = a.length;
1287
+ result = size == b.length;
1288
+
1289
+ if (result) {
1290
+ // deep compare the contents, ignoring non-numeric properties
1291
+ while (size--) {
1292
+ if (!(result = isEqual(a[size], b[size], stackA, stackB))) {
1293
+ break;
1294
+ }
1295
+ }
1296
+ }
1297
+ return result;
1298
+ }
1299
+ // deep compare objects
1300
+ for (var key in a) {
1301
+ if (hasOwnProperty.call(a, key)) {
1302
+ // count the number of properties.
1303
+ size++;
1304
+ // deep compare each property value.
1305
+ if (!(hasOwnProperty.call(b, key) && isEqual(a[key], b[key], stackA, stackB))) {
1306
+ return false;
1307
+ }
1308
+ }
1309
+ }
1310
+ // ensure both objects have the same number of properties
1311
+ for (key in b) {
1312
+ // The JS engine in Adobe products, like InDesign, has a bug that causes
1313
+ // `!size--` to throw an error so it must be wrapped in parentheses.
1314
+ // https://github.com/documentcloud/underscore/issues/355
1315
+ if (hasOwnProperty.call(b, key) && !(size--)) {
1316
+ // `size` will be `-1` if `b` has more properties than `a`
1317
+ return false;
1318
+ }
1319
+ }
1320
+ // handle JScript [[DontEnum]] bug
1321
+ if (hasDontEnumBug) {
1322
+ while (++index < 7) {
1323
+ key = shadowed[index];
1324
+ if (hasOwnProperty.call(a, key) &&
1325
+ !(hasOwnProperty.call(b, key) && isEqual(a[key], b[key], stackA, stackB))) {
1326
+ return false;
1327
+ }
1328
+ }
1329
+ }
1330
+ return true;
1331
+ }
1332
+
1333
+ /**
1334
+ * Checks if `value` is, or can be coerced to, a finite number.
1335
+ *
1336
+ * Note: This is not the same as native `isFinite`, which will return true for
1337
+ * booleans and empty strings. See http://es5.github.com/#x15.1.2.5.
1338
+ *
1339
+ * @deprecated
1340
+ * @static
1341
+ * @memberOf _
1342
+ * @category Objects
1343
+ * @param {Mixed} value The value to check.
1344
+ * @returns {Boolean} Returns `true` if the `value` is a finite number, else `false`.
1345
+ * @example
1346
+ *
1347
+ * _.isFinite(-101);
1348
+ * // => true
1349
+ *
1350
+ * _.isFinite('10');
1351
+ * // => true
1352
+ *
1353
+ * _.isFinite(true);
1354
+ * // => false
1355
+ *
1356
+ * _.isFinite('');
1357
+ * // => false
1358
+ *
1359
+ * _.isFinite(Infinity);
1360
+ * // => false
1361
+ */
1362
+ function isFinite(value) {
1363
+ return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
1364
+ }
1365
+
1366
+ /**
1367
+ * Checks if `value` is a function.
1368
+ *
1369
+ * @static
1370
+ * @memberOf _
1371
+ * @category Objects
1372
+ * @param {Mixed} value The value to check.
1373
+ * @returns {Boolean} Returns `true` if the `value` is a function, else `false`.
1374
+ * @example
1375
+ *
1376
+ * _.isFunction(_);
1377
+ * // => true
1378
+ */
1379
+ function isFunction(value) {
1380
+ return typeof value == 'function';
1381
+ }
1382
+ // fallback for older versions of Chrome and Safari
1383
+ if (isFunction(/x/)) {
1384
+ isFunction = function(value) {
1385
+ return toString.call(value) == funcClass;
1386
+ };
1387
+ }
1388
+
1389
+ /**
1390
+ * Checks if `value` is the language type of Object.
1391
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
1392
+ *
1393
+ * @static
1394
+ * @memberOf _
1395
+ * @category Objects
1396
+ * @param {Mixed} value The value to check.
1397
+ * @returns {Boolean} Returns `true` if the `value` is an object, else `false`.
1398
+ * @example
1399
+ *
1400
+ * _.isObject({});
1401
+ * // => true
1402
+ *
1403
+ * _.isObject([1, 2, 3]);
1404
+ * // => true
1405
+ *
1406
+ * _.isObject(1);
1407
+ * // => false
1408
+ */
1409
+ function isObject(value) {
1410
+ // check if the value is the ECMAScript language type of Object
1411
+ // http://es5.github.com/#x8
1412
+ // and avoid a V8 bug
1413
+ // http://code.google.com/p/v8/issues/detail?id=2291
1414
+ return value ? objectTypes[typeof value] : false;
1415
+ }
1416
+
1417
+ /**
1418
+ * Checks if `value` is `NaN`.
1419
+ *
1420
+ * Note: This is not the same as native `isNaN`, which will return true for
1421
+ * `undefined` and other values. See http://es5.github.com/#x15.1.2.4.
1422
+ *
1423
+ * @deprecated
1424
+ * @static
1425
+ * @memberOf _
1426
+ * @category Objects
1427
+ * @param {Mixed} value The value to check.
1428
+ * @returns {Boolean} Returns `true` if the `value` is `NaN`, else `false`.
1429
+ * @example
1430
+ *
1431
+ * _.isNaN(NaN);
1432
+ * // => true
1433
+ *
1434
+ * _.isNaN(new Number(NaN));
1435
+ * // => true
1436
+ *
1437
+ * isNaN(undefined);
1438
+ * // => true
1439
+ *
1440
+ * _.isNaN(undefined);
1441
+ * // => false
1442
+ */
1443
+ function isNaN(value) {
1444
+ // `NaN` as a primitive is the only value that is not equal to itself
1445
+ // (perform the [[Class]] check first to avoid errors with some host objects in IE)
1446
+ return toString.call(value) == numberClass && value != +value
1447
+ }
1448
+
1449
+ /**
1450
+ * Checks if `value` is `null`.
1451
+ *
1452
+ * @deprecated
1453
+ * @static
1454
+ * @memberOf _
1455
+ * @category Objects
1456
+ * @param {Mixed} value The value to check.
1457
+ * @returns {Boolean} Returns `true` if the `value` is `null`, else `false`.
1458
+ * @example
1459
+ *
1460
+ * _.isNull(null);
1461
+ * // => true
1462
+ *
1463
+ * _.isNull(undefined);
1464
+ * // => false
1465
+ */
1466
+ function isNull(value) {
1467
+ return value === null;
1468
+ }
1469
+
1470
+ /**
1471
+ * Checks if `value` is a number.
1472
+ *
1473
+ * @static
1474
+ * @memberOf _
1475
+ * @category Objects
1476
+ * @param {Mixed} value The value to check.
1477
+ * @returns {Boolean} Returns `true` if the `value` is a number, else `false`.
1478
+ * @example
1479
+ *
1480
+ * _.isNumber(8.4 * 5);
1481
+ * // => true
1482
+ */
1483
+ function isNumber(value) {
1484
+ return toString.call(value) == numberClass;
1485
+ }
1486
+
1487
+ /**
1488
+ * Checks if a given `value` is an object created by the `Object` constructor.
1489
+ *
1490
+ * @static
1491
+ * @memberOf _
1492
+ * @category Objects
1493
+ * @param {Mixed} value The value to check.
1494
+ * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`.
1495
+ * @example
1496
+ *
1497
+ * function Stooge(name, age) {
1498
+ * this.name = name;
1499
+ * this.age = age;
1500
+ * }
1501
+ *
1502
+ * _.isPlainObject(new Stooge('moe', 40));
1503
+ * // => false
1504
+ *
1505
+ * _.isPlainObject([1, 2, 3]);
1506
+ * // => false
1507
+ *
1508
+ * _.isPlainObject({ 'name': 'moe', 'age': 40 });
1509
+ * // => true
1510
+ */
1511
+ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
1512
+ if (!(value && typeof value == 'object')) {
1513
+ return false;
1514
+ }
1515
+ var valueOf = value.valueOf,
1516
+ objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
1517
+
1518
+ return objProto
1519
+ ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value))
1520
+ : shimIsPlainObject(value);
1521
+ };
1522
+
1523
+ /**
1524
+ * Checks if `value` is a regular expression.
1525
+ *
1526
+ * @static
1527
+ * @memberOf _
1528
+ * @category Objects
1529
+ * @param {Mixed} value The value to check.
1530
+ * @returns {Boolean} Returns `true` if the `value` is a regular expression, else `false`.
1531
+ * @example
1532
+ *
1533
+ * _.isRegExp(/moe/);
1534
+ * // => true
1535
+ */
1536
+ function isRegExp(value) {
1537
+ return toString.call(value) == regexpClass;
1538
+ }
1539
+
1540
+ /**
1541
+ * Checks if `value` is a string.
1542
+ *
1543
+ * @static
1544
+ * @memberOf _
1545
+ * @category Objects
1546
+ * @param {Mixed} value The value to check.
1547
+ * @returns {Boolean} Returns `true` if the `value` is a string, else `false`.
1548
+ * @example
1549
+ *
1550
+ * _.isString('moe');
1551
+ * // => true
1552
+ */
1553
+ function isString(value) {
1554
+ return toString.call(value) == stringClass;
1555
+ }
1556
+
1557
+ /**
1558
+ * Checks if `value` is `undefined`.
1559
+ *
1560
+ * @deprecated
1561
+ * @static
1562
+ * @memberOf _
1563
+ * @category Objects
1564
+ * @param {Mixed} value The value to check.
1565
+ * @returns {Boolean} Returns `true` if the `value` is `undefined`, else `false`.
1566
+ * @example
1567
+ *
1568
+ * _.isUndefined(void 0);
1569
+ * // => true
1570
+ */
1571
+ function isUndefined(value) {
1572
+ return value === undefined;
1573
+ }
1574
+
1575
+ /**
1576
+ * Creates an array composed of the own enumerable property names of `object`.
1577
+ *
1578
+ * @static
1579
+ * @memberOf _
1580
+ * @category Objects
1581
+ * @param {Object} object The object to inspect.
1582
+ * @returns {Array} Returns a new array of property names.
1583
+ * @example
1584
+ *
1585
+ * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
1586
+ * // => ['one', 'two', 'three'] (order is not guaranteed)
1587
+ */
1588
+ var keys = !nativeKeys ? shimKeys : function(object) {
1589
+ // avoid iterating over the `prototype` property
1590
+ return typeof object == 'function' && propertyIsEnumerable.call(object, 'prototype')
1591
+ ? shimKeys(object)
1592
+ : (isObject(object) ? nativeKeys(object) : []);
1593
+ };
1594
+
1595
+ /**
1596
+ * Merges enumerable properties of the source object(s) into the `destination`
1597
+ * object. Subsequent sources will overwrite propery assignments of previous
1598
+ * sources.
1599
+ *
1600
+ * @static
1601
+ * @memberOf _
1602
+ * @category Objects
1603
+ * @param {Object} object The destination object.
1604
+ * @param {Object} [source1, source2, ...] The source objects.
1605
+ * @param- {Object} [indicator] Internally used to indicate that the `stack`
1606
+ * argument is an array of traversed objects instead of another source object.
1607
+ * @param- {Array} [stackA=[]] Internally used to track traversed source objects.
1608
+ * @param- {Array} [stackB=[]] Internally used to associate values with their
1609
+ * source counterparts.
1610
+ * @returns {Object} Returns the destination object.
1611
+ * @example
1612
+ *
1613
+ * var stooges = [
1614
+ * { 'name': 'moe' },
1615
+ * { 'name': 'larry' }
1616
+ * ];
1617
+ *
1618
+ * var ages = [
1619
+ * { 'age': 40 },
1620
+ * { 'age': 50 }
1621
+ * ];
1622
+ *
1623
+ * _.merge(stooges, ages);
1624
+ * // => [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }]
1625
+ */
1626
+ function merge(object, source, indicator) {
1627
+ var args = arguments,
1628
+ index = 0,
1629
+ length = 2,
1630
+ stackA = args[3],
1631
+ stackB = args[4];
1632
+
1633
+ if (indicator !== objectRef) {
1634
+ stackA = [];
1635
+ stackB = [];
1636
+ length = args.length;
1637
+ }
1638
+ while (++index < length) {
1639
+ forOwn(args[index], function(source, key) {
1640
+ var found, isArr, value;
1641
+ if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
1642
+ // avoid merging previously merged cyclic sources
1643
+ var stackLength = stackA.length;
1644
+ while (stackLength--) {
1645
+ found = stackA[stackLength] == source;
1646
+ if (found) {
1647
+ break;
1648
+ }
1649
+ }
1650
+ if (found) {
1651
+ object[key] = stackB[stackLength];
1652
+ }
1653
+ else {
1654
+ // add `source` and associated `value` to the stack of traversed objects
1655
+ stackA.push(source);
1656
+ stackB.push(value = (value = object[key], isArr)
1657
+ ? (isArray(value) ? value : [])
1658
+ : (isPlainObject(value) ? value : {})
1659
+ );
1660
+ // recursively merge objects and arrays (susceptible to call stack limits)
1661
+ object[key] = merge(value, source, objectRef, stackA, stackB);
1662
+ }
1663
+ } else if (source != null) {
1664
+ object[key] = source;
1665
+ }
1666
+ });
1667
+ }
1668
+ return object;
1669
+ }
1670
+
1671
+ /**
1672
+ * Creates a shallow clone of `object` excluding the specified properties.
1673
+ * Property names may be specified as individual arguments or as arrays of
1674
+ * property names. If `callback` is passed, it will be executed for each property
1675
+ * in the `object`, omitting the properties `callback` returns truthy for. The
1676
+ * `callback` is bound to `thisArg` and invoked with three arguments; (value, key, object).
1677
+ *
1678
+ * @static
1679
+ * @memberOf _
1680
+ * @category Objects
1681
+ * @param {Object} object The source object.
1682
+ * @param {Function|String} callback|[prop1, prop2, ...] The properties to omit
1683
+ * or the function called per iteration.
1684
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
1685
+ * @returns {Object} Returns an object without the omitted properties.
1686
+ * @example
1687
+ *
1688
+ * _.omit({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'userid');
1689
+ * // => { 'name': 'moe', 'age': 40 }
1690
+ *
1691
+ * _.omit({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(value, key) {
1692
+ * return key.charAt(0) == '_';
1693
+ * });
1694
+ * // => { 'name': 'moe' }
1695
+ */
1696
+ function omit(object, callback, thisArg) {
1697
+ var isFunc = typeof callback == 'function',
1698
+ result = {};
1699
+
1700
+ if (isFunc) {
1701
+ callback = createCallback(callback, thisArg);
1702
+ } else {
1703
+ var props = concat.apply(arrayRef, arguments);
1704
+ }
1705
+ forIn(object, function(value, key, object) {
1706
+ if (isFunc
1707
+ ? !callback(value, key, object)
1708
+ : indexOf(props, key, 1) < 0
1709
+ ) {
1710
+ result[key] = value;
1711
+ }
1712
+ });
1713
+ return result;
1714
+ }
1715
+
1716
+ /**
1717
+ * Creates a two dimensional array of the given object's key-value pairs,
1718
+ * i.e. `[[key1, value1], [key2, value2]]`.
1719
+ *
1720
+ * @static
1721
+ * @memberOf _
1722
+ * @category Objects
1723
+ * @param {Object} object The object to inspect.
1724
+ * @returns {Array} Returns new array of key-value pairs.
1725
+ * @example
1726
+ *
1727
+ * _.pairs({ 'moe': 30, 'larry': 40, 'curly': 50 });
1728
+ * // => [['moe', 30], ['larry', 40], ['curly', 50]] (order is not guaranteed)
1729
+ */
1730
+ function pairs(object) {
1731
+ var result = [];
1732
+ forOwn(object, function(value, key) {
1733
+ result.push([key, value]);
1734
+ });
1735
+ return result;
1736
+ }
1737
+
1738
+ /**
1739
+ * Creates a shallow clone of `object` composed of the specified properties.
1740
+ * Property names may be specified as individual arguments or as arrays of
1741
+ * property names. If `callback` is passed, it will be executed for each property
1742
+ * in the `object`, picking the properties `callback` returns truthy for. The
1743
+ * `callback` is bound to `thisArg` and invoked with three arguments; (value, key, object).
1744
+ *
1745
+ * @static
1746
+ * @memberOf _
1747
+ * @category Objects
1748
+ * @param {Object} object The source object.
1749
+ * @param {Function|String} callback|[prop1, prop2, ...] The properties to pick
1750
+ * or the function called per iteration.
1751
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
1752
+ * @returns {Object} Returns an object composed of the picked properties.
1753
+ * @example
1754
+ *
1755
+ * _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age');
1756
+ * // => { 'name': 'moe', 'age': 40 }
1757
+ *
1758
+ * _.pick({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(value, key) {
1759
+ * return key.charAt(0) != '_';
1760
+ * });
1761
+ * // => { 'name': 'moe' }
1762
+ */
1763
+ function pick(object, callback, thisArg) {
1764
+ var result = {};
1765
+ if (typeof callback != 'function') {
1766
+ var index = 0,
1767
+ props = concat.apply(arrayRef, arguments),
1768
+ length = props.length;
1769
+
1770
+ while (++index < length) {
1771
+ var key = props[index];
1772
+ if (key in object) {
1773
+ result[key] = object[key];
1774
+ }
1775
+ }
1776
+ } else {
1777
+ callback = createCallback(callback, thisArg);
1778
+ forIn(object, function(value, key, object) {
1779
+ if (callback(value, key, object)) {
1780
+ result[key] = value;
1781
+ }
1782
+ });
1783
+ }
1784
+ return result;
1785
+ }
1786
+
1787
+ /**
1788
+ * Creates an array composed of the own enumerable property values of `object`.
1789
+ *
1790
+ * @static
1791
+ * @memberOf _
1792
+ * @category Objects
1793
+ * @param {Object} object The object to inspect.
1794
+ * @returns {Array} Returns a new array of property values.
1795
+ * @example
1796
+ *
1797
+ * _.values({ 'one': 1, 'two': 2, 'three': 3 });
1798
+ * // => [1, 2, 3]
1799
+ */
1800
+ function values(object) {
1801
+ var result = [];
1802
+ forOwn(object, function(value) {
1803
+ result.push(value);
1804
+ });
1805
+ return result;
1806
+ }
1807
+
1808
+ /*--------------------------------------------------------------------------*/
1809
+
1810
+ /**
1811
+ * Checks if a given `target` element is present in a `collection` using strict
1812
+ * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
1813
+ * as the offset from the end of the collection.
1814
+ *
1815
+ * @static
1816
+ * @memberOf _
1817
+ * @alias include
1818
+ * @category Collections
1819
+ * @param {Array|Object|String} collection The collection to iterate over.
1820
+ * @param {Mixed} target The value to check for.
1821
+ * @param {Number} [fromIndex=0] The index to search from.
1822
+ * @returns {Boolean} Returns `true` if the `target` element is found, else `false`.
1823
+ * @example
1824
+ *
1825
+ * _.contains([1, 2, 3], 1);
1826
+ * // => true
1827
+ *
1828
+ * _.contains([1, 2, 3], 1, 2);
1829
+ * // => false
1830
+ *
1831
+ * _.contains({ 'name': 'moe', 'age': 40 }, 'moe');
1832
+ * // => true
1833
+ *
1834
+ * _.contains('curly', 'ur');
1835
+ * // => true
1836
+ */
1837
+ function contains(collection, target, fromIndex) {
1838
+ var index = -1,
1839
+ length = collection ? collection.length : 0;
1840
+
1841
+ fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
1842
+ if (typeof length == 'number') {
1843
+ return (isString(collection)
1844
+ ? collection.indexOf(target, fromIndex)
1845
+ : indexOf(collection, target, fromIndex)
1846
+ ) > -1;
1847
+ }
1848
+ return some(collection, function(value) {
1849
+ return ++index >= fromIndex && value === target;
1850
+ });
1851
+ }
1852
+
1853
+ /**
1854
+ * Creates an object composed of keys returned from running each element of
1855
+ * `collection` through a `callback`. The corresponding value of each key is
1856
+ * the number of times the key was returned by `callback`. The `callback` is
1857
+ * bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
1858
+ * The `callback` argument may also be the name of a property to count by (e.g. 'length').
1859
+ *
1860
+ * @static
1861
+ * @memberOf _
1862
+ * @category Collections
1863
+ * @param {Array|Object|String} collection The collection to iterate over.
1864
+ * @param {Function|String} callback|property The function called per iteration
1865
+ * or property name to count by.
1866
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
1867
+ * @returns {Object} Returns the composed aggregate object.
1868
+ * @example
1869
+ *
1870
+ * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
1871
+ * // => { '4': 1, '6': 2 }
1872
+ *
1873
+ * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
1874
+ * // => { '4': 1, '6': 2 }
1875
+ *
1876
+ * _.countBy(['one', 'two', 'three'], 'length');
1877
+ * // => { '3': 2, '5': 1 }
1878
+ */
1879
+ function countBy(collection, callback, thisArg) {
1880
+ var result = {};
1881
+ callback = createCallback(callback, thisArg);
1882
+ forEach(collection, function(value, key, collection) {
1883
+ key = callback(value, key, collection);
1884
+ (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
1885
+ });
1886
+ return result;
1887
+ }
1888
+
1889
+ /**
1890
+ * Checks if the `callback` returns a truthy value for **all** elements of a
1891
+ * `collection`. The `callback` is bound to `thisArg` and invoked with three
1892
+ * arguments; (value, index|key, collection).
1893
+ *
1894
+ * @static
1895
+ * @memberOf _
1896
+ * @alias all
1897
+ * @category Collections
1898
+ * @param {Array|Object|String} collection The collection to iterate over.
1899
+ * @param {Function} [callback=identity] The function called per iteration.
1900
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
1901
+ * @returns {Boolean} Returns `true` if all elements pass the callback check,
1902
+ * else `false`.
1903
+ * @example
1904
+ *
1905
+ * _.every([true, 1, null, 'yes'], Boolean);
1906
+ * // => false
1907
+ */
1908
+ function every(collection, callback, thisArg) {
1909
+ var result = true;
1910
+ callback = createCallback(callback, thisArg);
1911
+
1912
+ if (isArray(collection)) {
1913
+ var index = -1,
1914
+ length = collection.length;
1915
+
1916
+ while (++index < length) {
1917
+ if (!(result = !!callback(collection[index], index, collection))) {
1918
+ break;
1919
+ }
1920
+ }
1921
+ } else {
1922
+ forEach(collection, function(value, index, collection) {
1923
+ return (result = !!callback(value, index, collection));
1924
+ });
1925
+ }
1926
+ return result;
1927
+ }
1928
+
1929
+ /**
1930
+ * Examines each element in a `collection`, returning an array of all elements
1931
+ * the `callback` returns truthy for. The `callback` is bound to `thisArg` and
1932
+ * invoked with three arguments; (value, index|key, collection).
1933
+ *
1934
+ * @static
1935
+ * @memberOf _
1936
+ * @alias select
1937
+ * @category Collections
1938
+ * @param {Array|Object|String} collection The collection to iterate over.
1939
+ * @param {Function} [callback=identity] The function called per iteration.
1940
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
1941
+ * @returns {Array} Returns a new array of elements that passed the callback check.
1942
+ * @example
1943
+ *
1944
+ * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
1945
+ * // => [2, 4, 6]
1946
+ */
1947
+ function filter(collection, callback, thisArg) {
1948
+ var result = [];
1949
+ callback = createCallback(callback, thisArg);
1950
+ forEach(collection, function(value, index, collection) {
1951
+ if (callback(value, index, collection)) {
1952
+ result.push(value);
1953
+ }
1954
+ });
1955
+ return result;
1956
+ }
1957
+
1958
+ /**
1959
+ * Examines each element in a `collection`, returning the first one the `callback`
1960
+ * returns truthy for. The function returns as soon as it finds an acceptable
1961
+ * element, and does not iterate over the entire `collection`. The `callback` is
1962
+ * bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
1963
+ *
1964
+ * @static
1965
+ * @memberOf _
1966
+ * @alias detect
1967
+ * @category Collections
1968
+ * @param {Array|Object|String} collection The collection to iterate over.
1969
+ * @param {Function} callback The function called per iteration.
1970
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
1971
+ * @returns {Mixed} Returns the element that passed the callback check,
1972
+ * else `undefined`.
1973
+ * @example
1974
+ *
1975
+ * var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
1976
+ * // => 2
1977
+ */
1978
+ function find(collection, callback, thisArg) {
1979
+ var result;
1980
+ callback = createCallback(callback, thisArg);
1981
+ forEach(collection, function(value, index, collection) {
1982
+ if (callback(value, index, collection)) {
1983
+ result = value;
1984
+ return false;
1985
+ }
1986
+ });
1987
+ return result;
1988
+ }
1989
+
1990
+ /**
1991
+ * Iterates over a `collection`, executing the `callback` for each element in
1992
+ * the `collection`. The `callback` is bound to `thisArg` and invoked with three
1993
+ * arguments; (value, index|key, collection). Callbacks may exit iteration early
1994
+ * by explicitly returning `false`.
1995
+ *
1996
+ * @static
1997
+ * @memberOf _
1998
+ * @alias each
1999
+ * @category Collections
2000
+ * @param {Array|Object|String} collection The collection to iterate over.
2001
+ * @param {Function} callback The function called per iteration.
2002
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2003
+ * @returns {Array|Object|String} Returns `collection`.
2004
+ * @example
2005
+ *
2006
+ * _([1, 2, 3]).forEach(alert).join(',');
2007
+ * // => alerts each number and returns '1,2,3'
2008
+ *
2009
+ * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert);
2010
+ * // => alerts each number (order is not guaranteed)
2011
+ */
2012
+ var forEach = createIterator(forEachIteratorOptions);
2013
+
2014
+ /**
2015
+ * Creates an object composed of keys returned from running each element of
2016
+ * `collection` through a `callback`. The corresponding value of each key is an
2017
+ * array of elements passed to `callback` that returned the key. The `callback`
2018
+ * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
2019
+ * The `callback` argument may also be the name of a property to group by (e.g. 'length').
2020
+ *
2021
+ * @static
2022
+ * @memberOf _
2023
+ * @category Collections
2024
+ * @param {Array|Object|String} collection The collection to iterate over.
2025
+ * @param {Function|String} callback|property The function called per iteration
2026
+ * or property name to group by.
2027
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2028
+ * @returns {Object} Returns the composed aggregate object.
2029
+ * @example
2030
+ *
2031
+ * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
2032
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
2033
+ *
2034
+ * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
2035
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
2036
+ *
2037
+ * _.groupBy(['one', 'two', 'three'], 'length');
2038
+ * // => { '3': ['one', 'two'], '5': ['three'] }
2039
+ */
2040
+ function groupBy(collection, callback, thisArg) {
2041
+ var result = {};
2042
+ callback = createCallback(callback, thisArg);
2043
+ forEach(collection, function(value, key, collection) {
2044
+ key = callback(value, key, collection);
2045
+ (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
2046
+ });
2047
+ return result;
2048
+ }
2049
+
2050
+ /**
2051
+ * Invokes the method named by `methodName` on each element in the `collection`,
2052
+ * returning an array of the results of each invoked method. Additional arguments
2053
+ * will be passed to each invoked method. If `methodName` is a function it will
2054
+ * be invoked for, and `this` bound to, each element in the `collection`.
2055
+ *
2056
+ * @static
2057
+ * @memberOf _
2058
+ * @category Collections
2059
+ * @param {Array|Object|String} collection The collection to iterate over.
2060
+ * @param {Function|String} methodName The name of the method to invoke or
2061
+ * the function invoked per iteration.
2062
+ * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
2063
+ * @returns {Array} Returns a new array of the results of each invoked method.
2064
+ * @example
2065
+ *
2066
+ * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
2067
+ * // => [[1, 5, 7], [1, 2, 3]]
2068
+ *
2069
+ * _.invoke([123, 456], String.prototype.split, '');
2070
+ * // => [['1', '2', '3'], ['4', '5', '6']]
2071
+ */
2072
+ function invoke(collection, methodName) {
2073
+ var args = slice.call(arguments, 2),
2074
+ isFunc = typeof methodName == 'function',
2075
+ result = [];
2076
+
2077
+ forEach(collection, function(value) {
2078
+ result.push((isFunc ? methodName : value[methodName]).apply(value, args));
2079
+ });
2080
+ return result;
2081
+ }
2082
+
2083
+ /**
2084
+ * Creates an array of values by running each element in the `collection`
2085
+ * through a `callback`. The `callback` is bound to `thisArg` and invoked with
2086
+ * three arguments; (value, index|key, collection).
2087
+ *
2088
+ * @static
2089
+ * @memberOf _
2090
+ * @alias collect
2091
+ * @category Collections
2092
+ * @param {Array|Object|String} collection The collection to iterate over.
2093
+ * @param {Function} [callback=identity] The function called per iteration.
2094
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2095
+ * @returns {Array} Returns a new array of the results of each `callback` execution.
2096
+ * @example
2097
+ *
2098
+ * _.map([1, 2, 3], function(num) { return num * 3; });
2099
+ * // => [3, 6, 9]
2100
+ *
2101
+ * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
2102
+ * // => [3, 6, 9] (order is not guaranteed)
2103
+ */
2104
+ function map(collection, callback, thisArg) {
2105
+ var index = -1,
2106
+ length = collection ? collection.length : 0,
2107
+ result = Array(typeof length == 'number' ? length : 0);
2108
+
2109
+ callback = createCallback(callback, thisArg);
2110
+ if (isArray(collection)) {
2111
+ while (++index < length) {
2112
+ result[index] = callback(collection[index], index, collection);
2113
+ }
2114
+ } else {
2115
+ forEach(collection, function(value, key, collection) {
2116
+ result[++index] = callback(value, key, collection);
2117
+ });
2118
+ }
2119
+ return result;
2120
+ }
2121
+
2122
+ /**
2123
+ * Retrieves the maximum value of an `array`. If `callback` is passed,
2124
+ * it will be executed for each value in the `array` to generate the
2125
+ * criterion by which the value is ranked. The `callback` is bound to
2126
+ * `thisArg` and invoked with three arguments; (value, index, collection).
2127
+ *
2128
+ * @static
2129
+ * @memberOf _
2130
+ * @category Collections
2131
+ * @param {Array|Object|String} collection The collection to iterate over.
2132
+ * @param {Function} [callback] The function called per iteration.
2133
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2134
+ * @returns {Mixed} Returns the maximum value.
2135
+ * @example
2136
+ *
2137
+ * var stooges = [
2138
+ * { 'name': 'moe', 'age': 40 },
2139
+ * { 'name': 'larry', 'age': 50 },
2140
+ * { 'name': 'curly', 'age': 60 }
2141
+ * ];
2142
+ *
2143
+ * _.max(stooges, function(stooge) { return stooge.age; });
2144
+ * // => { 'name': 'curly', 'age': 60 };
2145
+ */
2146
+ function max(collection, callback, thisArg) {
2147
+ var computed = -Infinity,
2148
+ index = -1,
2149
+ length = collection ? collection.length : 0,
2150
+ result = computed;
2151
+
2152
+ if (callback || !isArray(collection)) {
2153
+ callback = !callback && isString(collection)
2154
+ ? charAtCallback
2155
+ : createCallback(callback, thisArg);
2156
+
2157
+ forEach(collection, function(value, index, collection) {
2158
+ var current = callback(value, index, collection);
2159
+ if (current > computed) {
2160
+ computed = current;
2161
+ result = value;
2162
+ }
2163
+ });
2164
+ } else {
2165
+ while (++index < length) {
2166
+ if (collection[index] > result) {
2167
+ result = collection[index];
2168
+ }
2169
+ }
2170
+ }
2171
+ return result;
2172
+ }
2173
+
2174
+ /**
2175
+ * Retrieves the minimum value of an `array`. If `callback` is passed,
2176
+ * it will be executed for each value in the `array` to generate the
2177
+ * criterion by which the value is ranked. The `callback` is bound to `thisArg`
2178
+ * and invoked with three arguments; (value, index, collection).
2179
+ *
2180
+ * @static
2181
+ * @memberOf _
2182
+ * @category Collections
2183
+ * @param {Array|Object|String} collection The collection to iterate over.
2184
+ * @param {Function} [callback] The function called per iteration.
2185
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2186
+ * @returns {Mixed} Returns the minimum value.
2187
+ * @example
2188
+ *
2189
+ * _.min([10, 5, 100, 2, 1000]);
2190
+ * // => 2
2191
+ */
2192
+ function min(collection, callback, thisArg) {
2193
+ var computed = Infinity,
2194
+ index = -1,
2195
+ length = collection ? collection.length : 0,
2196
+ result = computed;
2197
+
2198
+ if (callback || !isArray(collection)) {
2199
+ callback = !callback && isString(collection)
2200
+ ? charAtCallback
2201
+ : createCallback(callback, thisArg);
2202
+
2203
+ forEach(collection, function(value, index, collection) {
2204
+ var current = callback(value, index, collection);
2205
+ if (current < computed) {
2206
+ computed = current;
2207
+ result = value;
2208
+ }
2209
+ });
2210
+ } else {
2211
+ while (++index < length) {
2212
+ if (collection[index] < result) {
2213
+ result = collection[index];
2214
+ }
2215
+ }
2216
+ }
2217
+ return result;
2218
+ }
2219
+
2220
+ /**
2221
+ * Retrieves the value of a specified property from all elements in
2222
+ * the `collection`.
2223
+ *
2224
+ * @static
2225
+ * @memberOf _
2226
+ * @category Collections
2227
+ * @param {Array|Object|String} collection The collection to iterate over.
2228
+ * @param {String} property The property to pluck.
2229
+ * @returns {Array} Returns a new array of property values.
2230
+ * @example
2231
+ *
2232
+ * var stooges = [
2233
+ * { 'name': 'moe', 'age': 40 },
2234
+ * { 'name': 'larry', 'age': 50 },
2235
+ * { 'name': 'curly', 'age': 60 }
2236
+ * ];
2237
+ *
2238
+ * _.pluck(stooges, 'name');
2239
+ * // => ['moe', 'larry', 'curly']
2240
+ */
2241
+ function pluck(collection, property) {
2242
+ var result = [];
2243
+ forEach(collection, function(value) {
2244
+ result.push(value[property]);
2245
+ });
2246
+ return result;
2247
+ }
2248
+
2249
+ /**
2250
+ * Boils down a `collection` to a single value. The initial state of the
2251
+ * reduction is `accumulator` and each successive step of it should be returned
2252
+ * by the `callback`. The `callback` is bound to `thisArg` and invoked with 4
2253
+ * arguments; for arrays they are (accumulator, value, index|key, collection).
2254
+ *
2255
+ * @static
2256
+ * @memberOf _
2257
+ * @alias foldl, inject
2258
+ * @category Collections
2259
+ * @param {Array|Object|String} collection The collection to iterate over.
2260
+ * @param {Function} callback The function called per iteration.
2261
+ * @param {Mixed} [accumulator] Initial value of the accumulator.
2262
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2263
+ * @returns {Mixed} Returns the accumulated value.
2264
+ * @example
2265
+ *
2266
+ * var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; });
2267
+ * // => 6
2268
+ */
2269
+ function reduce(collection, callback, accumulator, thisArg) {
2270
+ var noaccum = arguments.length < 3;
2271
+ callback = createCallback(callback, thisArg);
2272
+ forEach(collection, function(value, index, collection) {
2273
+ accumulator = noaccum
2274
+ ? (noaccum = false, value)
2275
+ : callback(accumulator, value, index, collection)
2276
+ });
2277
+ return accumulator;
2278
+ }
2279
+
2280
+ /**
2281
+ * The right-associative version of `_.reduce`.
2282
+ *
2283
+ * @static
2284
+ * @memberOf _
2285
+ * @alias foldr
2286
+ * @category Collections
2287
+ * @param {Array|Object|String} collection The collection to iterate over.
2288
+ * @param {Function} callback The function called per iteration.
2289
+ * @param {Mixed} [accumulator] Initial value of the accumulator.
2290
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2291
+ * @returns {Mixed} Returns the accumulated value.
2292
+ * @example
2293
+ *
2294
+ * var list = [[0, 1], [2, 3], [4, 5]];
2295
+ * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
2296
+ * // => [4, 5, 2, 3, 0, 1]
2297
+ */
2298
+ function reduceRight(collection, callback, accumulator, thisArg) {
2299
+ var iteratee = collection,
2300
+ length = collection ? collection.length : 0,
2301
+ noaccum = arguments.length < 3;
2302
+
2303
+ if (typeof length != 'number') {
2304
+ var props = keys(collection);
2305
+ length = props.length;
2306
+ } else if (noCharByIndex && isString(collection)) {
2307
+ iteratee = collection.split('');
2308
+ }
2309
+ forEach(collection, function(value, index, collection) {
2310
+ index = props ? props[--length] : --length;
2311
+ accumulator = noaccum
2312
+ ? (noaccum = false, iteratee[index])
2313
+ : callback.call(thisArg, accumulator, iteratee[index], index, collection);
2314
+ });
2315
+ return accumulator;
2316
+ }
2317
+
2318
+ /**
2319
+ * The opposite of `_.filter`, this method returns the values of a
2320
+ * `collection` that `callback` does **not** return truthy for.
2321
+ *
2322
+ * @static
2323
+ * @memberOf _
2324
+ * @category Collections
2325
+ * @param {Array|Object|String} collection The collection to iterate over.
2326
+ * @param {Function} [callback=identity] The function called per iteration.
2327
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2328
+ * @returns {Array} Returns a new array of elements that did **not** pass the
2329
+ * callback check.
2330
+ * @example
2331
+ *
2332
+ * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
2333
+ * // => [1, 3, 5]
2334
+ */
2335
+ function reject(collection, callback, thisArg) {
2336
+ callback = createCallback(callback, thisArg);
2337
+ return filter(collection, function(value, index, collection) {
2338
+ return !callback(value, index, collection);
2339
+ });
2340
+ }
2341
+
2342
+ /**
2343
+ * Creates an array of shuffled `array` values, using a version of the
2344
+ * Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
2345
+ *
2346
+ * @static
2347
+ * @memberOf _
2348
+ * @category Collections
2349
+ * @param {Array|Object|String} collection The collection to shuffle.
2350
+ * @returns {Array} Returns a new shuffled collection.
2351
+ * @example
2352
+ *
2353
+ * _.shuffle([1, 2, 3, 4, 5, 6]);
2354
+ * // => [4, 1, 6, 3, 5, 2]
2355
+ */
2356
+ function shuffle(collection) {
2357
+ var index = -1,
2358
+ result = Array(collection ? collection.length : 0);
2359
+
2360
+ forEach(collection, function(value) {
2361
+ var rand = floor(nativeRandom() * (++index + 1));
2362
+ result[index] = result[rand];
2363
+ result[rand] = value;
2364
+ });
2365
+ return result;
2366
+ }
2367
+
2368
+ /**
2369
+ * Gets the size of the `collection` by returning `collection.length` for arrays
2370
+ * and array-like objects or the number of own enumerable properties for objects.
2371
+ *
2372
+ * @static
2373
+ * @memberOf _
2374
+ * @category Collections
2375
+ * @param {Array|Object|String} collection The collection to inspect.
2376
+ * @returns {Number} Returns `collection.length` or number of own enumerable properties.
2377
+ * @example
2378
+ *
2379
+ * _.size([1, 2]);
2380
+ * // => 2
2381
+ *
2382
+ * _.size({ 'one': 1, 'two': 2, 'three': 3 });
2383
+ * // => 3
2384
+ *
2385
+ * _.size('curly');
2386
+ * // => 5
2387
+ */
2388
+ function size(collection) {
2389
+ var length = collection ? collection.length : 0;
2390
+ return typeof length == 'number' ? length : keys(collection).length;
2391
+ }
2392
+
2393
+ /**
2394
+ * Checks if the `callback` returns a truthy value for **any** element of a
2395
+ * `collection`. The function returns as soon as it finds passing value, and
2396
+ * does not iterate over the entire `collection`. The `callback` is bound to
2397
+ * `thisArg` and invoked with three arguments; (value, index|key, collection).
2398
+ *
2399
+ * @static
2400
+ * @memberOf _
2401
+ * @alias any
2402
+ * @category Collections
2403
+ * @param {Array|Object|String} collection The collection to iterate over.
2404
+ * @param {Function} [callback=identity] The function called per iteration.
2405
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2406
+ * @returns {Boolean} Returns `true` if any element passes the callback check,
2407
+ * else `false`.
2408
+ * @example
2409
+ *
2410
+ * _.some([null, 0, 'yes', false]);
2411
+ * // => true
2412
+ */
2413
+ function some(collection, callback, thisArg) {
2414
+ var result;
2415
+ callback = createCallback(callback, thisArg);
2416
+
2417
+ if (isArray(collection)) {
2418
+ var index = -1,
2419
+ length = collection.length;
2420
+
2421
+ while (++index < length) {
2422
+ if (result = callback(collection[index], index, collection)) {
2423
+ break;
2424
+ }
2425
+ }
2426
+ } else {
2427
+ forEach(collection, function(value, index, collection) {
2428
+ return !(result = callback(value, index, collection));
2429
+ });
2430
+ }
2431
+ return !!result;
2432
+ }
2433
+
2434
+ /**
2435
+ * Creates an array, stable sorted in ascending order by the results of
2436
+ * running each element of `collection` through a `callback`. The `callback`
2437
+ * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
2438
+ * The `callback` argument may also be the name of a property to sort by (e.g. 'length').
2439
+ *
2440
+ * @static
2441
+ * @memberOf _
2442
+ * @category Collections
2443
+ * @param {Array|Object|String} collection The collection to iterate over.
2444
+ * @param {Function|String} callback|property The function called per iteration
2445
+ * or property name to sort by.
2446
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2447
+ * @returns {Array} Returns a new array of sorted elements.
2448
+ * @example
2449
+ *
2450
+ * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
2451
+ * // => [3, 1, 2]
2452
+ *
2453
+ * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
2454
+ * // => [3, 1, 2]
2455
+ *
2456
+ * _.sortBy(['larry', 'brendan', 'moe'], 'length');
2457
+ * // => ['moe', 'larry', 'brendan']
2458
+ */
2459
+ function sortBy(collection, callback, thisArg) {
2460
+ var result = [];
2461
+ callback = createCallback(callback, thisArg);
2462
+ forEach(collection, function(value, index, collection) {
2463
+ result.push({
2464
+ 'criteria': callback(value, index, collection),
2465
+ 'index': index,
2466
+ 'value': value
2467
+ });
2468
+ });
2469
+
2470
+ var length = result.length;
2471
+ result.sort(compareAscending);
2472
+ while (length--) {
2473
+ result[length] = result[length].value;
2474
+ }
2475
+ return result;
2476
+ }
2477
+
2478
+ /**
2479
+ * Converts the `collection`, to an array.
2480
+ *
2481
+ * @static
2482
+ * @memberOf _
2483
+ * @category Collections
2484
+ * @param {Array|Object|String} collection The collection to convert.
2485
+ * @returns {Array} Returns the new converted array.
2486
+ * @example
2487
+ *
2488
+ * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
2489
+ * // => [2, 3, 4]
2490
+ */
2491
+ function toArray(collection) {
2492
+ if (collection && typeof collection.length == 'number') {
2493
+ return (noArraySliceOnStrings ? isString(collection) : typeof collection == 'string')
2494
+ ? collection.split('')
2495
+ : slice.call(collection);
2496
+ }
2497
+ return values(collection);
2498
+ }
2499
+
2500
+ /**
2501
+ * Examines each element in a `collection`, returning an array of all elements
2502
+ * that contain the given `properties`.
2503
+ *
2504
+ * @static
2505
+ * @memberOf _
2506
+ * @category Collections
2507
+ * @param {Array|Object|String} collection The collection to iterate over.
2508
+ * @param {Object} properties The object of property values to filter by.
2509
+ * @returns {Array} Returns a new array of elements that contain the given `properties`.
2510
+ * @example
2511
+ *
2512
+ * var stooges = [
2513
+ * { 'name': 'moe', 'age': 40 },
2514
+ * { 'name': 'larry', 'age': 50 },
2515
+ * { 'name': 'curly', 'age': 60 }
2516
+ * ];
2517
+ *
2518
+ * _.where(stooges, { 'age': 40 });
2519
+ * // => [{ 'name': 'moe', 'age': 40 }]
2520
+ */
2521
+ function where(collection, properties) {
2522
+ var props = [];
2523
+ forIn(properties, function(value, prop) {
2524
+ props.push(prop);
2525
+ });
2526
+ return filter(collection, function(object) {
2527
+ var length = props.length;
2528
+ while (length--) {
2529
+ var result = object[props[length]] === properties[props[length]];
2530
+ if (!result) {
2531
+ break;
2532
+ }
2533
+ }
2534
+ return !!result;
2535
+ });
2536
+ }
2537
+
2538
+ /*--------------------------------------------------------------------------*/
2539
+
2540
+ /**
2541
+ * Creates an array with all falsey values of `array` removed. The values
2542
+ * `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey.
2543
+ *
2544
+ * @static
2545
+ * @memberOf _
2546
+ * @category Arrays
2547
+ * @param {Array} array The array to compact.
2548
+ * @returns {Array} Returns a new filtered array.
2549
+ * @example
2550
+ *
2551
+ * _.compact([0, 1, false, 2, '', 3]);
2552
+ * // => [1, 2, 3]
2553
+ */
2554
+ function compact(array) {
2555
+ var index = -1,
2556
+ length = array ? array.length : 0,
2557
+ result = [];
2558
+
2559
+ while (++index < length) {
2560
+ var value = array[index];
2561
+ if (value) {
2562
+ result.push(value);
2563
+ }
2564
+ }
2565
+ return result;
2566
+ }
2567
+
2568
+ /**
2569
+ * Creates an array of `array` elements not present in the other arrays
2570
+ * using strict equality for comparisons, i.e. `===`.
2571
+ *
2572
+ * @static
2573
+ * @memberOf _
2574
+ * @category Arrays
2575
+ * @param {Array} array The array to process.
2576
+ * @param {Array} [array1, array2, ...] Arrays to check.
2577
+ * @returns {Array} Returns a new array of `array` elements not present in the
2578
+ * other arrays.
2579
+ * @example
2580
+ *
2581
+ * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
2582
+ * // => [1, 3, 4]
2583
+ */
2584
+ function difference(array) {
2585
+ var index = -1,
2586
+ length = array ? array.length : 0,
2587
+ flattened = concat.apply(arrayRef, arguments),
2588
+ contains = cachedContains(flattened, length),
2589
+ result = [];
2590
+
2591
+ while (++index < length) {
2592
+ var value = array[index];
2593
+ if (!contains(value)) {
2594
+ result.push(value);
2595
+ }
2596
+ }
2597
+ return result;
2598
+ }
2599
+
2600
+ /**
2601
+ * Gets the first element of the `array`. Pass `n` to return the first `n`
2602
+ * elements of the `array`.
2603
+ *
2604
+ * @static
2605
+ * @memberOf _
2606
+ * @alias head, take
2607
+ * @category Arrays
2608
+ * @param {Array} array The array to query.
2609
+ * @param {Number} [n] The number of elements to return.
2610
+ * @param- {Object} [guard] Internally used to allow this method to work with
2611
+ * others like `_.map` without using their callback `index` argument for `n`.
2612
+ * @returns {Mixed} Returns the first element or an array of the first `n`
2613
+ * elements of `array`.
2614
+ * @example
2615
+ *
2616
+ * _.first([5, 4, 3, 2, 1]);
2617
+ * // => 5
2618
+ */
2619
+ function first(array, n, guard) {
2620
+ if (array) {
2621
+ return (n == null || guard) ? array[0] : slice.call(array, 0, n);
2622
+ }
2623
+ }
2624
+
2625
+ /**
2626
+ * Flattens a nested array (the nesting can be to any depth). If `shallow` is
2627
+ * truthy, `array` will only be flattened a single level.
2628
+ *
2629
+ * @static
2630
+ * @memberOf _
2631
+ * @category Arrays
2632
+ * @param {Array} array The array to compact.
2633
+ * @param {Boolean} shallow A flag to indicate only flattening a single level.
2634
+ * @returns {Array} Returns a new flattened array.
2635
+ * @example
2636
+ *
2637
+ * _.flatten([1, [2], [3, [[4]]]]);
2638
+ * // => [1, 2, 3, 4];
2639
+ *
2640
+ * _.flatten([1, [2], [3, [[4]]]], true);
2641
+ * // => [1, 2, 3, [[4]]];
2642
+ */
2643
+ function flatten(array, shallow) {
2644
+ var index = -1,
2645
+ length = array ? array.length : 0,
2646
+ result = [];
2647
+
2648
+ while (++index < length) {
2649
+ var value = array[index];
2650
+
2651
+ // recursively flatten arrays (susceptible to call stack limits)
2652
+ if (isArray(value)) {
2653
+ push.apply(result, shallow ? value : flatten(value));
2654
+ } else {
2655
+ result.push(value);
2656
+ }
2657
+ }
2658
+ return result;
2659
+ }
2660
+
2661
+ /**
2662
+ * Gets the index at which the first occurrence of `value` is found using
2663
+ * strict equality for comparisons, i.e. `===`. If the `array` is already
2664
+ * sorted, passing `true` for `fromIndex` will run a faster binary search.
2665
+ *
2666
+ * @static
2667
+ * @memberOf _
2668
+ * @category Arrays
2669
+ * @param {Array} array The array to search.
2670
+ * @param {Mixed} value The value to search for.
2671
+ * @param {Boolean|Number} [fromIndex=0] The index to search from or `true` to
2672
+ * perform a binary search on a sorted `array`.
2673
+ * @returns {Number} Returns the index of the matched value or `-1`.
2674
+ * @example
2675
+ *
2676
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2);
2677
+ * // => 1
2678
+ *
2679
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
2680
+ * // => 4
2681
+ *
2682
+ * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
2683
+ * // => 2
2684
+ */
2685
+ function indexOf(array, value, fromIndex) {
2686
+ var index = -1,
2687
+ length = array ? array.length : 0;
2688
+
2689
+ if (typeof fromIndex == 'number') {
2690
+ index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1;
2691
+ } else if (fromIndex) {
2692
+ index = sortedIndex(array, value);
2693
+ return array[index] === value ? index : -1;
2694
+ }
2695
+ while (++index < length) {
2696
+ if (array[index] === value) {
2697
+ return index;
2698
+ }
2699
+ }
2700
+ return -1;
2701
+ }
2702
+
2703
+ /**
2704
+ * Gets all but the last element of `array`. Pass `n` to exclude the last `n`
2705
+ * elements from the result.
2706
+ *
2707
+ * @static
2708
+ * @memberOf _
2709
+ * @category Arrays
2710
+ * @param {Array} array The array to query.
2711
+ * @param {Number} [n=1] The number of elements to exclude.
2712
+ * @param- {Object} [guard] Internally used to allow this method to work with
2713
+ * others like `_.map` without using their callback `index` argument for `n`.
2714
+ * @returns {Array} Returns all but the last element or `n` elements of `array`.
2715
+ * @example
2716
+ *
2717
+ * _.initial([3, 2, 1]);
2718
+ * // => [3, 2]
2719
+ */
2720
+ function initial(array, n, guard) {
2721
+ return array
2722
+ ? slice.call(array, 0, -((n == null || guard) ? 1 : n))
2723
+ : [];
2724
+ }
2725
+
2726
+ /**
2727
+ * Computes the intersection of all the passed-in arrays using strict equality
2728
+ * for comparisons, i.e. `===`.
2729
+ *
2730
+ * @static
2731
+ * @memberOf _
2732
+ * @category Arrays
2733
+ * @param {Array} [array1, array2, ...] Arrays to process.
2734
+ * @returns {Array} Returns a new array of unique elements, in order, that are
2735
+ * present in **all** of the arrays.
2736
+ * @example
2737
+ *
2738
+ * _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
2739
+ * // => [1, 2]
2740
+ */
2741
+ function intersection(array) {
2742
+ var args = arguments,
2743
+ argsLength = args.length,
2744
+ cache = {},
2745
+ result = [];
2746
+
2747
+ forEach(array, function(value) {
2748
+ if (indexOf(result, value) < 0) {
2749
+ var length = argsLength;
2750
+ while (--length) {
2751
+ if (!(cache[length] || (cache[length] = cachedContains(args[length])))(value)) {
2752
+ return;
2753
+ }
2754
+ }
2755
+ result.push(value);
2756
+ }
2757
+ });
2758
+ return result;
2759
+ }
2760
+
2761
+ /**
2762
+ * Gets the last element of the `array`. Pass `n` to return the last `n`
2763
+ * elements of the `array`.
2764
+ *
2765
+ * @static
2766
+ * @memberOf _
2767
+ * @category Arrays
2768
+ * @param {Array} array The array to query.
2769
+ * @param {Number} [n] The number of elements to return.
2770
+ * @param- {Object} [guard] Internally used to allow this method to work with
2771
+ * others like `_.map` without using their callback `index` argument for `n`.
2772
+ * @returns {Mixed} Returns the last element or an array of the last `n`
2773
+ * elements of `array`.
2774
+ * @example
2775
+ *
2776
+ * _.last([3, 2, 1]);
2777
+ * // => 1
2778
+ */
2779
+ function last(array, n, guard) {
2780
+ if (array) {
2781
+ var length = array.length;
2782
+ return (n == null || guard) ? array[length - 1] : slice.call(array, -n || length);
2783
+ }
2784
+ }
2785
+
2786
+ /**
2787
+ * Gets the index at which the last occurrence of `value` is found using strict
2788
+ * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
2789
+ * as the offset from the end of the collection.
2790
+ *
2791
+ * @static
2792
+ * @memberOf _
2793
+ * @category Arrays
2794
+ * @param {Array} array The array to search.
2795
+ * @param {Mixed} value The value to search for.
2796
+ * @param {Number} [fromIndex=array.length-1] The index to search from.
2797
+ * @returns {Number} Returns the index of the matched value or `-1`.
2798
+ * @example
2799
+ *
2800
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
2801
+ * // => 4
2802
+ *
2803
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
2804
+ * // => 1
2805
+ */
2806
+ function lastIndexOf(array, value, fromIndex) {
2807
+ var index = array ? array.length : 0;
2808
+ if (typeof fromIndex == 'number') {
2809
+ index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
2810
+ }
2811
+ while (index--) {
2812
+ if (array[index] === value) {
2813
+ return index;
2814
+ }
2815
+ }
2816
+ return -1;
2817
+ }
2818
+
2819
+ /**
2820
+ * Creates an object composed from arrays of `keys` and `values`. Pass either
2821
+ * a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or
2822
+ * two arrays, one of `keys` and one of corresponding `values`.
2823
+ *
2824
+ * @static
2825
+ * @memberOf _
2826
+ * @category Arrays
2827
+ * @param {Array} keys The array of keys.
2828
+ * @param {Array} [values=[]] The array of values.
2829
+ * @returns {Object} Returns an object composed of the given keys and
2830
+ * corresponding values.
2831
+ * @example
2832
+ *
2833
+ * _.object(['moe', 'larry', 'curly'], [30, 40, 50]);
2834
+ * // => { 'moe': 30, 'larry': 40, 'curly': 50 }
2835
+ */
2836
+ function object(keys, values) {
2837
+ var index = -1,
2838
+ length = keys ? keys.length : 0,
2839
+ result = {};
2840
+
2841
+ while (++index < length) {
2842
+ var key = keys[index];
2843
+ if (values) {
2844
+ result[key] = values[index];
2845
+ } else {
2846
+ result[key[0]] = key[1];
2847
+ }
2848
+ }
2849
+ return result;
2850
+ }
2851
+
2852
+ /**
2853
+ * Creates an array of numbers (positive and/or negative) progressing from
2854
+ * `start` up to but not including `stop`. This method is a port of Python's
2855
+ * `range()` function. See http://docs.python.org/library/functions.html#range.
2856
+ *
2857
+ * @static
2858
+ * @memberOf _
2859
+ * @category Arrays
2860
+ * @param {Number} [start=0] The start of the range.
2861
+ * @param {Number} end The end of the range.
2862
+ * @param {Number} [step=1] The value to increment or descrement by.
2863
+ * @returns {Array} Returns a new range array.
2864
+ * @example
2865
+ *
2866
+ * _.range(10);
2867
+ * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2868
+ *
2869
+ * _.range(1, 11);
2870
+ * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2871
+ *
2872
+ * _.range(0, 30, 5);
2873
+ * // => [0, 5, 10, 15, 20, 25]
2874
+ *
2875
+ * _.range(0, -10, -1);
2876
+ * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
2877
+ *
2878
+ * _.range(0);
2879
+ * // => []
2880
+ */
2881
+ function range(start, end, step) {
2882
+ start = +start || 0;
2883
+ step = +step || 1;
2884
+
2885
+ if (end == null) {
2886
+ end = start;
2887
+ start = 0;
2888
+ }
2889
+ // use `Array(length)` so V8 will avoid the slower "dictionary" mode
2890
+ // http://www.youtube.com/watch?v=XAqIpGU8ZZk#t=16m27s
2891
+ var index = -1,
2892
+ length = nativeMax(0, ceil((end - start) / step)),
2893
+ result = Array(length);
2894
+
2895
+ while (++index < length) {
2896
+ result[index] = start;
2897
+ start += step;
2898
+ }
2899
+ return result;
2900
+ }
2901
+
2902
+ /**
2903
+ * The opposite of `_.initial`, this method gets all but the first value of
2904
+ * `array`. Pass `n` to exclude the first `n` values from the result.
2905
+ *
2906
+ * @static
2907
+ * @memberOf _
2908
+ * @alias drop, tail
2909
+ * @category Arrays
2910
+ * @param {Array} array The array to query.
2911
+ * @param {Number} [n=1] The number of elements to exclude.
2912
+ * @param- {Object} [guard] Internally used to allow this method to work with
2913
+ * others like `_.map` without using their callback `index` argument for `n`.
2914
+ * @returns {Array} Returns all but the first value or `n` values of `array`.
2915
+ * @example
2916
+ *
2917
+ * _.rest([3, 2, 1]);
2918
+ * // => [2, 1]
2919
+ */
2920
+ function rest(array, n, guard) {
2921
+ return array
2922
+ ? slice.call(array, (n == null || guard) ? 1 : n)
2923
+ : [];
2924
+ }
2925
+
2926
+ /**
2927
+ * Uses a binary search to determine the smallest index at which the `value`
2928
+ * should be inserted into `array` in order to maintain the sort order of the
2929
+ * sorted `array`. If `callback` is passed, it will be executed for `value` and
2930
+ * each element in `array` to compute their sort ranking. The `callback` is
2931
+ * bound to `thisArg` and invoked with one argument; (value). The `callback`
2932
+ * argument may also be the name of a property to order by.
2933
+ *
2934
+ * @static
2935
+ * @memberOf _
2936
+ * @category Arrays
2937
+ * @param {Array} array The array to iterate over.
2938
+ * @param {Mixed} value The value to evaluate.
2939
+ * @param {Function|String} [callback=identity|property] The function called
2940
+ * per iteration or property name to order by.
2941
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
2942
+ * @returns {Number} Returns the index at which the value should be inserted
2943
+ * into `array`.
2944
+ * @example
2945
+ *
2946
+ * _.sortedIndex([20, 30, 50], 40);
2947
+ * // => 2
2948
+ *
2949
+ * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
2950
+ * // => 2
2951
+ *
2952
+ * var dict = {
2953
+ * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
2954
+ * };
2955
+ *
2956
+ * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
2957
+ * return dict.wordToNumber[word];
2958
+ * });
2959
+ * // => 2
2960
+ *
2961
+ * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
2962
+ * return this.wordToNumber[word];
2963
+ * }, dict);
2964
+ * // => 2
2965
+ */
2966
+ function sortedIndex(array, value, callback, thisArg) {
2967
+ var low = 0,
2968
+ high = array ? array.length : low;
2969
+
2970
+ // explicitly reference `identity` for better engine inlining
2971
+ callback = callback ? createCallback(callback, thisArg) : identity;
2972
+ value = callback(value);
2973
+ while (low < high) {
2974
+ var mid = (low + high) >>> 1;
2975
+ callback(array[mid]) < value
2976
+ ? low = mid + 1
2977
+ : high = mid;
2978
+ }
2979
+ return low;
2980
+ }
2981
+
2982
+ /**
2983
+ * Computes the union of the passed-in arrays using strict equality for
2984
+ * comparisons, i.e. `===`.
2985
+ *
2986
+ * @static
2987
+ * @memberOf _
2988
+ * @category Arrays
2989
+ * @param {Array} [array1, array2, ...] Arrays to process.
2990
+ * @returns {Array} Returns a new array of unique values, in order, that are
2991
+ * present in one or more of the arrays.
2992
+ * @example
2993
+ *
2994
+ * _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
2995
+ * // => [1, 2, 3, 101, 10]
2996
+ */
2997
+ function union() {
2998
+ return uniq(concat.apply(arrayRef, arguments));
2999
+ }
3000
+
3001
+ /**
3002
+ * Creates a duplicate-value-free version of the `array` using strict equality
3003
+ * for comparisons, i.e. `===`. If the `array` is already sorted, passing `true`
3004
+ * for `isSorted` will run a faster algorithm. If `callback` is passed, each
3005
+ * element of `array` is passed through a callback` before uniqueness is computed.
3006
+ * The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array).
3007
+ *
3008
+ * @static
3009
+ * @memberOf _
3010
+ * @alias unique
3011
+ * @category Arrays
3012
+ * @param {Array} array The array to process.
3013
+ * @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted.
3014
+ * @param {Function} [callback=identity] The function called per iteration.
3015
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
3016
+ * @returns {Array} Returns a duplicate-value-free array.
3017
+ * @example
3018
+ *
3019
+ * _.uniq([1, 2, 1, 3, 1]);
3020
+ * // => [1, 2, 3]
3021
+ *
3022
+ * _.uniq([1, 1, 2, 2, 3], true);
3023
+ * // => [1, 2, 3]
3024
+ *
3025
+ * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); });
3026
+ * // => [1, 2, 3]
3027
+ *
3028
+ * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math);
3029
+ * // => [1, 2, 3]
3030
+ */
3031
+ function uniq(array, isSorted, callback, thisArg) {
3032
+ var index = -1,
3033
+ length = array ? array.length : 0,
3034
+ result = [],
3035
+ seen = result;
3036
+
3037
+ // juggle arguments
3038
+ if (typeof isSorted == 'function') {
3039
+ thisArg = callback;
3040
+ callback = isSorted;
3041
+ isSorted = false;
3042
+ }
3043
+ // init value cache for large arrays
3044
+ var isLarge = !isSorted && length > 74;
3045
+ if (isLarge) {
3046
+ var cache = {};
3047
+ }
3048
+ if (callback) {
3049
+ seen = [];
3050
+ callback = createCallback(callback, thisArg);
3051
+ }
3052
+ while (++index < length) {
3053
+ var value = array[index],
3054
+ computed = callback ? callback(value, index, array) : value;
3055
+
3056
+ if (isLarge) {
3057
+ // manually coerce `computed` to a string because `hasOwnProperty`, in
3058
+ // some older versions of Firefox, coerces objects incorrectly
3059
+ seen = hasOwnProperty.call(cache, computed + '') ? cache[computed] : (cache[computed] = []);
3060
+ }
3061
+ if (isSorted
3062
+ ? !index || seen[seen.length - 1] !== computed
3063
+ : indexOf(seen, computed) < 0
3064
+ ) {
3065
+ if (callback || isLarge) {
3066
+ seen.push(computed);
3067
+ }
3068
+ result.push(value);
3069
+ }
3070
+ }
3071
+ return result;
3072
+ }
3073
+
3074
+ /**
3075
+ * Creates an array with all occurrences of the passed values removed using
3076
+ * strict equality for comparisons, i.e. `===`.
3077
+ *
3078
+ * @static
3079
+ * @memberOf _
3080
+ * @category Arrays
3081
+ * @param {Array} array The array to filter.
3082
+ * @param {Mixed} [value1, value2, ...] Values to remove.
3083
+ * @returns {Array} Returns a new filtered array.
3084
+ * @example
3085
+ *
3086
+ * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
3087
+ * // => [2, 3, 4]
3088
+ */
3089
+ function without(array) {
3090
+ var index = -1,
3091
+ length = array ? array.length : 0,
3092
+ contains = cachedContains(arguments, 1, 20),
3093
+ result = [];
3094
+
3095
+ while (++index < length) {
3096
+ var value = array[index];
3097
+ if (!contains(value)) {
3098
+ result.push(value);
3099
+ }
3100
+ }
3101
+ return result;
3102
+ }
3103
+
3104
+ /**
3105
+ * Groups the elements of each array at their corresponding indexes. Useful for
3106
+ * separate data sources that are coordinated through matching array indexes.
3107
+ * For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix
3108
+ * in a similar fashion.
3109
+ *
3110
+ * @static
3111
+ * @memberOf _
3112
+ * @category Arrays
3113
+ * @param {Array} [array1, array2, ...] Arrays to process.
3114
+ * @returns {Array} Returns a new array of grouped elements.
3115
+ * @example
3116
+ *
3117
+ * _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
3118
+ * // => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]]
3119
+ */
3120
+ function zip(array) {
3121
+ var index = -1,
3122
+ length = array ? max(pluck(arguments, 'length')) : 0,
3123
+ result = Array(length);
3124
+
3125
+ while (++index < length) {
3126
+ result[index] = pluck(arguments, index);
3127
+ }
3128
+ return result;
3129
+ }
3130
+
3131
+ /*--------------------------------------------------------------------------*/
3132
+
3133
+ /**
3134
+ * Creates a function that is restricted to executing `func` only after it is
3135
+ * called `n` times. The `func` is executed with the `this` binding of the
3136
+ * created function.
3137
+ *
3138
+ * @static
3139
+ * @memberOf _
3140
+ * @category Functions
3141
+ * @param {Number} n The number of times the function must be called before
3142
+ * it is executed.
3143
+ * @param {Function} func The function to restrict.
3144
+ * @returns {Function} Returns the new restricted function.
3145
+ * @example
3146
+ *
3147
+ * var renderNotes = _.after(notes.length, render);
3148
+ * _.forEach(notes, function(note) {
3149
+ * note.asyncSave({ 'success': renderNotes });
3150
+ * });
3151
+ * // `renderNotes` is run once, after all notes have saved
3152
+ */
3153
+ function after(n, func) {
3154
+ if (n < 1) {
3155
+ return func();
3156
+ }
3157
+ return function() {
3158
+ if (--n < 1) {
3159
+ return func.apply(this, arguments);
3160
+ }
3161
+ };
3162
+ }
3163
+
3164
+ /**
3165
+ * Creates a function that, when called, invokes `func` with the `this`
3166
+ * binding of `thisArg` and prepends any additional `bind` arguments to those
3167
+ * passed to the bound function.
3168
+ *
3169
+ * @static
3170
+ * @memberOf _
3171
+ * @category Functions
3172
+ * @param {Function} func The function to bind.
3173
+ * @param {Mixed} [thisArg] The `this` binding of `func`.
3174
+ * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
3175
+ * @returns {Function} Returns the new bound function.
3176
+ * @example
3177
+ *
3178
+ * var func = function(greeting) {
3179
+ * return greeting + ' ' + this.name;
3180
+ * };
3181
+ *
3182
+ * func = _.bind(func, { 'name': 'moe' }, 'hi');
3183
+ * func();
3184
+ * // => 'hi moe'
3185
+ */
3186
+ function bind(func, thisArg) {
3187
+ // use `Function#bind` if it exists and is fast
3188
+ // (in V8 `Function#bind` is slower except when partially applied)
3189
+ return isBindFast || (nativeBind && arguments.length > 2)
3190
+ ? nativeBind.call.apply(nativeBind, arguments)
3191
+ : createBound(func, thisArg, slice.call(arguments, 2));
3192
+ }
3193
+
3194
+ /**
3195
+ * Binds methods on `object` to `object`, overwriting the existing method.
3196
+ * If no method names are provided, all the function properties of `object`
3197
+ * will be bound.
3198
+ *
3199
+ * @static
3200
+ * @memberOf _
3201
+ * @category Functions
3202
+ * @param {Object} object The object to bind and assign the bound methods to.
3203
+ * @param {String} [methodName1, methodName2, ...] Method names on the object to bind.
3204
+ * @returns {Object} Returns `object`.
3205
+ * @example
3206
+ *
3207
+ * var buttonView = {
3208
+ * 'label': 'lodash',
3209
+ * 'onClick': function() { alert('clicked: ' + this.label); }
3210
+ * };
3211
+ *
3212
+ * _.bindAll(buttonView);
3213
+ * jQuery('#lodash_button').on('click', buttonView.onClick);
3214
+ * // => When the button is clicked, `this.label` will have the correct value
3215
+ */
3216
+ function bindAll(object) {
3217
+ var funcs = arguments,
3218
+ index = funcs.length > 1 ? 0 : (funcs = functions(object), -1),
3219
+ length = funcs.length;
3220
+
3221
+ while (++index < length) {
3222
+ var key = funcs[index];
3223
+ object[key] = bind(object[key], object);
3224
+ }
3225
+ return object;
3226
+ }
3227
+
3228
+ /**
3229
+ * Creates a function that is the composition of the passed functions,
3230
+ * where each function consumes the return value of the function that follows.
3231
+ * In math terms, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
3232
+ * Each function is executed with the `this` binding of the composed function.
3233
+ *
3234
+ * @static
3235
+ * @memberOf _
3236
+ * @category Functions
3237
+ * @param {Function} [func1, func2, ...] Functions to compose.
3238
+ * @returns {Function} Returns the new composed function.
3239
+ * @example
3240
+ *
3241
+ * var greet = function(name) { return 'hi: ' + name; };
3242
+ * var exclaim = function(statement) { return statement + '!'; };
3243
+ * var welcome = _.compose(exclaim, greet);
3244
+ * welcome('moe');
3245
+ * // => 'hi: moe!'
3246
+ */
3247
+ function compose() {
3248
+ var funcs = arguments;
3249
+ return function() {
3250
+ var args = arguments,
3251
+ length = funcs.length;
3252
+
3253
+ while (length--) {
3254
+ args = [funcs[length].apply(this, args)];
3255
+ }
3256
+ return args[0];
3257
+ };
3258
+ }
3259
+
3260
+ /**
3261
+ * Creates a function that will delay the execution of `func` until after
3262
+ * `wait` milliseconds have elapsed since the last time it was invoked. Pass
3263
+ * `true` for `immediate` to cause debounce to invoke `func` on the leading,
3264
+ * instead of the trailing, edge of the `wait` timeout. Subsequent calls to
3265
+ * the debounced function will return the result of the last `func` call.
3266
+ *
3267
+ * @static
3268
+ * @memberOf _
3269
+ * @category Functions
3270
+ * @param {Function} func The function to debounce.
3271
+ * @param {Number} wait The number of milliseconds to delay.
3272
+ * @param {Boolean} immediate A flag to indicate execution is on the leading
3273
+ * edge of the timeout.
3274
+ * @returns {Function} Returns the new debounced function.
3275
+ * @example
3276
+ *
3277
+ * var lazyLayout = _.debounce(calculateLayout, 300);
3278
+ * jQuery(window).on('resize', lazyLayout);
3279
+ */
3280
+ function debounce(func, wait, immediate) {
3281
+ var args,
3282
+ result,
3283
+ thisArg,
3284
+ timeoutId;
3285
+
3286
+ function delayed() {
3287
+ timeoutId = null;
3288
+ if (!immediate) {
3289
+ result = func.apply(thisArg, args);
3290
+ }
3291
+ }
3292
+ return function() {
3293
+ var isImmediate = immediate && !timeoutId;
3294
+ args = arguments;
3295
+ thisArg = this;
3296
+
3297
+ clearTimeout(timeoutId);
3298
+ timeoutId = setTimeout(delayed, wait);
3299
+
3300
+ if (isImmediate) {
3301
+ result = func.apply(thisArg, args);
3302
+ }
3303
+ return result;
3304
+ };
3305
+ }
3306
+
3307
+ /**
3308
+ * Executes the `func` function after `wait` milliseconds. Additional arguments
3309
+ * will be passed to `func` when it is invoked.
3310
+ *
3311
+ * @static
3312
+ * @memberOf _
3313
+ * @category Functions
3314
+ * @param {Function} func The function to delay.
3315
+ * @param {Number} wait The number of milliseconds to delay execution.
3316
+ * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with.
3317
+ * @returns {Number} Returns the `setTimeout` timeout id.
3318
+ * @example
3319
+ *
3320
+ * var log = _.bind(console.log, console);
3321
+ * _.delay(log, 1000, 'logged later');
3322
+ * // => 'logged later' (Appears after one second.)
3323
+ */
3324
+ function delay(func, wait) {
3325
+ var args = slice.call(arguments, 2);
3326
+ return setTimeout(function() { func.apply(undefined, args); }, wait);
3327
+ }
3328
+
3329
+ /**
3330
+ * Defers executing the `func` function until the current call stack has cleared.
3331
+ * Additional arguments will be passed to `func` when it is invoked.
3332
+ *
3333
+ * @static
3334
+ * @memberOf _
3335
+ * @category Functions
3336
+ * @param {Function} func The function to defer.
3337
+ * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with.
3338
+ * @returns {Number} Returns the `setTimeout` timeout id.
3339
+ * @example
3340
+ *
3341
+ * _.defer(function() { alert('deferred'); });
3342
+ * // returns from the function before `alert` is called
3343
+ */
3344
+ function defer(func) {
3345
+ var args = slice.call(arguments, 1);
3346
+ return setTimeout(function() { func.apply(undefined, args); }, 1);
3347
+ }
3348
+
3349
+ /**
3350
+ * Creates a function that, when called, invokes `object[methodName]` and
3351
+ * prepends any additional `lateBind` arguments to those passed to the bound
3352
+ * function. This method differs from `_.bind` by allowing bound functions to
3353
+ * reference methods that will be redefined or don't yet exist.
3354
+ *
3355
+ * @static
3356
+ * @memberOf _
3357
+ * @category Functions
3358
+ * @param {Object} object The object the method belongs to.
3359
+ * @param {String} methodName The method name.
3360
+ * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
3361
+ * @returns {Function} Returns the new bound function.
3362
+ * @example
3363
+ *
3364
+ * var object = {
3365
+ * 'name': 'moe',
3366
+ * 'greet': function(greeting) {
3367
+ * return greeting + ' ' + this.name;
3368
+ * }
3369
+ * };
3370
+ *
3371
+ * var func = _.lateBind(object, 'greet', 'hi');
3372
+ * func();
3373
+ * // => 'hi moe'
3374
+ *
3375
+ * object.greet = function(greeting) {
3376
+ * return greeting + ', ' + this.name + '!';
3377
+ * };
3378
+ *
3379
+ * func();
3380
+ * // => 'hi, moe!'
3381
+ */
3382
+ function lateBind(object, methodName) {
3383
+ return createBound(methodName, object, slice.call(arguments, 2));
3384
+ }
3385
+
3386
+ /**
3387
+ * Creates a function that memoizes the result of `func`. If `resolver` is
3388
+ * passed, it will be used to determine the cache key for storing the result
3389
+ * based on the arguments passed to the memoized function. By default, the first
3390
+ * argument passed to the memoized function is used as the cache key. The `func`
3391
+ * is executed with the `this` binding of the memoized function.
3392
+ *
3393
+ * @static
3394
+ * @memberOf _
3395
+ * @category Functions
3396
+ * @param {Function} func The function to have its output memoized.
3397
+ * @param {Function} [resolver] A function used to resolve the cache key.
3398
+ * @returns {Function} Returns the new memoizing function.
3399
+ * @example
3400
+ *
3401
+ * var fibonacci = _.memoize(function(n) {
3402
+ * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
3403
+ * });
3404
+ */
3405
+ function memoize(func, resolver) {
3406
+ var cache = {};
3407
+ return function() {
3408
+ var key = resolver ? resolver.apply(this, arguments) : arguments[0];
3409
+ return hasOwnProperty.call(cache, key)
3410
+ ? cache[key]
3411
+ : (cache[key] = func.apply(this, arguments));
3412
+ };
3413
+ }
3414
+
3415
+ /**
3416
+ * Creates a function that is restricted to execute `func` once. Repeat calls to
3417
+ * the function will return the value of the first call. The `func` is executed
3418
+ * with the `this` binding of the created function.
3419
+ *
3420
+ * @static
3421
+ * @memberOf _
3422
+ * @category Functions
3423
+ * @param {Function} func The function to restrict.
3424
+ * @returns {Function} Returns the new restricted function.
3425
+ * @example
3426
+ *
3427
+ * var initialize = _.once(createApplication);
3428
+ * initialize();
3429
+ * initialize();
3430
+ * // Application is only created once.
3431
+ */
3432
+ function once(func) {
3433
+ var result,
3434
+ ran = false;
3435
+
3436
+ return function() {
3437
+ if (ran) {
3438
+ return result;
3439
+ }
3440
+ ran = true;
3441
+ result = func.apply(this, arguments);
3442
+
3443
+ // clear the `func` variable so the function may be garbage collected
3444
+ func = null;
3445
+ return result;
3446
+ };
3447
+ }
3448
+
3449
+ /**
3450
+ * Creates a function that, when called, invokes `func` with any additional
3451
+ * `partial` arguments prepended to those passed to the new function. This
3452
+ * method is similar to `bind`, except it does **not** alter the `this` binding.
3453
+ *
3454
+ * @static
3455
+ * @memberOf _
3456
+ * @category Functions
3457
+ * @param {Function} func The function to partially apply arguments to.
3458
+ * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
3459
+ * @returns {Function} Returns the new partially applied function.
3460
+ * @example
3461
+ *
3462
+ * var greet = function(greeting, name) { return greeting + ': ' + name; };
3463
+ * var hi = _.partial(greet, 'hi');
3464
+ * hi('moe');
3465
+ * // => 'hi: moe'
3466
+ */
3467
+ function partial(func) {
3468
+ return createBound(func, slice.call(arguments, 1));
3469
+ }
3470
+
3471
+ /**
3472
+ * Creates a function that, when executed, will only call the `func`
3473
+ * function at most once per every `wait` milliseconds. If the throttled
3474
+ * function is invoked more than once during the `wait` timeout, `func` will
3475
+ * also be called on the trailing edge of the timeout. Subsequent calls to the
3476
+ * throttled function will return the result of the last `func` call.
3477
+ *
3478
+ * @static
3479
+ * @memberOf _
3480
+ * @category Functions
3481
+ * @param {Function} func The function to throttle.
3482
+ * @param {Number} wait The number of milliseconds to throttle executions to.
3483
+ * @returns {Function} Returns the new throttled function.
3484
+ * @example
3485
+ *
3486
+ * var throttled = _.throttle(updatePosition, 100);
3487
+ * jQuery(window).on('scroll', throttled);
3488
+ */
3489
+ function throttle(func, wait) {
3490
+ var args,
3491
+ result,
3492
+ thisArg,
3493
+ timeoutId,
3494
+ lastCalled = 0;
3495
+
3496
+ function trailingCall() {
3497
+ lastCalled = new Date;
3498
+ timeoutId = null;
3499
+ result = func.apply(thisArg, args);
3500
+ }
3501
+ return function() {
3502
+ var now = new Date,
3503
+ remaining = wait - (now - lastCalled);
3504
+
3505
+ args = arguments;
3506
+ thisArg = this;
3507
+
3508
+ if (remaining <= 0) {
3509
+ clearTimeout(timeoutId);
3510
+ lastCalled = now;
3511
+ result = func.apply(thisArg, args);
3512
+ }
3513
+ else if (!timeoutId) {
3514
+ timeoutId = setTimeout(trailingCall, remaining);
3515
+ }
3516
+ return result;
3517
+ };
3518
+ }
3519
+
3520
+ /**
3521
+ * Creates a function that passes `value` to the `wrapper` function as its
3522
+ * first argument. Additional arguments passed to the function are appended
3523
+ * to those passed to the `wrapper` function. The `wrapper` is executed with
3524
+ * the `this` binding of the created function.
3525
+ *
3526
+ * @static
3527
+ * @memberOf _
3528
+ * @category Functions
3529
+ * @param {Mixed} value The value to wrap.
3530
+ * @param {Function} wrapper The wrapper function.
3531
+ * @returns {Function} Returns the new function.
3532
+ * @example
3533
+ *
3534
+ * var hello = function(name) { return 'hello ' + name; };
3535
+ * hello = _.wrap(hello, function(func) {
3536
+ * return 'before, ' + func('moe') + ', after';
3537
+ * });
3538
+ * hello();
3539
+ * // => 'before, hello moe, after'
3540
+ */
3541
+ function wrap(value, wrapper) {
3542
+ return function() {
3543
+ var args = [value];
3544
+ push.apply(args, arguments);
3545
+ return wrapper.apply(this, args);
3546
+ };
3547
+ }
3548
+
3549
+ /*--------------------------------------------------------------------------*/
3550
+
3551
+ /**
3552
+ * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
3553
+ * corresponding HTML entities.
3554
+ *
3555
+ * @static
3556
+ * @memberOf _
3557
+ * @category Utilities
3558
+ * @param {String} string The string to escape.
3559
+ * @returns {String} Returns the escaped string.
3560
+ * @example
3561
+ *
3562
+ * _.escape('Moe, Larry & Curly');
3563
+ * // => "Moe, Larry &amp; Curly"
3564
+ */
3565
+ function escape(string) {
3566
+ return string == null ? '' : (string + '').replace(reUnescapedHtml, escapeHtmlChar);
3567
+ }
3568
+
3569
+ /**
3570
+ * This function returns the first argument passed to it.
3571
+ *
3572
+ * Note: It is used throughout Lo-Dash as a default callback.
3573
+ *
3574
+ * @static
3575
+ * @memberOf _
3576
+ * @category Utilities
3577
+ * @param {Mixed} value Any value.
3578
+ * @returns {Mixed} Returns `value`.
3579
+ * @example
3580
+ *
3581
+ * var moe = { 'name': 'moe' };
3582
+ * moe === _.identity(moe);
3583
+ * // => true
3584
+ */
3585
+ function identity(value) {
3586
+ return value;
3587
+ }
3588
+
3589
+ /**
3590
+ * Adds functions properties of `object` to the `lodash` function and chainable
3591
+ * wrapper.
3592
+ *
3593
+ * @static
3594
+ * @memberOf _
3595
+ * @category Utilities
3596
+ * @param {Object} object The object of function properties to add to `lodash`.
3597
+ * @example
3598
+ *
3599
+ * _.mixin({
3600
+ * 'capitalize': function(string) {
3601
+ * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
3602
+ * }
3603
+ * });
3604
+ *
3605
+ * _.capitalize('larry');
3606
+ * // => 'Larry'
3607
+ *
3608
+ * _('curly').capitalize();
3609
+ * // => 'Curly'
3610
+ */
3611
+ function mixin(object) {
3612
+ forEach(functions(object), function(methodName) {
3613
+ var func = lodash[methodName] = object[methodName];
3614
+
3615
+ lodash.prototype[methodName] = function() {
3616
+ var args = [this.__wrapped__];
3617
+ push.apply(args, arguments);
3618
+
3619
+ var result = func.apply(lodash, args);
3620
+ if (this.__chain__) {
3621
+ result = new lodash(result);
3622
+ result.__chain__ = true;
3623
+ }
3624
+ return result;
3625
+ };
3626
+ });
3627
+ }
3628
+
3629
+ /**
3630
+ * Reverts the '_' variable to its previous value and returns a reference to
3631
+ * the `lodash` function.
3632
+ *
3633
+ * @static
3634
+ * @memberOf _
3635
+ * @category Utilities
3636
+ * @returns {Function} Returns the `lodash` function.
3637
+ * @example
3638
+ *
3639
+ * var lodash = _.noConflict();
3640
+ */
3641
+ function noConflict() {
3642
+ window._ = oldDash;
3643
+ return this;
3644
+ }
3645
+
3646
+ /**
3647
+ * Produces a random number between `min` and `max` (inclusive). If only one
3648
+ * argument is passed, a number between `0` and the given number will be returned.
3649
+ *
3650
+ * @static
3651
+ * @memberOf _
3652
+ * @category Utilities
3653
+ * @param {Number} [min=0] The minimum possible value.
3654
+ * @param {Number} [max=1] The maximum possible value.
3655
+ * @returns {Number} Returns a random number.
3656
+ * @example
3657
+ *
3658
+ * _.random(0, 5);
3659
+ * // => a number between 1 and 5
3660
+ *
3661
+ * _.random(5);
3662
+ * // => also a number between 1 and 5
3663
+ */
3664
+ function random(min, max) {
3665
+ if (min == null && max == null) {
3666
+ max = 1;
3667
+ }
3668
+ min = +min || 0;
3669
+ if (max == null) {
3670
+ max = min;
3671
+ min = 0;
3672
+ }
3673
+ return min + floor(nativeRandom() * ((+max || 0) - min + 1));
3674
+ }
3675
+
3676
+ /**
3677
+ * Resolves the value of `property` on `object`. If `property` is a function
3678
+ * it will be invoked and its result returned, else the property value is
3679
+ * returned. If `object` is falsey, then `null` is returned.
3680
+ *
3681
+ * @deprecated
3682
+ * @static
3683
+ * @memberOf _
3684
+ * @category Utilities
3685
+ * @param {Object} object The object to inspect.
3686
+ * @param {String} property The property to get the value of.
3687
+ * @returns {Mixed} Returns the resolved value.
3688
+ * @example
3689
+ *
3690
+ * var object = {
3691
+ * 'cheese': 'crumpets',
3692
+ * 'stuff': function() {
3693
+ * return 'nonsense';
3694
+ * }
3695
+ * };
3696
+ *
3697
+ * _.result(object, 'cheese');
3698
+ * // => 'crumpets'
3699
+ *
3700
+ * _.result(object, 'stuff');
3701
+ * // => 'nonsense'
3702
+ */
3703
+ function result(object, property) {
3704
+ // based on Backbone's private `getValue` function
3705
+ // https://github.com/documentcloud/backbone/blob/0.9.2/backbone.js#L1419-1424
3706
+ var value = object ? object[property] : null;
3707
+ return isFunction(value) ? object[property]() : value;
3708
+ }
3709
+
3710
+ /**
3711
+ * A micro-templating method that handles arbitrary delimiters, preserves
3712
+ * whitespace, and correctly escapes quotes within interpolated code.
3713
+ *
3714
+ * Note: In the development build `_.template` utilizes sourceURLs for easier
3715
+ * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
3716
+ *
3717
+ * Note: Lo-Dash may be used in Chrome extensions by either creating a `lodash csp`
3718
+ * build and avoiding `_.template` use, or loading Lo-Dash in a sandboxed page.
3719
+ * See http://developer.chrome.com/trunk/extensions/sandboxingEval.html
3720
+ *
3721
+ * @static
3722
+ * @memberOf _
3723
+ * @category Utilities
3724
+ * @param {String} text The template text.
3725
+ * @param {Obect} data The data object used to populate the text.
3726
+ * @param {Object} options The options object.
3727
+ * escape - The "escape" delimiter regexp.
3728
+ * evaluate - The "evaluate" delimiter regexp.
3729
+ * interpolate - The "interpolate" delimiter regexp.
3730
+ * sourceURL - The sourceURL of the template's compiled source.
3731
+ * variable - The data object variable name.
3732
+ *
3733
+ * @returns {Function|String} Returns a compiled function when no `data` object
3734
+ * is given, else it returns the interpolated text.
3735
+ * @example
3736
+ *
3737
+ * // using a compiled template
3738
+ * var compiled = _.template('hello <%= name %>');
3739
+ * compiled({ 'name': 'moe' });
3740
+ * // => 'hello moe'
3741
+ *
3742
+ * var list = '<% _.forEach(people, function(name) { %><li><%= name %></li><% }); %>';
3743
+ * _.template(list, { 'people': ['moe', 'larry', 'curly'] });
3744
+ * // => '<li>moe</li><li>larry</li><li>curly</li>'
3745
+ *
3746
+ * // using the "escape" delimiter to escape HTML in data property values
3747
+ * _.template('<b><%- value %></b>', { 'value': '<script>' });
3748
+ * // => '<b>&lt;script&gt;</b>'
3749
+ *
3750
+ * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
3751
+ * _.template('hello ${ name }', { 'name': 'curly' });
3752
+ * // => 'hello curly'
3753
+ *
3754
+ * // using the internal `print` function in "evaluate" delimiters
3755
+ * _.template('<% print("hello " + epithet); %>!', { 'epithet': 'stooge' });
3756
+ * // => 'hello stooge!'
3757
+ *
3758
+ * // using custom template delimiters
3759
+ * _.templateSettings = {
3760
+ * 'interpolate': /{{([\s\S]+?)}}/g
3761
+ * };
3762
+ *
3763
+ * _.template('hello {{ name }}!', { 'name': 'mustache' });
3764
+ * // => 'hello mustache!'
3765
+ *
3766
+ * // using the `sourceURL` option to specify a custom sourceURL for the template
3767
+ * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
3768
+ * compiled(data);
3769
+ * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
3770
+ *
3771
+ * // using the `variable` option to ensure a with-statement isn't used in the compiled template
3772
+ * var compiled = _.template('hello <%= data.name %>!', null, { 'variable': 'data' });
3773
+ * compiled.source;
3774
+ * // => function(data) {
3775
+ * var __t, __p = '', __e = _.escape;
3776
+ * __p += 'hello ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
3777
+ * return __p;
3778
+ * }
3779
+ *
3780
+ * // using the `source` property to inline compiled templates for meaningful
3781
+ * // line numbers in error messages and a stack trace
3782
+ * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
3783
+ * var JST = {\
3784
+ * "main": ' + _.template(mainText).source + '\
3785
+ * };\
3786
+ * ');
3787
+ */
3788
+ function template(text, data, options) {
3789
+ // based on John Resig's `tmpl` implementation
3790
+ // http://ejohn.org/blog/javascript-micro-templating/
3791
+ // and Laura Doktorova's doT.js
3792
+ // https://github.com/olado/doT
3793
+ text || (text = '');
3794
+ options || (options = {});
3795
+
3796
+ var isEvaluating,
3797
+ result,
3798
+ settings = lodash.templateSettings,
3799
+ index = 0,
3800
+ interpolate = options.interpolate || settings.interpolate || reNoMatch,
3801
+ source = "__p += '",
3802
+ variable = options.variable || settings.variable,
3803
+ hasVariable = variable;
3804
+
3805
+ // compile regexp to match each delimiter
3806
+ var reDelimiters = RegExp(
3807
+ (options.escape || settings.escape || reNoMatch).source + '|' +
3808
+ interpolate.source + '|' +
3809
+ (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
3810
+ (options.evaluate || settings.evaluate || reNoMatch).source + '|$'
3811
+ , 'g');
3812
+
3813
+ text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
3814
+ interpolateValue || (interpolateValue = esTemplateValue);
3815
+
3816
+ // escape characters that cannot be included in string literals
3817
+ source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
3818
+
3819
+ // replace delimiters with snippets
3820
+ source +=
3821
+ escapeValue ? "' +\n__e(" + escapeValue + ") +\n'" :
3822
+ evaluateValue ? "';\n" + evaluateValue + ";\n__p += '" :
3823
+ interpolateValue ? "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'" : '';
3824
+
3825
+ isEvaluating || (isEvaluating = evaluateValue || reComplexDelimiter.test(escapeValue || interpolateValue));
3826
+ index = offset + match.length;
3827
+ });
3828
+
3829
+ source += "';\n";
3830
+
3831
+ // if `variable` is not specified and the template contains "evaluate"
3832
+ // delimiters, wrap a with-statement around the generated code to add the
3833
+ // data object to the top of the scope chain
3834
+ if (!hasVariable) {
3835
+ variable = 'obj';
3836
+ if (isEvaluating) {
3837
+ source = 'with (' + variable + ') {\n' + source + '\n}\n';
3838
+ }
3839
+ else {
3840
+ // avoid a with-statement by prepending data object references to property names
3841
+ var reDoubleVariable = RegExp('(\\(\\s*)' + variable + '\\.' + variable + '\\b', 'g');
3842
+ source = source
3843
+ .replace(reInsertVariable, '$&' + variable + '.')
3844
+ .replace(reDoubleVariable, '$1__d');
3845
+ }
3846
+ }
3847
+
3848
+ // cleanup code by stripping empty strings
3849
+ source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
3850
+ .replace(reEmptyStringMiddle, '$1')
3851
+ .replace(reEmptyStringTrailing, '$1;');
3852
+
3853
+ // frame code as the function body
3854
+ source = 'function(' + variable + ') {\n' +
3855
+ (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
3856
+ 'var __t, __p = \'\', __e = _.escape' +
3857
+ (isEvaluating
3858
+ ? ', __j = Array.prototype.join;\n' +
3859
+ 'function print() { __p += __j.call(arguments, \'\') }\n'
3860
+ : (hasVariable ? '' : ', __d = ' + variable + '.' + variable + ' || ' + variable) + ';\n'
3861
+ ) +
3862
+ source +
3863
+ 'return __p\n}';
3864
+
3865
+ // use a sourceURL for easier debugging
3866
+ // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
3867
+ var sourceURL = useSourceURL
3868
+ ? '\n//@ sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']')
3869
+ : '';
3870
+
3871
+ try {
3872
+ result = Function('_', 'return ' + source + sourceURL)(lodash);
3873
+ } catch(e) {
3874
+ e.source = source;
3875
+ throw e;
3876
+ }
3877
+
3878
+ if (data) {
3879
+ return result(data);
3880
+ }
3881
+ // provide the compiled function's source via its `toString` method, in
3882
+ // supported environments, or the `source` property as a convenience for
3883
+ // inlining compiled templates during the build process
3884
+ result.source = source;
3885
+ return result;
3886
+ }
3887
+
3888
+ /**
3889
+ * Executes the `callback` function `n` times, returning an array of the results
3890
+ * of each `callback` execution. The `callback` is bound to `thisArg` and invoked
3891
+ * with one argument; (index).
3892
+ *
3893
+ * @static
3894
+ * @memberOf _
3895
+ * @category Utilities
3896
+ * @param {Number} n The number of times to execute the callback.
3897
+ * @param {Function} callback The function called per iteration.
3898
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
3899
+ * @returns {Array} Returns a new array of the results of each `callback` execution.
3900
+ * @example
3901
+ *
3902
+ * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
3903
+ * // => [3, 6, 4]
3904
+ *
3905
+ * _.times(3, function(n) { mage.castSpell(n); });
3906
+ * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
3907
+ *
3908
+ * _.times(3, function(n) { this.cast(n); }, mage);
3909
+ * // => also calls `mage.castSpell(n)` three times
3910
+ */
3911
+ function times(n, callback, thisArg) {
3912
+ n = +n || 0;
3913
+ var index = -1,
3914
+ result = Array(n);
3915
+
3916
+ while (++index < n) {
3917
+ result[index] = callback.call(thisArg, index);
3918
+ }
3919
+ return result;
3920
+ }
3921
+
3922
+ /**
3923
+ * The opposite of `_.escape`, this method converts the HTML entities
3924
+ * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#x27;` in `string` to their
3925
+ * corresponding characters.
3926
+ *
3927
+ * @static
3928
+ * @memberOf _
3929
+ * @category Utilities
3930
+ * @param {String} string The string to unescape.
3931
+ * @returns {String} Returns the unescaped string.
3932
+ * @example
3933
+ *
3934
+ * _.unescape('Moe, Larry &amp; Curly');
3935
+ * // => "Moe, Larry & Curly"
3936
+ */
3937
+ function unescape(string) {
3938
+ return string == null ? '' : (string + '').replace(reEscapedHtml, unescapeHtmlChar);
3939
+ }
3940
+
3941
+ /**
3942
+ * Generates a unique id. If `prefix` is passed, the id will be appended to it.
3943
+ *
3944
+ * @static
3945
+ * @memberOf _
3946
+ * @category Utilities
3947
+ * @param {String} [prefix] The value to prefix the id with.
3948
+ * @returns {Number|String} Returns a numeric id if no prefix is passed, else
3949
+ * a string id may be returned.
3950
+ * @example
3951
+ *
3952
+ * _.uniqueId('contact_');
3953
+ * // => 'contact_104'
3954
+ */
3955
+ function uniqueId(prefix) {
3956
+ var id = idCounter++;
3957
+ return prefix ? prefix + id : id;
3958
+ }
3959
+
3960
+ /*--------------------------------------------------------------------------*/
3961
+
3962
+ /**
3963
+ * Wraps the value in a `lodash` wrapper object.
3964
+ *
3965
+ * @static
3966
+ * @memberOf _
3967
+ * @category Chaining
3968
+ * @param {Mixed} value The value to wrap.
3969
+ * @returns {Object} Returns the wrapper object.
3970
+ * @example
3971
+ *
3972
+ * var stooges = [
3973
+ * { 'name': 'moe', 'age': 40 },
3974
+ * { 'name': 'larry', 'age': 50 },
3975
+ * { 'name': 'curly', 'age': 60 }
3976
+ * ];
3977
+ *
3978
+ * var youngest = _.chain(stooges)
3979
+ * .sortBy(function(stooge) { return stooge.age; })
3980
+ * .map(function(stooge) { return stooge.name + ' is ' + stooge.age; })
3981
+ * .first()
3982
+ * .value();
3983
+ * // => 'moe is 40'
3984
+ */
3985
+ function chain(value) {
3986
+ value = new lodash(value);
3987
+ value.__chain__ = true;
3988
+ return value;
3989
+ }
3990
+
3991
+ /**
3992
+ * Invokes `interceptor` with the `value` as the first argument, and then
3993
+ * returns `value`. The purpose of this method is to "tap into" a method chain,
3994
+ * in order to perform operations on intermediate results within the chain.
3995
+ *
3996
+ * @static
3997
+ * @memberOf _
3998
+ * @category Chaining
3999
+ * @param {Mixed} value The value to pass to `interceptor`.
4000
+ * @param {Function} interceptor The function to invoke.
4001
+ * @returns {Mixed} Returns `value`.
4002
+ * @example
4003
+ *
4004
+ * _.chain([1, 2, 3, 200])
4005
+ * .filter(function(num) { return num % 2 == 0; })
4006
+ * .tap(alert)
4007
+ * .map(function(num) { return num * num })
4008
+ * .value();
4009
+ * // => // [2, 200] (alerted)
4010
+ * // => [4, 40000]
4011
+ */
4012
+ function tap(value, interceptor) {
4013
+ interceptor(value);
4014
+ return value;
4015
+ }
4016
+
4017
+ /**
4018
+ * Enables method chaining on the wrapper object.
4019
+ *
4020
+ * @name chain
4021
+ * @deprecated
4022
+ * @memberOf _
4023
+ * @category Chaining
4024
+ * @returns {Mixed} Returns the wrapper object.
4025
+ * @example
4026
+ *
4027
+ * _([1, 2, 3]).value();
4028
+ * // => [1, 2, 3]
4029
+ */
4030
+ function wrapperChain() {
4031
+ this.__chain__ = true;
4032
+ return this;
4033
+ }
4034
+
4035
+ /**
4036
+ * Extracts the wrapped value.
4037
+ *
4038
+ * @name value
4039
+ * @memberOf _
4040
+ * @category Chaining
4041
+ * @returns {Mixed} Returns the wrapped value.
4042
+ * @example
4043
+ *
4044
+ * _([1, 2, 3]).value();
4045
+ * // => [1, 2, 3]
4046
+ */
4047
+ function wrapperValue() {
4048
+ return this.__wrapped__;
4049
+ }
4050
+
4051
+ /*--------------------------------------------------------------------------*/
4052
+
4053
+ /**
4054
+ * The semantic version number.
4055
+ *
4056
+ * @static
4057
+ * @memberOf _
4058
+ * @type String
4059
+ */
4060
+ lodash.VERSION = '0.9.2';
4061
+
4062
+ // assign static methods
4063
+ lodash.after = after;
4064
+ lodash.bind = bind;
4065
+ lodash.bindAll = bindAll;
4066
+ lodash.chain = chain;
4067
+ lodash.clone = clone;
4068
+ lodash.compact = compact;
4069
+ lodash.compose = compose;
4070
+ lodash.contains = contains;
4071
+ lodash.countBy = countBy;
4072
+ lodash.debounce = debounce;
4073
+ lodash.defaults = defaults;
4074
+ lodash.defer = defer;
4075
+ lodash.delay = delay;
4076
+ lodash.difference = difference;
4077
+ lodash.escape = escape;
4078
+ lodash.every = every;
4079
+ lodash.extend = extend;
4080
+ lodash.filter = filter;
4081
+ lodash.find = find;
4082
+ lodash.first = first;
4083
+ lodash.flatten = flatten;
4084
+ lodash.forEach = forEach;
4085
+ lodash.forIn = forIn;
4086
+ lodash.forOwn = forOwn;
4087
+ lodash.functions = functions;
4088
+ lodash.groupBy = groupBy;
4089
+ lodash.has = has;
4090
+ lodash.identity = identity;
4091
+ lodash.indexOf = indexOf;
4092
+ lodash.initial = initial;
4093
+ lodash.intersection = intersection;
4094
+ lodash.invert = invert;
4095
+ lodash.invoke = invoke;
4096
+ lodash.isArguments = isArguments;
4097
+ lodash.isArray = isArray;
4098
+ lodash.isBoolean = isBoolean;
4099
+ lodash.isDate = isDate;
4100
+ lodash.isElement = isElement;
4101
+ lodash.isEmpty = isEmpty;
4102
+ lodash.isEqual = isEqual;
4103
+ lodash.isFinite = isFinite;
4104
+ lodash.isFunction = isFunction;
4105
+ lodash.isNaN = isNaN;
4106
+ lodash.isNull = isNull;
4107
+ lodash.isNumber = isNumber;
4108
+ lodash.isObject = isObject;
4109
+ lodash.isPlainObject = isPlainObject;
4110
+ lodash.isRegExp = isRegExp;
4111
+ lodash.isString = isString;
4112
+ lodash.isUndefined = isUndefined;
4113
+ lodash.keys = keys;
4114
+ lodash.last = last;
4115
+ lodash.lastIndexOf = lastIndexOf;
4116
+ lodash.lateBind = lateBind;
4117
+ lodash.map = map;
4118
+ lodash.max = max;
4119
+ lodash.memoize = memoize;
4120
+ lodash.merge = merge;
4121
+ lodash.min = min;
4122
+ lodash.mixin = mixin;
4123
+ lodash.noConflict = noConflict;
4124
+ lodash.object = object;
4125
+ lodash.omit = omit;
4126
+ lodash.once = once;
4127
+ lodash.pairs = pairs;
4128
+ lodash.partial = partial;
4129
+ lodash.pick = pick;
4130
+ lodash.pluck = pluck;
4131
+ lodash.random = random;
4132
+ lodash.range = range;
4133
+ lodash.reduce = reduce;
4134
+ lodash.reduceRight = reduceRight;
4135
+ lodash.reject = reject;
4136
+ lodash.rest = rest;
4137
+ lodash.result = result;
4138
+ lodash.shuffle = shuffle;
4139
+ lodash.size = size;
4140
+ lodash.some = some;
4141
+ lodash.sortBy = sortBy;
4142
+ lodash.sortedIndex = sortedIndex;
4143
+ lodash.tap = tap;
4144
+ lodash.template = template;
4145
+ lodash.throttle = throttle;
4146
+ lodash.times = times;
4147
+ lodash.toArray = toArray;
4148
+ lodash.unescape = unescape;
4149
+ lodash.union = union;
4150
+ lodash.uniq = uniq;
4151
+ lodash.uniqueId = uniqueId;
4152
+ lodash.values = values;
4153
+ lodash.where = where;
4154
+ lodash.without = without;
4155
+ lodash.wrap = wrap;
4156
+ lodash.zip = zip;
4157
+
4158
+ // assign aliases
4159
+ lodash.all = every;
4160
+ lodash.any = some;
4161
+ lodash.collect = map;
4162
+ lodash.detect = find;
4163
+ lodash.drop = rest;
4164
+ lodash.each = forEach;
4165
+ lodash.foldl = reduce;
4166
+ lodash.foldr = reduceRight;
4167
+ lodash.head = first;
4168
+ lodash.include = contains;
4169
+ lodash.inject = reduce;
4170
+ lodash.methods = functions;
4171
+ lodash.select = filter;
4172
+ lodash.tail = rest;
4173
+ lodash.take = first;
4174
+ lodash.unique = uniq;
4175
+
4176
+ // add pseudo private property to be used and removed during the build process
4177
+ lodash._iteratorTemplate = iteratorTemplate;
4178
+
4179
+ /*--------------------------------------------------------------------------*/
4180
+
4181
+ // add all static functions to `lodash.prototype`
4182
+ mixin(lodash);
4183
+
4184
+ // add `lodash.prototype.chain` after calling `mixin()` to avoid overwriting
4185
+ // it with the wrapped `lodash.chain`
4186
+ lodash.prototype.chain = wrapperChain;
4187
+ lodash.prototype.value = wrapperValue;
4188
+
4189
+ // add all mutator Array functions to the wrapper.
4190
+ forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
4191
+ var func = arrayRef[methodName];
4192
+
4193
+ lodash.prototype[methodName] = function() {
4194
+ var value = this.__wrapped__;
4195
+ func.apply(value, arguments);
4196
+
4197
+ // avoid array-like object bugs with `Array#shift` and `Array#splice` in
4198
+ // Firefox < 10 and IE < 9
4199
+ if (hasObjectSpliceBug && value.length === 0) {
4200
+ delete value[0];
4201
+ }
4202
+ if (this.__chain__) {
4203
+ value = new lodash(value);
4204
+ value.__chain__ = true;
4205
+ }
4206
+ return value;
4207
+ };
4208
+ });
4209
+
4210
+ // add all accessor Array functions to the wrapper.
4211
+ forEach(['concat', 'join', 'slice'], function(methodName) {
4212
+ var func = arrayRef[methodName];
4213
+
4214
+ lodash.prototype[methodName] = function() {
4215
+ var value = this.__wrapped__,
4216
+ result = func.apply(value, arguments);
4217
+
4218
+ if (this.__chain__) {
4219
+ result = new lodash(result);
4220
+ result.__chain__ = true;
4221
+ }
4222
+ return result;
4223
+ };
4224
+ });
4225
+
4226
+ /*--------------------------------------------------------------------------*/
4227
+
4228
+ // expose Lo-Dash
4229
+ // some AMD build optimizers, like r.js, check for specific condition patterns like the following:
4230
+ if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
4231
+ // Expose Lo-Dash to the global object even when an AMD loader is present in
4232
+ // case Lo-Dash was injected by a third-party script and not intended to be
4233
+ // loaded as a module. The global assignment can be reverted in the Lo-Dash
4234
+ // module via its `noConflict()` method.
4235
+ window._ = lodash;
4236
+
4237
+ // define as an anonymous module so, through path mapping, it can be
4238
+ // referenced as the "underscore" module
4239
+ define(function() {
4240
+ return lodash;
4241
+ });
4242
+ }
4243
+ // check for `exports` after `define` in case a build optimizer adds an `exports` object
4244
+ else if (freeExports) {
4245
+ // in Node.js or RingoJS v0.8.0+
4246
+ if (typeof module == 'object' && module && module.exports == freeExports) {
4247
+ (module.exports = lodash)._ = lodash;
4248
+ }
4249
+ // in Narwhal or RingoJS v0.7.0-
4250
+ else {
4251
+ freeExports._ = lodash;
4252
+ }
4253
+ }
4254
+ else {
4255
+ // in a browser or Rhino
4256
+ window._ = lodash;
4257
+ }
4258
+ }(this));