character 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -1
  3. data/.rspec +1 -0
  4. data/README.md +185 -14
  5. data/Rakefile +8 -1
  6. data/app/assets/images/character/logo.jpg +0 -0
  7. data/app/assets/javascripts/character.coffee +134 -0
  8. data/app/assets/javascripts/character/dashboard/_visitors.coffee +27 -0
  9. data/app/assets/javascripts/character/dashboard/layout.coffee +156 -0
  10. data/app/assets/javascripts/character/dashboard/module.coffee +51 -0
  11. data/app/assets/javascripts/character/generic/details.coffee +233 -0
  12. data/app/assets/javascripts/character/generic/helpers/compact_object.coffee +7 -0
  13. data/app/assets/javascripts/character/generic/helpers/data_inputs.coffee +21 -0
  14. data/app/assets/javascripts/character/generic/helpers/date_select.coffee +45 -0
  15. data/app/assets/javascripts/character/generic/helpers/editor.coffee +11 -0
  16. data/app/assets/javascripts/character/generic/helpers/redactor.coffee +38 -0
  17. data/app/assets/javascripts/character/generic/helpers/reorder.coffee +36 -0
  18. data/app/assets/javascripts/character/generic/layout.coffee +40 -0
  19. data/app/assets/javascripts/character/generic/list.coffee +214 -0
  20. data/app/assets/javascripts/character/generic/model.coffee +135 -0
  21. data/app/assets/javascripts/character/generic/module.coffee +157 -0
  22. data/app/assets/javascripts/character/images/module.coffee +148 -0
  23. data/app/assets/javascripts/character/pages/module.coffee +43 -0
  24. data/app/assets/javascripts/character/posts/module.coffee +113 -0
  25. data/app/assets/javascripts/character/settings/_admins.coffee +61 -0
  26. data/app/assets/javascripts/character/settings/_authors.coffee +56 -0
  27. data/app/assets/javascripts/character/settings/_categories.coffee +61 -0
  28. data/app/assets/javascripts/character/settings/_layout.coffee +7 -0
  29. data/app/assets/javascripts/character/settings/_redirects.coffee +56 -0
  30. data/app/assets/javascripts/character/settings/_website.coffee +7 -0
  31. data/app/assets/javascripts/character/settings/details.coffee +16 -0
  32. data/app/assets/javascripts/character/settings/layout.coffee +46 -0
  33. data/app/assets/javascripts/character/settings/module.coffee +78 -0
  34. data/app/assets/stylesheets/character.scss +37 -0
  35. data/app/assets/stylesheets/character/_admins.scss +30 -0
  36. data/app/assets/stylesheets/character/_authors.scss +30 -0
  37. data/app/assets/stylesheets/character/_categories.scss +32 -0
  38. data/app/assets/stylesheets/character/_dashboard.scss +143 -0
  39. data/app/assets/stylesheets/character/_posts.scss +93 -0
  40. data/app/assets/stylesheets/character/_redirects.scss +35 -0
  41. data/app/assets/stylesheets/character/base.scss +967 -0
  42. data/app/assets/stylesheets/character/typography.scss +29 -0
  43. data/app/controllers/character/api_controller.rb +170 -0
  44. data/app/controllers/character/application_controller.rb +37 -0
  45. data/app/controllers/character/settings_controller.rb +72 -0
  46. data/app/controllers/concerns/character/auth_concern.rb +41 -0
  47. data/app/controllers/concerns/character/instance_concern.rb +31 -0
  48. data/app/controllers/concerns/character/json_object_concern.rb +32 -0
  49. data/app/controllers/concerns/character/model_class_concern.rb +28 -0
  50. data/app/controllers/concerns/character/params_concern.rb +33 -0
  51. data/app/controllers/concerns/character/templates_concern.rb +32 -0
  52. data/app/controllers/concerns/not_found.rb +18 -0
  53. data/app/controllers/concerns/website_settings.rb +18 -0
  54. data/app/controllers/pages_controller.rb +8 -0
  55. data/app/controllers/posts_controller.rb +43 -0
  56. data/app/helpers/character_helper.rb +8 -0
  57. data/app/helpers/page_helper.rb +67 -0
  58. data/app/inputs/foundation_string_input.rb +44 -0
  59. data/app/inputs/foundation_switch_input.rb +35 -0
  60. data/app/models/character/image.rb +12 -0
  61. data/app/models/character/page.rb +21 -0
  62. data/app/models/character/post.rb +32 -12
  63. data/app/models/character/post_author.rb +22 -0
  64. data/app/models/character/post_category.rb +21 -0
  65. data/app/models/character/redirect.rb +15 -0
  66. data/app/models/character/settings/variable.rb +23 -0
  67. data/app/models/character/sitemap/sitemap_generator_helper.rb +15 -0
  68. data/app/models/character/user.rb +29 -0
  69. data/app/models/concerns/created_ago.rb +12 -0
  70. data/app/models/concerns/hideable.rb +27 -0
  71. data/app/models/concerns/orderable.rb +8 -0
  72. data/app/models/concerns/report.rb +11 -0
  73. data/app/models/concerns/report_daily.rb +32 -0
  74. data/app/models/concerns/report_monthly.rb +18 -0
  75. data/app/models/concerns/report_weekly.rb +19 -0
  76. data/app/models/concerns/updated_ago.rb +12 -0
  77. data/app/models/reports/analytics_daily.rb +26 -0
  78. data/app/models/reports/analytics_monthly.rb +16 -0
  79. data/app/models/reports/analytics_weekly.rb +16 -0
  80. data/app/services/google_analytics.rb +43 -0
  81. data/app/uploaders/character/image_uploader.rb +22 -0
  82. data/app/uploaders/character/settings/file_uploader.rb +5 -0
  83. data/app/views/character/character.html.erb +67 -0
  84. data/app/views/character/generic/form.html.erb +8 -0
  85. data/app/views/character/pages/form.html.erb +28 -0
  86. data/app/views/character/posts/form.html.erb +38 -0
  87. data/app/views/character/settings/admins.html.erb +29 -0
  88. data/app/views/character/settings/post_authors.html.erb +28 -0
  89. data/app/views/character/settings/post_categories.html.erb +31 -0
  90. data/app/views/character/settings/redirects.html.erb +30 -0
  91. data/app/views/character/settings/settings_group.html.erb +67 -0
  92. data/app/views/errors/not_found.html.erb +157 -0
  93. data/app/views/pages/_default.html.erb +3 -0
  94. data/app/views/pages/_redactor.html.erb +3 -0
  95. data/app/views/pages/show.html.erb +5 -0
  96. data/app/views/posts/_post.html.erb +17 -0
  97. data/app/views/posts/author.html.erb +18 -0
  98. data/app/views/posts/category.html.erb +18 -0
  99. data/app/views/posts/index.html.erb +18 -0
  100. data/app/views/posts/rss.builder +19 -0
  101. data/app/views/posts/show.html.erb +14 -0
  102. data/app/views/shared/_google_analytics.html.erb +13 -0
  103. data/character.gemspec +48 -5
  104. data/doc/README_old.md +161 -0
  105. data/doc/generic_app.md +19 -0
  106. data/doc/img/demo-1.jpg +0 -0
  107. data/doc/img/demo-2.jpg +0 -0
  108. data/doc/img/demo-3.jpg +0 -0
  109. data/doc/img/demo-4.jpg +0 -0
  110. data/doc/img/demo-5.jpg +0 -0
  111. data/doc/instances.md +39 -0
  112. data/doc/settings.md +1 -0
  113. data/lib/character.rb +29 -1
  114. data/lib/character/engine.rb +33 -1
  115. data/lib/character/generators/bootstrap_generator.rb +51 -0
  116. data/lib/character/instance.rb +59 -0
  117. data/lib/character/routing.rb +42 -5
  118. data/lib/character/settings.rb +101 -0
  119. data/lib/character/templates/admin.coffee +15 -0
  120. data/lib/character/templates/admin.scss +3 -0
  121. data/lib/character/templates/application.html.erb +44 -0
  122. data/lib/character/templates/application.scss +12 -0
  123. data/lib/character/templates/assets.rb +1 -0
  124. data/lib/character/templates/initializer.rb +5 -0
  125. data/lib/character/templates/settings.scss +11 -0
  126. data/lib/character/templates/settings.yml +67 -0
  127. data/lib/character/templates/typography.scss +13 -0
  128. data/lib/character/version.rb +2 -2
  129. data/lib/mongoid/carrierwave_serialization_patch.rb +9 -0
  130. data/lib/tasks/analytics.rake +52 -0
  131. data/test/config/application.rb +65 -0
  132. data/test/config/mongoid.yml +12 -0
  133. data/test/config/secrets.yml +22 -0
  134. data/test/controllers/character/api_controller_test.rb +94 -0
  135. data/test/factories/product_factory.rb +5 -0
  136. data/test/lib/character/engine_test.rb +33 -0
  137. data/test/lib/character/routing_test.rb +31 -0
  138. data/test/test_helper.rb +48 -0
  139. data/vendor/assets/javascripts/backbone.js +944 -794
  140. data/vendor/assets/javascripts/jquery.fileupload.js +1426 -0
  141. data/vendor/assets/javascripts/jquery.form.js +1278 -0
  142. data/vendor/assets/javascripts/jquery.iframe-transport.js +214 -0
  143. data/vendor/assets/javascripts/raphael.js +8117 -0
  144. data/vendor/assets/javascripts/raphael.morris.js +1885 -0
  145. data/vendor/assets/javascripts/underscore.inflection.js +177 -0
  146. data/vendor/assets/javascripts/underscore.string.js +1 -1
  147. data/vendor/assets/stylesheets/csspinner.css +361 -0
  148. data/vendor/assets/stylesheets/normalize.css +423 -0
  149. metadata +499 -49
  150. data/app/controllers/character/posts_controller.rb +0 -27
  151. data/lib/generators/character/install_generator.rb +0 -42
  152. data/lib/generators/character/templates/README +0 -1
  153. data/lib/generators/character/templates/admin/character.rb +0 -3
  154. data/vendor/assets/fonts/general_foundicons.eot +0 -0
  155. data/vendor/assets/fonts/general_foundicons.svg +0 -15
  156. data/vendor/assets/fonts/general_foundicons.ttf +0 -0
  157. data/vendor/assets/fonts/general_foundicons.woff +0 -0
  158. data/vendor/assets/javascripts/character/index.js.coffee +0 -53
  159. data/vendor/assets/javascripts/character/models/post.js.coffee +0 -39
  160. data/vendor/assets/javascripts/character/views/app.js.coffee +0 -81
  161. data/vendor/assets/javascripts/character/views/editor.js.coffee +0 -231
  162. data/vendor/assets/javascripts/character/views/editor_settings.js.coffee +0 -44
  163. data/vendor/assets/javascripts/character/views/index.js.coffee +0 -116
  164. data/vendor/assets/javascripts/character/views/preview.js.coffee +0 -49
  165. data/vendor/assets/javascripts/jquery.smartresize.js +0 -30
  166. data/vendor/assets/javascripts/lodash.js +0 -4258
  167. data/vendor/assets/javascripts/showdown.js +0 -62
  168. data/vendor/assets/stylesheets/character/_base.css.scss +0 -84
  169. data/vendor/assets/stylesheets/character/_icons.css.scss.erb +0 -96
  170. data/vendor/assets/stylesheets/character/_view_editor.css.scss +0 -115
  171. data/vendor/assets/stylesheets/character/_view_index.css.scss +0 -73
  172. data/vendor/assets/stylesheets/character/_view_preview.css.scss +0 -49
  173. data/vendor/assets/stylesheets/character/index.css.scss +0 -32
@@ -1,44 +0,0 @@
1
-
2
- class EditorSettingsView extends Backbone.View
3
- tagName: 'div'
4
- className: 'settings'
5
- id: 'settings'
6
-
7
-
8
- initialize: ->
9
- html = @render().el
10
- $('footer').append(html)
11
-
12
- @settings_btn = document.getElementById('settings_btn')
13
-
14
- @shown = false
15
-
16
-
17
- render: ->
18
- date = @model?.get('date')
19
- html = """<div class='settings-box'>
20
- Date: <input id='date' type='date' value='#{date}'>
21
- </div>
22
- <button class='foundicon-settings' id='settings_btn'></button>"""
23
- $(this.el).html html
24
- return this
25
-
26
-
27
- date: ->
28
- $('#date').val()
29
-
30
-
31
- show_or_hide_settings_box: ->
32
- if @shown
33
- $(@el).removeClass('shown')
34
- @shown = false
35
- else
36
- @shown = true
37
- $(@el).addClass('shown')
38
-
39
-
40
- events:
41
- 'click #settings_btn': 'show_or_hide_settings_box'
42
-
43
-
44
- window.EditorSettingsView = EditorSettingsView
@@ -1,116 +0,0 @@
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
-
@@ -1,49 +0,0 @@
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
@@ -1,30 +0,0 @@
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');
@@ -1,4258 +0,0 @@
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));