yellow-brick-road 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. data/README.rst +42 -20
  2. data/lib/generators/templates/yellow_brick_road.rb.erb +19 -0
  3. data/lib/generators/yellow_brick_road/install_generator.rb +14 -0
  4. data/lib/yellow-brick-road/config.rb +41 -8
  5. data/lib/yellow-brick-road/directive_processor.rb +6 -5
  6. data/lib/yellow-brick-road/engine.rb +2 -3
  7. data/lib/yellow-brick-road/soy_processor.rb +1 -1
  8. data/lib/yellow-brick-road/version.rb +1 -1
  9. data/test/dummy/app/assets/javascripts/closure-deps.js +1 -1
  10. data/test/dummy/config/initializers/yellow_brick_road.rb +18 -1
  11. data/test/dummy/log/development.log +2208 -0
  12. data/test/dummy/tmp/cache/assets/C33/E00/sprockets%2F50c54266987e056bca666f8951752841 +2556 -0
  13. data/test/dummy/tmp/cache/assets/C48/990/sprockets%2F182c7921a46c3b8603c7f5595a111407 +823 -0
  14. data/test/dummy/tmp/cache/assets/C53/B40/sprockets%2F48cf0c035092dc945559526a279061c6 +204 -0
  15. data/test/dummy/tmp/cache/assets/C60/DB0/sprockets%2F3f00684578f2a3246581db667309ed89 +187 -0
  16. data/test/dummy/tmp/cache/assets/C60/E40/sprockets%2F3c5422f721521f492a5f02ca00b70009 +457 -0
  17. data/test/dummy/tmp/cache/assets/C73/DE0/sprockets%2F21f1f4574326846114a3c106873cebc3 +0 -0
  18. data/test/dummy/tmp/cache/assets/C7E/9F0/sprockets%2F89862076204c62c4593ac20de32da909 +4 -4
  19. data/test/dummy/tmp/cache/assets/C80/6F0/sprockets%2F56459a0713f8610d7d261f8be93073a2 +115 -0
  20. data/test/dummy/tmp/cache/assets/C8D/E10/sprockets%2F34b84bc4732937f885707002eda3896e +511 -0
  21. data/test/dummy/tmp/cache/assets/C93/CB0/sprockets%2F539b403b24833ca478a6f5877f37687c +239 -0
  22. data/test/dummy/tmp/cache/assets/C9A/C70/sprockets%2F10933dc6d342f604514713510b9ef0ab +806 -0
  23. data/test/dummy/tmp/cache/assets/CA0/7C0/sprockets%2Ff591bc0af8f085501241305c04907d3e +590 -0
  24. data/test/dummy/tmp/cache/assets/CA1/4A0/sprockets%2F5a9ad311e7d225b530b597041714b1e9 +2539 -0
  25. data/test/dummy/tmp/cache/assets/CA7/310/sprockets%2F45664cf816315200b574e029fde6f10a +0 -0
  26. data/test/dummy/tmp/cache/assets/CA7/A80/sprockets%2F1f32590957635a5a4f35442bc22f4ca4 +0 -0
  27. data/test/dummy/tmp/cache/assets/CAE/1D0/sprockets%2F2e62c7733d38a817a1532a744c6287bd +72 -0
  28. data/test/dummy/tmp/cache/assets/CB2/3C0/sprockets%2F9c35c290501a896b82c31448a39f3d5d +142 -0
  29. data/test/dummy/tmp/cache/assets/CB3/F20/sprockets%2F558b00e493fb501f7d95761e7eb40273 +2539 -0
  30. data/test/dummy/tmp/cache/assets/CBE/550/sprockets%2Fd680cac830e0b3408ba910f0b0421147 +2 -2
  31. data/test/dummy/tmp/cache/assets/CCD/480/sprockets%2Ffe7e11511634a2d03e1a20980b4593cf +0 -0
  32. data/test/dummy/tmp/cache/assets/CD0/080/sprockets%2Ffd5cbb87741244521d013d11c55573fa +204 -0
  33. data/test/dummy/tmp/cache/assets/CD2/020/sprockets%2Ff97740ba22118a2c91e992aac041843b +811 -0
  34. data/test/dummy/tmp/cache/assets/CD8/D90/sprockets%2F55dd841661d646f0024261a08ecf8ec0 +823 -0
  35. data/test/dummy/tmp/cache/assets/CE3/0D0/sprockets%2F301f97a178fd839a81bd663a6e22b616 +811 -0
  36. data/test/dummy/tmp/cache/assets/CE4/330/sprockets%2Fbd23466639af99164ab8e1c93721f14b +127 -0
  37. data/test/dummy/tmp/cache/assets/CE6/8A0/sprockets%2F3c0e7c5fa31563c8e820d6771e09918d +103 -0
  38. data/test/dummy/tmp/cache/assets/CEB/120/sprockets%2F857a0dde6829f7a27b93a840e1c60469 +522 -0
  39. data/test/dummy/tmp/cache/assets/CEE/CF0/sprockets%2F376f94b987d8156056c4e1d38ec06bf0 +0 -0
  40. data/test/dummy/tmp/cache/assets/CF2/C10/sprockets%2Fc64ef8a9dd0a1c3101d662750105c11a +806 -0
  41. data/test/dummy/tmp/cache/assets/CF3/CD0/sprockets%2F4bb42a5a6b504190f10d20b1c5f93d54 +1529 -0
  42. data/test/dummy/tmp/cache/assets/CF6/890/sprockets%2F36007a87f140155b5a04f2ca6b262dcc +494 -0
  43. data/test/dummy/tmp/cache/assets/CF6/9D0/sprockets%2F34b7199e9d33994c8ec7a442d60ca985 +173 -0
  44. data/test/dummy/tmp/cache/assets/CFA/A90/sprockets%2F901ba405a6d6747f6412ed4d0e0ac620 +256 -0
  45. data/test/dummy/tmp/cache/assets/CFC/E70/sprockets%2F8ee639668b5f0e629fbe0d62d1394689 +173 -0
  46. data/test/dummy/tmp/cache/assets/D04/1B0/sprockets%2F418f2b3b6b08b320f6db268a0991c54c +0 -0
  47. data/test/dummy/tmp/cache/assets/D05/920/sprockets%2F909507434dcc270db4853e4c147f0aac +5 -4
  48. data/test/dummy/tmp/cache/assets/D07/DB0/sprockets%2F0c17d7dac64290e385c91eb6f1570b31 +511 -0
  49. data/test/dummy/tmp/cache/assets/D07/EE0/sprockets%2F4999982b09e0b786894fce44f5d783cc +1371 -0
  50. data/test/dummy/tmp/cache/assets/D09/380/sprockets%2F14383e18fa2faac6b561a29d8e132863 +0 -0
  51. data/test/dummy/tmp/cache/assets/D0D/200/sprockets%2F545a7e34cce1d4272d83d58fd4215d42 +1277 -0
  52. data/test/dummy/tmp/cache/assets/D0E/870/sprockets%2F84996444f4f1f3fdc0248131cfb1a3b6 +794 -0
  53. data/test/dummy/tmp/cache/assets/D15/F60/sprockets%2Fa28394e3f80365b5bc86794dd46daa22 +0 -0
  54. data/test/dummy/tmp/cache/assets/D18/950/sprockets%2Fcf650d67c5d431ffdb38552e562299b2 +474 -0
  55. data/test/dummy/tmp/cache/assets/D18/E10/sprockets%2Fec7c58f640556b401fcd66528352dc9d +474 -0
  56. data/test/dummy/tmp/cache/assets/D20/660/sprockets%2F0d2875475ced01df962f3d758cda7792 +103 -0
  57. data/test/dummy/tmp/cache/assets/D22/AB0/sprockets%2F0b08e7f81651aaf739a93d61ae99779c +283 -0
  58. data/test/dummy/tmp/cache/assets/D2E/B20/sprockets%2Feed5412a17a52b1a335925e2af1f75d3 +0 -0
  59. data/test/dummy/tmp/cache/assets/D36/700/sprockets%2Fd219bf9db2eacc105bb294755093a437 +505 -0
  60. data/test/dummy/tmp/cache/assets/D3B/A10/sprockets%2Fcf38b51682d84a04da7b8a7313de52c6 +207 -0
  61. data/test/dummy/tmp/cache/assets/D3C/0E0/sprockets%2Fe9d7aba138d602c4a6ac701bc9615977 +505 -0
  62. data/test/dummy/tmp/cache/assets/D3E/FF0/sprockets%2F6bd8ccd3e02f397c20f349d5c0960e51 +0 -0
  63. data/test/dummy/tmp/cache/assets/D41/B30/sprockets%2Fba1b93913dd01d83ac9a96df334456f8 +0 -0
  64. data/test/dummy/tmp/cache/assets/D41/DA0/sprockets%2Fe8d00810698a9fcee032022fefd084f7 +0 -0
  65. data/test/dummy/tmp/cache/assets/D44/CF0/sprockets%2Ffa31a45f04884493c909c5a67fcbdf23 +1371 -0
  66. data/test/dummy/tmp/cache/assets/D47/BE0/sprockets%2F0b5ebdf6dec160a264698e7f745061e8 +142 -0
  67. data/test/dummy/tmp/cache/assets/D4C/F30/sprockets%2Ff90155c10f59a3fe44959ac09bf817fe +2556 -0
  68. data/test/dummy/tmp/cache/assets/D4E/7C0/sprockets%2Ff01b58512d01eda23fd5cb23a2b28b60 +1529 -0
  69. data/test/dummy/tmp/cache/assets/D4E/860/sprockets%2F86eed0c77c47d0970345bbabb58d8939 +1277 -0
  70. data/test/dummy/tmp/cache/assets/D4E/C30/sprockets%2F52420c10c73ca310d026565eafdadb4e +1545 -0
  71. data/test/dummy/tmp/cache/assets/D4E/F60/sprockets%2F9893a3c5aeb1a9e77469f4751b4d3c3f +115 -0
  72. data/test/dummy/tmp/cache/assets/D4F/E60/sprockets%2F17ee65de1f78c3dd5c165a9867e810b6 +165 -0
  73. data/test/dummy/tmp/cache/assets/D57/0D0/sprockets%2Fa29e6e8106d9d5ed1e2889126cfbf877 +300 -0
  74. data/test/dummy/tmp/cache/assets/D5C/650/sprockets%2Fe1c381da3cc213a639e956ae3315a2bd +607 -0
  75. data/test/dummy/tmp/cache/assets/D61/860/sprockets%2Fbf032a3b4aad2c2e25704e65c966cf45 +794 -0
  76. data/test/dummy/tmp/cache/assets/D63/B20/sprockets%2F31fc70ce66bb80fb9421be34eb3b0287 +0 -0
  77. data/test/dummy/tmp/cache/assets/D64/D60/sprockets%2Fa544ea03bf0a45948a053ba76ec2a79f +239 -0
  78. data/test/dummy/tmp/cache/assets/D6B/F90/sprockets%2F66636712ecb1fcc777dccf7643a0e1b1 +127 -0
  79. data/test/dummy/tmp/cache/assets/D6E/AD0/sprockets%2Fc91cdc6a72c729d7a64119198b3d2eab +0 -0
  80. data/test/dummy/tmp/cache/assets/D6F/140/sprockets%2F9ddc51f4388dd5243a28dba1ce47572b +53 -0
  81. data/test/dummy/tmp/cache/assets/D72/800/sprockets%2F92baa375d54e16fe0a5c7f079a1ce992 +165 -0
  82. data/test/dummy/tmp/cache/assets/D74/220/sprockets%2F3f888bda53179cb945eab35fbd31a708 +53 -0
  83. data/test/dummy/tmp/cache/assets/D78/5F0/sprockets%2F638ed6af667d4fc5147f72ff34aa2d33 +0 -0
  84. data/test/dummy/tmp/cache/assets/D7D/640/sprockets%2F95a7c5580f957c31e1ab9d0773ed5fde +607 -0
  85. data/test/dummy/tmp/cache/assets/D84/210/sprockets%2Fabd0103ccec2b428ac62c94e4c40b384 +6 -5
  86. data/test/dummy/tmp/cache/assets/D89/020/sprockets%2Fa06df6166e70324e712e54b1cafca0ae +187 -0
  87. data/test/dummy/tmp/cache/assets/D8A/9F0/sprockets%2Fc06547ca33ee3d03be14ce045ae1c9e2 +207 -0
  88. data/test/dummy/tmp/cache/assets/D9E/B80/sprockets%2F9561df1d45c7ff4aa8ac3e2df0c99121 +0 -0
  89. data/test/dummy/tmp/cache/assets/DA3/F30/sprockets%2Fe015d6ccdfcf022e47c83d7906f728ae +457 -0
  90. data/test/dummy/tmp/cache/assets/DAE/190/sprockets%2F433c7b21968be8d1f9bfdbdf7a637c57 +0 -0
  91. data/test/dummy/tmp/cache/assets/DB3/600/sprockets%2F9b70ae73f15ba693886eeef4eb5d6c75 +0 -0
  92. data/test/dummy/tmp/cache/assets/DB4/510/sprockets%2F29cdae8e29c88fd9ddbd4831419560fe +1260 -0
  93. data/test/dummy/tmp/cache/assets/DC1/4A0/sprockets%2F0b63dfcf163f2faeb612724eb4545bcc +1354 -0
  94. data/test/dummy/tmp/cache/assets/DC4/C10/sprockets%2Fcf48f4cbad3db33146eab4c577c1d209 +300 -0
  95. data/test/dummy/tmp/cache/assets/DC4/CA0/sprockets%2Fd0da8a60ea4dc16b9fd3e2a50d88633c +0 -0
  96. data/test/dummy/tmp/cache/assets/DC7/8C0/sprockets%2F1ad68dcc9ef598d3811ba2ac5c0ea182 +1354 -0
  97. data/test/dummy/tmp/cache/assets/DC7/C00/sprockets%2Fba755ff3a81c3192f0e45a4f7c0c7dcb +0 -0
  98. data/test/dummy/tmp/cache/assets/DCA/760/sprockets%2F717c4cea10bf601090ffdfe4e668e4cb +283 -0
  99. data/test/dummy/tmp/cache/assets/DCA/DE0/sprockets%2F51dcced9ec2b3cd4b1cc2949f860c361 +590 -0
  100. data/test/dummy/tmp/cache/assets/DD7/E70/sprockets%2F2595d8c8d1d5f4deb096247fb3bfc7ab +256 -0
  101. data/test/dummy/tmp/cache/assets/DE1/9D0/sprockets%2F8befd77af580ee16ec42ec95b1766ff3 +1545 -0
  102. data/test/dummy/tmp/cache/assets/E00/D80/sprockets%2F9debc27161f7bccf2d84a36b8c36c4bf +522 -0
  103. data/test/dummy/tmp/cache/assets/E00/E60/sprockets%2Fac159b94b0a6d621e4f6cde9b4de87bb +0 -0
  104. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  105. data/test/dummy/tmp/cache/assets/E1B/D00/sprockets%2F886dff4afe55f9d3f8abe434f2689add +72 -0
  106. data/test/dummy/tmp/cache/assets/E1B/F20/sprockets%2Fa4bbc04eb83ebf94fd8134c3abd220dd +494 -0
  107. data/test/dummy/tmp/cache/assets/E71/0C0/sprockets%2F5ffdc0daa0a1f9638c787897ceefcdee +1260 -0
  108. metadata +186 -10
  109. data/test/dummy/tmp/pids/server.pid +0 -1
@@ -0,0 +1,1371 @@
1
+ o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1325549267.8640718: @value{I"
2
+ class:EFI"BundledAsset;
3
+ FI"id;
4
+ F"%17ac20756a770afbab2d234d9f34de67I"logical_path;
5
+ FI" closure/goog/array/array.js;
6
+ TI"
7
+ F"�/Users/ali/.rvm/gems/ruby-1.9.3-p0/bundler/gems/closure-library-wrapper-b30bab11ab83/vendor/closure-library/closure/goog/array/array.jsI"content_type;
8
+ FI"application/javascript;
9
+ FI"
10
+ mtime;
11
+ FI"2012-01-03T00:06:51+00:00;
12
+ FI" body;
13
+ FI"��// Copyright 2006 The Closure Library Authors. All Rights Reserved.
14
+ //
15
+ // Licensed under the Apache License, Version 2.0 (the "License");
16
+ // you may not use this file except in compliance with the License.
17
+ // You may obtain a copy of the License at
18
+ //
19
+ // http://www.apache.org/licenses/LICENSE-2.0
20
+ //
21
+ // Unless required by applicable law or agreed to in writing, software
22
+ // distributed under the License is distributed on an "AS-IS" BASIS,
23
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24
+ // See the License for the specific language governing permissions and
25
+ // limitations under the License.
26
+
27
+ /**
28
+ * @fileoverview Utilities for manipulating arrays.
29
+ *
30
+ */
31
+
32
+
33
+
34
+ goog.provide('goog.array');
35
+ goog.provide('goog.array.ArrayLike');
36
+
37
+ goog.require('goog.asserts');
38
+
39
+
40
+ /**
41
+ * @define {boolean} NATIVE_ARRAY_PROTOTYPES indicates whether the code should
42
+ * rely on Array.prototype functions, if available.
43
+ *
44
+ * The Array.prototype functions can be defined by external libraries like
45
+ * Prototype and setting this flag to false forces closure to use its own
46
+ * goog.array implementation.
47
+ *
48
+ * If your javascript can be loaded by a third party site and you are wary about
49
+ * relying on the prototype functions, specify
50
+ * "--define goog.NATIVE_ARRAY_PROTOTYPES=false" to the JSCompiler.
51
+ */
52
+ goog.NATIVE_ARRAY_PROTOTYPES = true;
53
+
54
+
55
+ /**
56
+ * @typedef {Array|NodeList|Arguments|{length: number}}
57
+ */
58
+ goog.array.ArrayLike;
59
+
60
+
61
+ /**
62
+ * Returns the last element in an array without removing it.
63
+ * @param {goog.array.ArrayLike} array The array.
64
+ * @return {*} Last item in array.
65
+ */
66
+ goog.array.peek = function(array) {
67
+ return array[array.length - 1];
68
+ };
69
+
70
+
71
+ /**
72
+ * Reference to the original {@code Array.prototype}.
73
+ * @private
74
+ */
75
+ goog.array.ARRAY_PROTOTYPE_ = Array.prototype;
76
+
77
+
78
+ // NOTE(arv): Since most of the array functions are generic it allows you to
79
+ // pass an array-like object. Strings have a length and are considered array-
80
+ // like. However, the 'in' operator does not work on strings so we cannot just
81
+ // use the array path even if the browser supports indexing into strings. We
82
+ // therefore end up splitting the string.
83
+
84
+
85
+ /**
86
+ * Returns the index of the first element of an array with a specified
87
+ * value, or -1 if the element is not present in the array.
88
+ *
89
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-indexof}
90
+ *
91
+ * @param {goog.array.ArrayLike} arr The array to be searched.
92
+ * @param {*} obj The object for which we are searching.
93
+ * @param {number=} opt_fromIndex The index at which to start the search. If
94
+ * omitted the search starts at index 0.
95
+ * @return {number} The index of the first matching array element.
96
+ */
97
+ goog.array.indexOf = goog.NATIVE_ARRAY_PROTOTYPES &&
98
+ goog.array.ARRAY_PROTOTYPE_.indexOf ?
99
+ function(arr, obj, opt_fromIndex) {
100
+ goog.asserts.assert(arr.length != null);
101
+
102
+ return goog.array.ARRAY_PROTOTYPE_.indexOf.call(arr, obj, opt_fromIndex);
103
+ } :
104
+ function(arr, obj, opt_fromIndex) {
105
+ var fromIndex = opt_fromIndex == null ?
106
+ 0 : (opt_fromIndex < 0 ?
107
+ Math.max(0, arr.length + opt_fromIndex) : opt_fromIndex);
108
+
109
+ if (goog.isString(arr)) {
110
+ // Array.prototype.indexOf uses === so only strings should be found.
111
+ if (!goog.isString(obj) || obj.length != 1) {
112
+ return -1;
113
+ }
114
+ return arr.indexOf(obj, fromIndex);
115
+ }
116
+
117
+ for (var i = fromIndex; i < arr.length; i++) {
118
+ if (i in arr && arr[i] === obj)
119
+ return i;
120
+ }
121
+ return -1;
122
+ };
123
+
124
+
125
+ /**
126
+ * Returns the index of the last element of an array with a specified value, or
127
+ * -1 if the element is not present in the array.
128
+ *
129
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-lastindexof}
130
+ *
131
+ * @param {goog.array.ArrayLike} arr The array to be searched.
132
+ * @param {*} obj The object for which we are searching.
133
+ * @param {?number=} opt_fromIndex The index at which to start the search. If
134
+ * omitted the search starts at the end of the array.
135
+ * @return {number} The index of the last matching array element.
136
+ */
137
+ goog.array.lastIndexOf = goog.NATIVE_ARRAY_PROTOTYPES &&
138
+ goog.array.ARRAY_PROTOTYPE_.lastIndexOf ?
139
+ function(arr, obj, opt_fromIndex) {
140
+ goog.asserts.assert(arr.length != null);
141
+
142
+ // Firefox treats undefined and null as 0 in the fromIndex argument which
143
+ // leads it to always return -1
144
+ var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex;
145
+ return goog.array.ARRAY_PROTOTYPE_.lastIndexOf.call(arr, obj, fromIndex);
146
+ } :
147
+ function(arr, obj, opt_fromIndex) {
148
+ var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex;
149
+
150
+ if (fromIndex < 0) {
151
+ fromIndex = Math.max(0, arr.length + fromIndex);
152
+ }
153
+
154
+ if (goog.isString(arr)) {
155
+ // Array.prototype.lastIndexOf uses === so only strings should be found.
156
+ if (!goog.isString(obj) || obj.length != 1) {
157
+ return -1;
158
+ }
159
+ return arr.lastIndexOf(obj, fromIndex);
160
+ }
161
+
162
+ for (var i = fromIndex; i >= 0; i--) {
163
+ if (i in arr && arr[i] === obj)
164
+ return i;
165
+ }
166
+ return -1;
167
+ };
168
+
169
+
170
+ /**
171
+ * Calls a function for each element in an array.
172
+ *
173
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-foreach}
174
+ *
175
+ * @param {goog.array.ArrayLike} arr Array or array like object over
176
+ * which to iterate.
177
+ * @param {?function(this: T, ...)} f The function to call for every element.
178
+ * This function takes 3 arguments (the element, the index and the array).
179
+ * The return value is ignored. The function is called only for indexes of
180
+ * the array which have assigned values; it is not called for indexes which
181
+ * have been deleted or which have never been assigned values.
182
+ * @param {T=} opt_obj The object to be used as the value of 'this'
183
+ * within f.
184
+ * @template T
185
+ */
186
+ goog.array.forEach = goog.NATIVE_ARRAY_PROTOTYPES &&
187
+ goog.array.ARRAY_PROTOTYPE_.forEach ?
188
+ function(arr, f, opt_obj) {
189
+ goog.asserts.assert(arr.length != null);
190
+
191
+ goog.array.ARRAY_PROTOTYPE_.forEach.call(arr, f, opt_obj);
192
+ } :
193
+ function(arr, f, opt_obj) {
194
+ var l = arr.length; // must be fixed during loop... see docs
195
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
196
+ for (var i = 0; i < l; i++) {
197
+ if (i in arr2) {
198
+ f.call(opt_obj, arr2[i], i, arr);
199
+ }
200
+ }
201
+ };
202
+
203
+
204
+ /**
205
+ * Calls a function for each element in an array, starting from the last
206
+ * element rather than the first.
207
+ *
208
+ * @param {goog.array.ArrayLike} arr The array over which to iterate.
209
+ * @param {Function} f The function to call for every element. This function
210
+ * takes 3 arguments (the element, the index and the array). The return
211
+ * value is ignored.
212
+ * @param {Object=} opt_obj The object to be used as the value of 'this'
213
+ * within f.
214
+ */
215
+ goog.array.forEachRight = function(arr, f, opt_obj) {
216
+ var l = arr.length; // must be fixed during loop... see docs
217
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
218
+ for (var i = l - 1; i >= 0; --i) {
219
+ if (i in arr2) {
220
+ f.call(opt_obj, arr2[i], i, arr);
221
+ }
222
+ }
223
+ };
224
+
225
+
226
+ /**
227
+ * Calls a function for each element in an array, and if the function returns
228
+ * true adds the element to a new array.
229
+ *
230
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-filter}
231
+ *
232
+ * @param {goog.array.ArrayLike} arr The array over which to iterate.
233
+ * @param {Function} f The function to call for every element. This function
234
+ * takes 3 arguments (the element, the index and the array) and must
235
+ * return a Boolean. If the return value is true the element is added to the
236
+ * result array. If it is false the element is not included.
237
+ * @param {Object=} opt_obj The object to be used as the value of 'this'
238
+ * within f.
239
+ * @return {!Array} a new array in which only elements that passed the test are
240
+ * present.
241
+ */
242
+ goog.array.filter = goog.NATIVE_ARRAY_PROTOTYPES &&
243
+ goog.array.ARRAY_PROTOTYPE_.filter ?
244
+ function(arr, f, opt_obj) {
245
+ goog.asserts.assert(arr.length != null);
246
+
247
+ return goog.array.ARRAY_PROTOTYPE_.filter.call(arr, f, opt_obj);
248
+ } :
249
+ function(arr, f, opt_obj) {
250
+ var l = arr.length; // must be fixed during loop... see docs
251
+ var res = [];
252
+ var resLength = 0;
253
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
254
+ for (var i = 0; i < l; i++) {
255
+ if (i in arr2) {
256
+ var val = arr2[i]; // in case f mutates arr2
257
+ if (f.call(opt_obj, val, i, arr)) {
258
+ res[resLength++] = val;
259
+ }
260
+ }
261
+ }
262
+ return res;
263
+ };
264
+
265
+
266
+ /**
267
+ * Calls a function for each element in an array and inserts the result into a
268
+ * new array.
269
+ *
270
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-map}
271
+ *
272
+ * @param {goog.array.ArrayLike} arr The array over which to iterate.
273
+ * @param {Function} f The function to call for every element. This function
274
+ * takes 3 arguments (the element, the index and the array) and should
275
+ * return something. The result will be inserted into a new array.
276
+ * @param {Object=} opt_obj The object to be used as the value of 'this'
277
+ * within f.
278
+ * @return {!Array} a new array with the results from f.
279
+ */
280
+ goog.array.map = goog.NATIVE_ARRAY_PROTOTYPES &&
281
+ goog.array.ARRAY_PROTOTYPE_.map ?
282
+ function(arr, f, opt_obj) {
283
+ goog.asserts.assert(arr.length != null);
284
+
285
+ return goog.array.ARRAY_PROTOTYPE_.map.call(arr, f, opt_obj);
286
+ } :
287
+ function(arr, f, opt_obj) {
288
+ var l = arr.length; // must be fixed during loop... see docs
289
+ var res = new Array(l);
290
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
291
+ for (var i = 0; i < l; i++) {
292
+ if (i in arr2) {
293
+ res[i] = f.call(opt_obj, arr2[i], i, arr);
294
+ }
295
+ }
296
+ return res;
297
+ };
298
+
299
+
300
+ /**
301
+ * Passes every element of an array into a function and accumulates the result.
302
+ *
303
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-reduce}
304
+ *
305
+ * For example:
306
+ * var a = [1, 2, 3, 4];
307
+ * goog.array.reduce(a, function(r, v, i, arr) {return r + v;}, 0);
308
+ * returns 10
309
+ *
310
+ * @param {goog.array.ArrayLike} arr The array over which to iterate.
311
+ * @param {Function} f The function to call for every element. This function
312
+ * takes 4 arguments (the function's previous result or the initial value,
313
+ * the value of the current array element, the current array index, and the
314
+ * array itself)
315
+ * function(previousValue, currentValue, index, array).
316
+ * @param {*} val The initial value to pass into the function on the first call.
317
+ * @param {Object=} opt_obj The object to be used as the value of 'this'
318
+ * within f.
319
+ * @return {*} Result of evaluating f repeatedly across the values of the array.
320
+ */
321
+ goog.array.reduce = function(arr, f, val, opt_obj) {
322
+ if (arr.reduce) {
323
+ if (opt_obj) {
324
+ return arr.reduce(goog.bind(f, opt_obj), val);
325
+ } else {
326
+ return arr.reduce(f, val);
327
+ }
328
+ }
329
+ var rval = val;
330
+ goog.array.forEach(arr, function(val, index) {
331
+ rval = f.call(opt_obj, rval, val, index, arr);
332
+ });
333
+ return rval;
334
+ };
335
+
336
+
337
+ /**
338
+ * Passes every element of an array into a function and accumulates the result,
339
+ * starting from the last element and working towards the first.
340
+ *
341
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-reduceright}
342
+ *
343
+ * For example:
344
+ * var a = ['a', 'b', 'c'];
345
+ * goog.array.reduceRight(a, function(r, v, i, arr) {return r + v;}, '');
346
+ * returns 'cba'
347
+ *
348
+ * @param {goog.array.ArrayLike} arr The array over which to iterate.
349
+ * @param {Function} f The function to call for every element. This function
350
+ * takes 4 arguments (the function's previous result or the initial value,
351
+ * the value of the current array element, the current array index, and the
352
+ * array itself)
353
+ * function(previousValue, currentValue, index, array).
354
+ * @param {*} val The initial value to pass into the function on the first call.
355
+ * @param {Object=} opt_obj The object to be used as the value of 'this'
356
+ * within f.
357
+ * @return {*} Object returned as a result of evaluating f repeatedly across the
358
+ * values of the array.
359
+ */
360
+ goog.array.reduceRight = function(arr, f, val, opt_obj) {
361
+ if (arr.reduceRight) {
362
+ if (opt_obj) {
363
+ return arr.reduceRight(goog.bind(f, opt_obj), val);
364
+ } else {
365
+ return arr.reduceRight(f, val);
366
+ }
367
+ }
368
+ var rval = val;
369
+ goog.array.forEachRight(arr, function(val, index) {
370
+ rval = f.call(opt_obj, rval, val, index, arr);
371
+ });
372
+ return rval;
373
+ };
374
+
375
+
376
+ /**
377
+ * Calls f for each element of an array. If any call returns true, some()
378
+ * returns true (without checking the remaining elements). If all calls
379
+ * return false, some() returns false.
380
+ *
381
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-some}
382
+ *
383
+ * @param {goog.array.ArrayLike} arr The array to check.
384
+ * @param {Function} f The function to call for every element. This function
385
+ * takes 3 arguments (the element, the index and the array) and must
386
+ * return a Boolean.
387
+ * @param {Object=} opt_obj The object to be used as the value of 'this'
388
+ * within f.
389
+ * @return {boolean} true if any element passes the test.
390
+ */
391
+ goog.array.some = goog.NATIVE_ARRAY_PROTOTYPES &&
392
+ goog.array.ARRAY_PROTOTYPE_.some ?
393
+ function(arr, f, opt_obj) {
394
+ goog.asserts.assert(arr.length != null);
395
+
396
+ return goog.array.ARRAY_PROTOTYPE_.some.call(arr, f, opt_obj);
397
+ } :
398
+ function(arr, f, opt_obj) {
399
+ var l = arr.length; // must be fixed during loop... see docs
400
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
401
+ for (var i = 0; i < l; i++) {
402
+ if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) {
403
+ return true;
404
+ }
405
+ }
406
+ return false;
407
+ };
408
+
409
+
410
+ /**
411
+ * Call f for each element of an array. If all calls return true, every()
412
+ * returns true. If any call returns false, every() returns false and
413
+ * does not continue to check the remaining elements.
414
+ *
415
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-every}
416
+ *
417
+ * @param {goog.array.ArrayLike} arr The array to check.
418
+ * @param {Function} f The function to call for every element. This function
419
+ * takes 3 arguments (the element, the index and the array) and must
420
+ * return a Boolean.
421
+ * @param {Object=} opt_obj The object to be used as the value of 'this'
422
+ * within f.
423
+ * @return {boolean} false if any element fails the test.
424
+ */
425
+ goog.array.every = goog.NATIVE_ARRAY_PROTOTYPES &&
426
+ goog.array.ARRAY_PROTOTYPE_.every ?
427
+ function(arr, f, opt_obj) {
428
+ goog.asserts.assert(arr.length != null);
429
+
430
+ return goog.array.ARRAY_PROTOTYPE_.every.call(arr, f, opt_obj);
431
+ } :
432
+ function(arr, f, opt_obj) {
433
+ var l = arr.length; // must be fixed during loop... see docs
434
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
435
+ for (var i = 0; i < l; i++) {
436
+ if (i in arr2 && !f.call(opt_obj, arr2[i], i, arr)) {
437
+ return false;
438
+ }
439
+ }
440
+ return true;
441
+ };
442
+
443
+
444
+ /**
445
+ * Search an array for the first element that satisfies a given condition and
446
+ * return that element.
447
+ * @param {goog.array.ArrayLike} arr The array to search.
448
+ * @param {Function} f The function to call for every element. This function
449
+ * takes 3 arguments (the element, the index and the array) and should
450
+ * return a boolean.
451
+ * @param {Object=} opt_obj An optional "this" context for the function.
452
+ * @return {*} The first array element that passes the test, or null if no
453
+ * element is found.
454
+ */
455
+ goog.array.find = function(arr, f, opt_obj) {
456
+ var i = goog.array.findIndex(arr, f, opt_obj);
457
+ return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i];
458
+ };
459
+
460
+
461
+ /**
462
+ * Search an array for the first element that satisfies a given condition and
463
+ * return its index.
464
+ * @param {goog.array.ArrayLike} arr The array to search.
465
+ * @param {Function} f The function to call for every element. This function
466
+ * takes 3 arguments (the element, the index and the array) and should
467
+ * return a boolean.
468
+ * @param {Object=} opt_obj An optional "this" context for the function.
469
+ * @return {number} The index of the first array element that passes the test,
470
+ * or -1 if no element is found.
471
+ */
472
+ goog.array.findIndex = function(arr, f, opt_obj) {
473
+ var l = arr.length; // must be fixed during loop... see docs
474
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
475
+ for (var i = 0; i < l; i++) {
476
+ if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) {
477
+ return i;
478
+ }
479
+ }
480
+ return -1;
481
+ };
482
+
483
+
484
+ /**
485
+ * Search an array (in reverse order) for the last element that satisfies a
486
+ * given condition and return that element.
487
+ * @param {goog.array.ArrayLike} arr The array to search.
488
+ * @param {Function} f The function to call for every element. This function
489
+ * takes 3 arguments (the element, the index and the array) and should
490
+ * return a boolean.
491
+ * @param {Object=} opt_obj An optional "this" context for the function.
492
+ * @return {*} The last array element that passes the test, or null if no
493
+ * element is found.
494
+ */
495
+ goog.array.findRight = function(arr, f, opt_obj) {
496
+ var i = goog.array.findIndexRight(arr, f, opt_obj);
497
+ return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i];
498
+ };
499
+
500
+
501
+ /**
502
+ * Search an array (in reverse order) for the last element that satisfies a
503
+ * given condition and return its index.
504
+ * @param {goog.array.ArrayLike} arr The array to search.
505
+ * @param {Function} f The function to call for every element. This function
506
+ * takes 3 arguments (the element, the index and the array) and should
507
+ * return a boolean.
508
+ * @param {Object=} opt_obj An optional "this" context for the function.
509
+ * @return {number} The index of the last array element that passes the test,
510
+ * or -1 if no element is found.
511
+ */
512
+ goog.array.findIndexRight = function(arr, f, opt_obj) {
513
+ var l = arr.length; // must be fixed during loop... see docs
514
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
515
+ for (var i = l - 1; i >= 0; i--) {
516
+ if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) {
517
+ return i;
518
+ }
519
+ }
520
+ return -1;
521
+ };
522
+
523
+
524
+ /**
525
+ * Whether the array contains the given object.
526
+ * @param {goog.array.ArrayLike} arr The array to test for the presence of the
527
+ * element.
528
+ * @param {*} obj The object for which to test.
529
+ * @return {boolean} true if obj is present.
530
+ */
531
+ goog.array.contains = function(arr, obj) {
532
+ return goog.array.indexOf(arr, obj) >= 0;
533
+ };
534
+
535
+
536
+ /**
537
+ * Whether the array is empty.
538
+ * @param {goog.array.ArrayLike} arr The array to test.
539
+ * @return {boolean} true if empty.
540
+ */
541
+ goog.array.isEmpty = function(arr) {
542
+ return arr.length == 0;
543
+ };
544
+
545
+
546
+ /**
547
+ * Clears the array.
548
+ * @param {goog.array.ArrayLike} arr Array or array like object to clear.
549
+ */
550
+ goog.array.clear = function(arr) {
551
+ // For non real arrays we don't have the magic length so we delete the
552
+ // indices.
553
+ if (!goog.isArray(arr)) {
554
+ for (var i = arr.length - 1; i >= 0; i--) {
555
+ delete arr[i];
556
+ }
557
+ }
558
+ arr.length = 0;
559
+ };
560
+
561
+
562
+ /**
563
+ * Pushes an item into an array, if it's not already in the array.
564
+ * @param {Array} arr Array into which to insert the item.
565
+ * @param {*} obj Value to add.
566
+ */
567
+ goog.array.insert = function(arr, obj) {
568
+ if (!goog.array.contains(arr, obj)) {
569
+ arr.push(obj);
570
+ }
571
+ };
572
+
573
+
574
+ /**
575
+ * Inserts an object at the given index of the array.
576
+ * @param {goog.array.ArrayLike} arr The array to modify.
577
+ * @param {*} obj The object to insert.
578
+ * @param {number=} opt_i The index at which to insert the object. If omitted,
579
+ * treated as 0. A negative index is counted from the end of the array.
580
+ */
581
+ goog.array.insertAt = function(arr, obj, opt_i) {
582
+ goog.array.splice(arr, opt_i, 0, obj);
583
+ };
584
+
585
+
586
+ /**
587
+ * Inserts at the given index of the array, all elements of another array.
588
+ * @param {goog.array.ArrayLike} arr The array to modify.
589
+ * @param {goog.array.ArrayLike} elementsToAdd The array of elements to add.
590
+ * @param {number=} opt_i The index at which to insert the object. If omitted,
591
+ * treated as 0. A negative index is counted from the end of the array.
592
+ */
593
+ goog.array.insertArrayAt = function(arr, elementsToAdd, opt_i) {
594
+ goog.partial(goog.array.splice, arr, opt_i, 0).apply(null, elementsToAdd);
595
+ };
596
+
597
+
598
+ /**
599
+ * Inserts an object into an array before a specified object.
600
+ * @param {Array} arr The array to modify.
601
+ * @param {*} obj The object to insert.
602
+ * @param {*=} opt_obj2 The object before which obj should be inserted. If obj2
603
+ * is omitted or not found, obj is inserted at the end of the array.
604
+ */
605
+ goog.array.insertBefore = function(arr, obj, opt_obj2) {
606
+ var i;
607
+ if (arguments.length == 2 || (i = goog.array.indexOf(arr, opt_obj2)) < 0) {
608
+ arr.push(obj);
609
+ } else {
610
+ goog.array.insertAt(arr, obj, i);
611
+ }
612
+ };
613
+
614
+
615
+ /**
616
+ * Removes the first occurrence of a particular value from an array.
617
+ * @param {goog.array.ArrayLike} arr Array from which to remove value.
618
+ * @param {*} obj Object to remove.
619
+ * @return {boolean} True if an element was removed.
620
+ */
621
+ goog.array.remove = function(arr, obj) {
622
+ var i = goog.array.indexOf(arr, obj);
623
+ var rv;
624
+ if ((rv = i >= 0)) {
625
+ goog.array.removeAt(arr, i);
626
+ }
627
+ return rv;
628
+ };
629
+
630
+
631
+ /**
632
+ * Removes from an array the element at index i
633
+ * @param {goog.array.ArrayLike} arr Array or array like object from which to
634
+ * remove value.
635
+ * @param {number} i The index to remove.
636
+ * @return {boolean} True if an element was removed.
637
+ */
638
+ goog.array.removeAt = function(arr, i) {
639
+ goog.asserts.assert(arr.length != null);
640
+
641
+ // use generic form of splice
642
+ // splice returns the removed items and if successful the length of that
643
+ // will be 1
644
+ return goog.array.ARRAY_PROTOTYPE_.splice.call(arr, i, 1).length == 1;
645
+ };
646
+
647
+
648
+ /**
649
+ * Removes the first value that satisfies the given condition.
650
+ * @param {goog.array.ArrayLike} arr Array from which to remove value.
651
+ * @param {Function} f The function to call for every element. This function
652
+ * takes 3 arguments (the element, the index and the array) and should
653
+ * return a boolean.
654
+ * @param {Object=} opt_obj An optional "this" context for the function.
655
+ * @return {boolean} True if an element was removed.
656
+ */
657
+ goog.array.removeIf = function(arr, f, opt_obj) {
658
+ var i = goog.array.findIndex(arr, f, opt_obj);
659
+ if (i >= 0) {
660
+ goog.array.removeAt(arr, i);
661
+ return true;
662
+ }
663
+ return false;
664
+ };
665
+
666
+
667
+ /**
668
+ * Returns a new array that is the result of joining the arguments. If arrays
669
+ * are passed then their items are added, however, if non-arrays are passed they
670
+ * will be added to the return array as is.
671
+ *
672
+ * Note that ArrayLike objects will be added as is, rather than having their
673
+ * items added.
674
+ *
675
+ * goog.array.concat([1, 2], [3, 4]) -> [1, 2, 3, 4]
676
+ * goog.array.concat(0, [1, 2]) -> [0, 1, 2]
677
+ * goog.array.concat([1, 2], null) -> [1, 2, null]
678
+ *
679
+ * There is bug in all current versions of IE (6, 7 and 8) where arrays created
680
+ * in an iframe become corrupted soon (not immediately) after the iframe is
681
+ * destroyed. This is common if loading data via goog.net.IframeIo, for example.
682
+ * This corruption only affects the concat method which will start throwing
683
+ * Catastrophic Errors (#-2147418113).
684
+ *
685
+ * See http://endoflow.com/scratch/corrupted-arrays.html for a test case.
686
+ *
687
+ * Internally goog.array should use this, so that all methods will continue to
688
+ * work on these broken array objects.
689
+ *
690
+ * @param {...*} var_args Items to concatenate. Arrays will have each item
691
+ * added, while primitives and objects will be added as is.
692
+ * @return {!Array} The new resultant array.
693
+ */
694
+ goog.array.concat = function(var_args) {
695
+ return goog.array.ARRAY_PROTOTYPE_.concat.apply(
696
+ goog.array.ARRAY_PROTOTYPE_, arguments);
697
+ };
698
+
699
+
700
+ /**
701
+ * Does a shallow copy of an array.
702
+ * @param {goog.array.ArrayLike} arr Array or array-like object to clone.
703
+ * @return {!Array} Clone of the input array.
704
+ */
705
+ goog.array.clone = function(arr) {
706
+ if (goog.isArray(arr)) {
707
+ return goog.array.concat(/** @type {!Array} */ (arr));
708
+ } else { // array like
709
+ // Concat does not work with non arrays.
710
+ var rv = [];
711
+ for (var i = 0, len = arr.length; i < len; i++) {
712
+ rv[i] = arr[i];
713
+ }
714
+ return rv;
715
+ }
716
+ };
717
+
718
+
719
+ /**
720
+ * Converts an object to an array.
721
+ * @param {goog.array.ArrayLike} object The object to convert to an array.
722
+ * @return {!Array} The object converted into an array. If object has a
723
+ * length property, every property indexed with a non-negative number
724
+ * less than length will be included in the result. If object does not
725
+ * have a length property, an empty array will be returned.
726
+ */
727
+ goog.array.toArray = function(object) {
728
+ if (goog.isArray(object)) {
729
+ // This fixes the JS compiler warning and forces the Object to an Array type
730
+ return goog.array.concat(/** @type {!Array} */ (object));
731
+ }
732
+ // Clone what we hope to be an array-like object to an array.
733
+ // We could check isArrayLike() first, but no check we perform would be as
734
+ // reliable as simply making the call.
735
+ return goog.array.clone(/** @type {Array} */ (object));
736
+ };
737
+
738
+
739
+ /**
740
+ * Extends an array with another array, element, or "array like" object.
741
+ * This function operates 'in-place', it does not create a new Array.
742
+ *
743
+ * Example:
744
+ * var a = [];
745
+ * goog.array.extend(a, [0, 1]);
746
+ * a; // [0, 1]
747
+ * goog.array.extend(a, 2);
748
+ * a; // [0, 1, 2]
749
+ *
750
+ * @param {Array} arr1 The array to modify.
751
+ * @param {...*} var_args The elements or arrays of elements to add to arr1.
752
+ */
753
+ goog.array.extend = function(arr1, var_args) {
754
+ for (var i = 1; i < arguments.length; i++) {
755
+ var arr2 = arguments[i];
756
+ // If we have an Array or an Arguments object we can just call push
757
+ // directly.
758
+ var isArrayLike;
759
+ if (goog.isArray(arr2) ||
760
+ // Detect Arguments. ES5 says that the [[Class]] of an Arguments object
761
+ // is "Arguments" but only V8 and JSC/Safari gets this right. We instead
762
+ // detect Arguments by checking for array like and presence of "callee".
763
+ (isArrayLike = goog.isArrayLike(arr2)) &&
764
+ // The getter for callee throws an exception in strict mode
765
+ // according to section 10.6 in ES5 so check for presence instead.
766
+ arr2.hasOwnProperty('callee')) {
767
+ arr1.push.apply(arr1, arr2);
768
+
769
+ } else if (isArrayLike) {
770
+ // Otherwise loop over arr2 to prevent copying the object.
771
+ var len1 = arr1.length;
772
+ var len2 = arr2.length;
773
+ for (var j = 0; j < len2; j++) {
774
+ arr1[len1 + j] = arr2[j];
775
+ }
776
+ } else {
777
+ arr1.push(arr2);
778
+ }
779
+ }
780
+ };
781
+
782
+
783
+ /**
784
+ * Adds or removes elements from an array. This is a generic version of Array
785
+ * splice. This means that it might work on other objects similar to arrays,
786
+ * such as the arguments object.
787
+ *
788
+ * @param {goog.array.ArrayLike} arr The array to modify.
789
+ * @param {number|undefined} index The index at which to start changing the
790
+ * array. If not defined, treated as 0.
791
+ * @param {number} howMany How many elements to remove (0 means no removal. A
792
+ * value below 0 is treated as zero and so is any other non number. Numbers
793
+ * are floored).
794
+ * @param {...*} var_args Optional, additional elements to insert into the
795
+ * array.
796
+ * @return {!Array} the removed elements.
797
+ */
798
+ goog.array.splice = function(arr, index, howMany, var_args) {
799
+ goog.asserts.assert(arr.length != null);
800
+
801
+ return goog.array.ARRAY_PROTOTYPE_.splice.apply(
802
+ arr, goog.array.slice(arguments, 1));
803
+ };
804
+
805
+
806
+ /**
807
+ * Returns a new array from a segment of an array. This is a generic version of
808
+ * Array slice. This means that it might work on other objects similar to
809
+ * arrays, such as the arguments object.
810
+ *
811
+ * @param {goog.array.ArrayLike} arr The array from which to copy a segment.
812
+ * @param {number} start The index of the first element to copy.
813
+ * @param {number=} opt_end The index after the last element to copy.
814
+ * @return {!Array} A new array containing the specified segment of the original
815
+ * array.
816
+ */
817
+ goog.array.slice = function(arr, start, opt_end) {
818
+ goog.asserts.assert(arr.length != null);
819
+
820
+ // passing 1 arg to slice is not the same as passing 2 where the second is
821
+ // null or undefined (in that case the second argument is treated as 0).
822
+ // we could use slice on the arguments object and then use apply instead of
823
+ // testing the length
824
+ if (arguments.length <= 2) {
825
+ return goog.array.ARRAY_PROTOTYPE_.slice.call(arr, start);
826
+ } else {
827
+ return goog.array.ARRAY_PROTOTYPE_.slice.call(arr, start, opt_end);
828
+ }
829
+ };
830
+
831
+
832
+ /**
833
+ * Removes all duplicates from an array (retaining only the first
834
+ * occurrence of each array element). This function modifies the
835
+ * array in place and doesn't change the order of the non-duplicate items.
836
+ *
837
+ * For objects, duplicates are identified as having the same unique ID as
838
+ * defined by {@link goog.getUid}.
839
+ *
840
+ * Runtime: N,
841
+ * Worstcase space: 2N (no dupes)
842
+ *
843
+ * @param {goog.array.ArrayLike} arr The array from which to remove duplicates.
844
+ * @param {Array=} opt_rv An optional array in which to return the results,
845
+ * instead of performing the removal inplace. If specified, the original
846
+ * array will remain unchanged.
847
+ */
848
+ goog.array.removeDuplicates = function(arr, opt_rv) {
849
+ var returnArray = opt_rv || arr;
850
+
851
+ var seen = {}, cursorInsert = 0, cursorRead = 0;
852
+ while (cursorRead < arr.length) {
853
+ var current = arr[cursorRead++];
854
+
855
+ // Prefix each type with a single character representing the type to
856
+ // prevent conflicting keys (e.g. true and 'true').
857
+ var key = goog.isObject(current) ?
858
+ 'o' + goog.getUid(current) :
859
+ (typeof current).charAt(0) + current;
860
+
861
+ if (!Object.prototype.hasOwnProperty.call(seen, key)) {
862
+ seen[key] = true;
863
+ returnArray[cursorInsert++] = current;
864
+ }
865
+ }
866
+ returnArray.length = cursorInsert;
867
+ };
868
+
869
+
870
+ /**
871
+ * Searches the specified array for the specified target using the binary
872
+ * search algorithm. If no opt_compareFn is specified, elements are compared
873
+ * using <code>goog.array.defaultCompare</code>, which compares the elements
874
+ * using the built in < and > operators. This will produce the expected
875
+ * behavior for homogeneous arrays of String(s) and Number(s). The array
876
+ * specified <b>must</b> be sorted in ascending order (as defined by the
877
+ * comparison function). If the array is not sorted, results are undefined.
878
+ * If the array contains multiple instances of the specified target value, any
879
+ * of these instances may be found.
880
+ *
881
+ * Runtime: O(log n)
882
+ *
883
+ * @param {goog.array.ArrayLike} arr The array to be searched.
884
+ * @param {*} target The sought value.
885
+ * @param {Function=} opt_compareFn Optional comparison function by which the
886
+ * array is ordered. Should take 2 arguments to compare, and return a
887
+ * negative number, zero, or a positive number depending on whether the
888
+ * first argument is less than, equal to, or greater than the second.
889
+ * @return {number} Lowest index of the target value if found, otherwise
890
+ * (-(insertion point) - 1). The insertion point is where the value should
891
+ * be inserted into arr to preserve the sorted property. Return value >= 0
892
+ * iff target is found.
893
+ */
894
+ goog.array.binarySearch = function(arr, target, opt_compareFn) {
895
+ return goog.array.binarySearch_(arr,
896
+ opt_compareFn || goog.array.defaultCompare, false /* isEvaluator */,
897
+ target);
898
+ };
899
+
900
+
901
+ /**
902
+ * Selects an index in the specified array using the binary search algorithm.
903
+ * The evaluator receives an element and determines whether the desired index
904
+ * is before, at, or after it. The evaluator must be consistent (formally,
905
+ * goog.array.map(goog.array.map(arr, evaluator, opt_obj), goog.math.sign)
906
+ * must be monotonically non-increasing).
907
+ *
908
+ * Runtime: O(log n)
909
+ *
910
+ * @param {goog.array.ArrayLike} arr The array to be searched.
911
+ * @param {Function} evaluator Evaluator function that receives 3 arguments
912
+ * (the element, the index and the array). Should return a negative number,
913
+ * zero, or a positive number depending on whether the desired index is
914
+ * before, at, or after the element passed to it.
915
+ * @param {Object=} opt_obj The object to be used as the value of 'this'
916
+ * within evaluator.
917
+ * @return {number} Index of the leftmost element matched by the evaluator, if
918
+ * such exists; otherwise (-(insertion point) - 1). The insertion point is
919
+ * the index of the first element for which the evaluator returns negative,
920
+ * or arr.length if no such element exists. The return value is non-negative
921
+ * iff a match is found.
922
+ */
923
+ goog.array.binarySelect = function(arr, evaluator, opt_obj) {
924
+ return goog.array.binarySearch_(arr, evaluator, true /* isEvaluator */,
925
+ undefined /* opt_target */, opt_obj);
926
+ };
927
+
928
+
929
+ /**
930
+ * Implementation of a binary search algorithm which knows how to use both
931
+ * comparison functions and evaluators. If an evaluator is provided, will call
932
+ * the evaluator with the given optional data object, conforming to the
933
+ * interface defined in binarySelect. Otherwise, if a comparison function is
934
+ * provided, will call the comparison function against the given data object.
935
+ *
936
+ * This implementation purposefully does not use goog.bind or goog.partial for
937
+ * performance reasons.
938
+ *
939
+ * Runtime: O(log n)
940
+ *
941
+ * @param {goog.array.ArrayLike} arr The array to be searched.
942
+ * @param {Function} compareFn Either an evaluator or a comparison function,
943
+ * as defined by binarySearch and binarySelect above.
944
+ * @param {boolean} isEvaluator Whether the function is an evaluator or a
945
+ * comparison function.
946
+ * @param {*=} opt_target If the function is a comparison function, then this is
947
+ * the target to binary search for.
948
+ * @param {Object=} opt_selfObj If the function is an evaluator, this is an
949
+ * optional this object for the evaluator.
950
+ * @return {number} Lowest index of the target value if found, otherwise
951
+ * (-(insertion point) - 1). The insertion point is where the value should
952
+ * be inserted into arr to preserve the sorted property. Return value >= 0
953
+ * iff target is found.
954
+ * @private
955
+ */
956
+ goog.array.binarySearch_ = function(arr, compareFn, isEvaluator, opt_target,
957
+ opt_selfObj) {
958
+ var left = 0; // inclusive
959
+ var right = arr.length; // exclusive
960
+ var found;
961
+ while (left < right) {
962
+ var middle = (left + right) >> 1;
963
+ var compareResult;
964
+ if (isEvaluator) {
965
+ compareResult = compareFn.call(opt_selfObj, arr[middle], middle, arr);
966
+ } else {
967
+ compareResult = compareFn(opt_target, arr[middle]);
968
+ }
969
+ if (compareResult > 0) {
970
+ left = middle + 1;
971
+ } else {
972
+ right = middle;
973
+ // We are looking for the lowest index so we can't return immediately.
974
+ found = !compareResult;
975
+ }
976
+ }
977
+ // left is the index if found, or the insertion point otherwise.
978
+ // ~left is a shorthand for -left - 1.
979
+ return found ? left : ~left;
980
+ };
981
+
982
+
983
+ /**
984
+ * Sorts the specified array into ascending order. If no opt_compareFn is
985
+ * specified, elements are compared using
986
+ * <code>goog.array.defaultCompare</code>, which compares the elements using
987
+ * the built in < and > operators. This will produce the expected behavior
988
+ * for homogeneous arrays of String(s) and Number(s), unlike the native sort,
989
+ * but will give unpredictable results for heterogenous lists of strings and
990
+ * numbers with different numbers of digits.
991
+ *
992
+ * This sort is not guaranteed to be stable.
993
+ *
994
+ * Runtime: Same as <code>Array.prototype.sort</code>
995
+ *
996
+ * @param {Array} arr The array to be sorted.
997
+ * @param {Function=} opt_compareFn Optional comparison function by which the
998
+ * array is to be ordered. Should take 2 arguments to compare, and return a
999
+ * negative number, zero, or a positive number depending on whether the
1000
+ * first argument is less than, equal to, or greater than the second.
1001
+ */
1002
+ goog.array.sort = function(arr, opt_compareFn) {
1003
+ // TODO(arv): Update type annotation since null is not accepted.
1004
+ goog.asserts.assert(arr.length != null);
1005
+
1006
+ goog.array.ARRAY_PROTOTYPE_.sort.call(
1007
+ arr, opt_compareFn || goog.array.defaultCompare);
1008
+ };
1009
+
1010
+
1011
+ /**
1012
+ * Sorts the specified array into ascending order in a stable way. If no
1013
+ * opt_compareFn is specified, elements are compared using
1014
+ * <code>goog.array.defaultCompare</code>, which compares the elements using
1015
+ * the built in < and > operators. This will produce the expected behavior
1016
+ * for homogeneous arrays of String(s) and Number(s).
1017
+ *
1018
+ * Runtime: Same as <code>Array.prototype.sort</code>, plus an additional
1019
+ * O(n) overhead of copying the array twice.
1020
+ *
1021
+ * @param {Array} arr The array to be sorted.
1022
+ * @param {function(*, *): number=} opt_compareFn Optional comparison function
1023
+ * by which the array is to be ordered. Should take 2 arguments to compare,
1024
+ * and return a negative number, zero, or a positive number depending on
1025
+ * whether the first argument is less than, equal to, or greater than the
1026
+ * second.
1027
+ */
1028
+ goog.array.stableSort = function(arr, opt_compareFn) {
1029
+ for (var i = 0; i < arr.length; i++) {
1030
+ arr[i] = {index: i, value: arr[i]};
1031
+ }
1032
+ var valueCompareFn = opt_compareFn || goog.array.defaultCompare;
1033
+ function stableCompareFn(obj1, obj2) {
1034
+ return valueCompareFn(obj1.value, obj2.value) || obj1.index - obj2.index;
1035
+ };
1036
+ goog.array.sort(arr, stableCompareFn);
1037
+ for (var i = 0; i < arr.length; i++) {
1038
+ arr[i] = arr[i].value;
1039
+ }
1040
+ };
1041
+
1042
+
1043
+ /**
1044
+ * Sorts an array of objects by the specified object key and compare
1045
+ * function. If no compare function is provided, the key values are
1046
+ * compared in ascending order using <code>goog.array.defaultCompare</code>.
1047
+ * This won't work for keys that get renamed by the compiler. So use
1048
+ * {'foo': 1, 'bar': 2} rather than {foo: 1, bar: 2}.
1049
+ * @param {Array.<Object>} arr An array of objects to sort.
1050
+ * @param {string} key The object key to sort by.
1051
+ * @param {Function=} opt_compareFn The function to use to compare key
1052
+ * values.
1053
+ */
1054
+ goog.array.sortObjectsByKey = function(arr, key, opt_compareFn) {
1055
+ var compare = opt_compareFn || goog.array.defaultCompare;
1056
+ goog.array.sort(arr, function(a, b) {
1057
+ return compare(a[key], b[key]);
1058
+ });
1059
+ };
1060
+
1061
+
1062
+ /**
1063
+ * Tells if the array is sorted.
1064
+ * @param {!Array} arr The array.
1065
+ * @param {Function=} opt_compareFn Function to compare the array elements.
1066
+ * Should take 2 arguments to compare, and return a negative number, zero,
1067
+ * or a positive number depending on whether the first argument is less
1068
+ * than, equal to, or greater than the second.
1069
+ * @param {boolean=} opt_strict If true no equal elements are allowed.
1070
+ * @return {boolean} Whether the array is sorted.
1071
+ */
1072
+ goog.array.isSorted = function(arr, opt_compareFn, opt_strict) {
1073
+ var compare = opt_compareFn || goog.array.defaultCompare;
1074
+ for (var i = 1; i < arr.length; i++) {
1075
+ var compareResult = compare(arr[i - 1], arr[i]);
1076
+ if (compareResult > 0 || compareResult == 0 && opt_strict) {
1077
+ return false;
1078
+ }
1079
+ }
1080
+ return true;
1081
+ };
1082
+
1083
+
1084
+ /**
1085
+ * Compares two arrays for equality. Two arrays are considered equal if they
1086
+ * have the same length and their corresponding elements are equal according to
1087
+ * the comparison function.
1088
+ *
1089
+ * @param {goog.array.ArrayLike} arr1 The first array to compare.
1090
+ * @param {goog.array.ArrayLike} arr2 The second array to compare.
1091
+ * @param {Function=} opt_equalsFn Optional comparison function.
1092
+ * Should take 2 arguments to compare, and return true if the arguments
1093
+ * are equal. Defaults to {@link goog.array.defaultCompareEquality} which
1094
+ * compares the elements using the built-in '===' operator.
1095
+ * @return {boolean} Whether the two arrays are equal.
1096
+ */
1097
+ goog.array.equals = function(arr1, arr2, opt_equalsFn) {
1098
+ if (!goog.isArrayLike(arr1) || !goog.isArrayLike(arr2) ||
1099
+ arr1.length != arr2.length) {
1100
+ return false;
1101
+ }
1102
+ var l = arr1.length;
1103
+ var equalsFn = opt_equalsFn || goog.array.defaultCompareEquality;
1104
+ for (var i = 0; i < l; i++) {
1105
+ if (!equalsFn(arr1[i], arr2[i])) {
1106
+ return false;
1107
+ }
1108
+ }
1109
+ return true;
1110
+ };
1111
+
1112
+
1113
+ /**
1114
+ * @deprecated Use {@link goog.array.equals}.
1115
+ * @param {goog.array.ArrayLike} arr1 See {@link goog.array.equals}.
1116
+ * @param {goog.array.ArrayLike} arr2 See {@link goog.array.equals}.
1117
+ * @param {Function=} opt_equalsFn See {@link goog.array.equals}.
1118
+ * @return {boolean} See {@link goog.array.equals}.
1119
+ */
1120
+ goog.array.compare = function(arr1, arr2, opt_equalsFn) {
1121
+ return goog.array.equals(arr1, arr2, opt_equalsFn);
1122
+ };
1123
+
1124
+
1125
+ /**
1126
+ * 3-way array compare function.
1127
+ * @param {!goog.array.ArrayLike} arr1 The first array to compare.
1128
+ * @param {!goog.array.ArrayLike} arr2 The second array to compare.
1129
+ * @param {(function(*, *): number)=} opt_compareFn Optional comparison function
1130
+ * by which the array is to be ordered. Should take 2 arguments to compare,
1131
+ * and return a negative number, zero, or a positive number depending on
1132
+ * whether the first argument is less than, equal to, or greater than the
1133
+ * second.
1134
+ * @return {number} Negative number, zero, or a positive number depending on
1135
+ * whether the first argument is less than, equal to, or greater than the
1136
+ * second.
1137
+ */
1138
+ goog.array.compare3 = function(arr1, arr2, opt_compareFn) {
1139
+ var compare = opt_compareFn || goog.array.defaultCompare;
1140
+ var l = Math.min(arr1.length, arr2.length);
1141
+ for (var i = 0; i < l; i++) {
1142
+ var result = compare(arr1[i], arr2[i]);
1143
+ if (result != 0) {
1144
+ return result;
1145
+ }
1146
+ }
1147
+ return goog.array.defaultCompare(arr1.length, arr2.length);
1148
+ };
1149
+
1150
+
1151
+ /**
1152
+ * Compares its two arguments for order, using the built in < and >
1153
+ * operators.
1154
+ * @param {*} a The first object to be compared.
1155
+ * @param {*} b The second object to be compared.
1156
+ * @return {number} A negative number, zero, or a positive number as the first
1157
+ * argument is less than, equal to, or greater than the second.
1158
+ */
1159
+ goog.array.defaultCompare = function(a, b) {
1160
+ return a > b ? 1 : a < b ? -1 : 0;
1161
+ };
1162
+
1163
+
1164
+ /**
1165
+ * Compares its two arguments for equality, using the built in === operator.
1166
+ * @param {*} a The first object to compare.
1167
+ * @param {*} b The second object to compare.
1168
+ * @return {boolean} True if the two arguments are equal, false otherwise.
1169
+ */
1170
+ goog.array.defaultCompareEquality = function(a, b) {
1171
+ return a === b;
1172
+ };
1173
+
1174
+
1175
+ /**
1176
+ * Inserts a value into a sorted array. The array is not modified if the
1177
+ * value is already present.
1178
+ * @param {Array} array The array to modify.
1179
+ * @param {*} value The object to insert.
1180
+ * @param {Function=} opt_compareFn Optional comparison function by which the
1181
+ * array is ordered. Should take 2 arguments to compare, and return a
1182
+ * negative number, zero, or a positive number depending on whether the
1183
+ * first argument is less than, equal to, or greater than the second.
1184
+ * @return {boolean} True if an element was inserted.
1185
+ */
1186
+ goog.array.binaryInsert = function(array, value, opt_compareFn) {
1187
+ var index = goog.array.binarySearch(array, value, opt_compareFn);
1188
+ if (index < 0) {
1189
+ goog.array.insertAt(array, value, -(index + 1));
1190
+ return true;
1191
+ }
1192
+ return false;
1193
+ };
1194
+
1195
+
1196
+ /**
1197
+ * Removes a value from a sorted array.
1198
+ * @param {Array} array The array to modify.
1199
+ * @param {*} value The object to remove.
1200
+ * @param {Function=} opt_compareFn Optional comparison function by which the
1201
+ * array is ordered. Should take 2 arguments to compare, and return a
1202
+ * negative number, zero, or a positive number depending on whether the
1203
+ * first argument is less than, equal to, or greater than the second.
1204
+ * @return {boolean} True if an element was removed.
1205
+ */
1206
+ goog.array.binaryRemove = function(array, value, opt_compareFn) {
1207
+ var index = goog.array.binarySearch(array, value, opt_compareFn);
1208
+ return (index >= 0) ? goog.array.removeAt(array, index) : false;
1209
+ };
1210
+
1211
+
1212
+ /**
1213
+ * Splits an array into disjoint buckets according to a splitting function.
1214
+ * @param {Array} array The array.
1215
+ * @param {Function} sorter Function to call for every element. This
1216
+ * takes 3 arguments (the element, the index and the array) and must
1217
+ * return a valid object key (a string, number, etc), or undefined, if
1218
+ * that object should not be placed in a bucket.
1219
+ * @return {!Object} An object, with keys being all of the unique return values
1220
+ * of sorter, and values being arrays containing the items for
1221
+ * which the splitter returned that key.
1222
+ */
1223
+ goog.array.bucket = function(array, sorter) {
1224
+ var buckets = {};
1225
+
1226
+ for (var i = 0; i < array.length; i++) {
1227
+ var value = array[i];
1228
+ var key = sorter(value, i, array);
1229
+ if (goog.isDef(key)) {
1230
+ // Push the value to the right bucket, creating it if necessary.
1231
+ var bucket = buckets[key] || (buckets[key] = []);
1232
+ bucket.push(value);
1233
+ }
1234
+ }
1235
+
1236
+ return buckets;
1237
+ };
1238
+
1239
+
1240
+ /**
1241
+ * Returns an array consisting of the given value repeated N times.
1242
+ *
1243
+ * @param {*} value The value to repeat.
1244
+ * @param {number} n The repeat count.
1245
+ * @return {!Array.<*>} An array with the repeated value.
1246
+ */
1247
+ goog.array.repeat = function(value, n) {
1248
+ var array = [];
1249
+ for (var i = 0; i < n; i++) {
1250
+ array[i] = value;
1251
+ }
1252
+ return array;
1253
+ };
1254
+
1255
+
1256
+ /**
1257
+ * Returns an array consisting of every argument with all arrays
1258
+ * expanded in-place recursively.
1259
+ *
1260
+ * @param {...*} var_args The values to flatten.
1261
+ * @return {!Array.<*>} An array containing the flattened values.
1262
+ */
1263
+ goog.array.flatten = function(var_args) {
1264
+ var result = [];
1265
+ for (var i = 0; i < arguments.length; i++) {
1266
+ var element = arguments[i];
1267
+ if (goog.isArray(element)) {
1268
+ result.push.apply(result, goog.array.flatten.apply(null, element));
1269
+ } else {
1270
+ result.push(element);
1271
+ }
1272
+ }
1273
+ return result;
1274
+ };
1275
+
1276
+
1277
+ /**
1278
+ * Rotates an array in-place. After calling this method, the element at
1279
+ * index i will be the element previously at index (i - n) %
1280
+ * array.length, for all values of i between 0 and array.length - 1,
1281
+ * inclusive.
1282
+ *
1283
+ * For example, suppose list comprises [t, a, n, k, s]. After invoking
1284
+ * rotate(array, 1) (or rotate(array, -4)), array will comprise [s, t, a, n, k].
1285
+ *
1286
+ * @param {!Array.<*>} array The array to rotate.
1287
+ * @param {number} n The amount to rotate.
1288
+ * @return {!Array.<*>} The array.
1289
+ */
1290
+ goog.array.rotate = function(array, n) {
1291
+ goog.asserts.assert(array.length != null);
1292
+
1293
+ if (array.length) {
1294
+ n %= array.length;
1295
+ if (n > 0) {
1296
+ goog.array.ARRAY_PROTOTYPE_.unshift.apply(array, array.splice(-n, n));
1297
+ } else if (n < 0) {
1298
+ goog.array.ARRAY_PROTOTYPE_.push.apply(array, array.splice(0, -n));
1299
+ }
1300
+ }
1301
+ return array;
1302
+ };
1303
+
1304
+
1305
+ /**
1306
+ * Creates a new array for which the element at position i is an array of the
1307
+ * ith element of the provided arrays. The returned array will only be as long
1308
+ * as the shortest array provided; additional values are ignored. For example,
1309
+ * the result of zipping [1, 2] and [3, 4, 5] is [[1,3], [2, 4]].
1310
+ *
1311
+ * This is similar to the zip() function in Python. See {@link
1312
+ * http://docs.python.org/library/functions.html#zip}
1313
+ *
1314
+ * @param {...!goog.array.ArrayLike} var_args Arrays to be combined.
1315
+ * @return {!Array.<!Array>} A new array of arrays created from provided arrays.
1316
+ */
1317
+ goog.array.zip = function(var_args) {
1318
+ if (!arguments.length) {
1319
+ return [];
1320
+ }
1321
+ var result = [];
1322
+ for (var i = 0; true; i++) {
1323
+ var value = [];
1324
+ for (var j = 0; j < arguments.length; j++) {
1325
+ var arr = arguments[j];
1326
+ // If i is larger than the array length, this is the shortest array.
1327
+ if (i >= arr.length) {
1328
+ return result;
1329
+ }
1330
+ value.push(arr[i]);
1331
+ }
1332
+ result.push(value);
1333
+ }
1334
+ };
1335
+
1336
+
1337
+ /**
1338
+ * Shuffles the values in the specified array using the Fisher-Yates in-place
1339
+ * shuffle (also known as the Knuth Shuffle). By default, calls Math.random()
1340
+ * and so resets the state of that random number generator. Similarly, may reset
1341
+ * the state of the any other specified random number generator.
1342
+ *
1343
+ * Runtime: O(n)
1344
+ *
1345
+ * @param {!Array} arr The array to be shuffled.
1346
+ * @param {Function=} opt_randFn Optional random function to use for shuffling.
1347
+ * Takes no arguments, and returns a random number on the interval [0, 1).
1348
+ * Defaults to Math.random() using JavaScript's built-in Math library.
1349
+ */
1350
+ goog.array.shuffle = function(arr, opt_randFn) {
1351
+ var randFn = opt_randFn || Math.random;
1352
+
1353
+ for (var i = arr.length - 1; i > 0; i--) {
1354
+ // Choose a random array index in [0, i] (inclusive with i).
1355
+ var j = Math.floor(randFn() * (i + 1));
1356
+
1357
+ var tmp = arr[i];
1358
+ arr[i] = arr[j];
1359
+ arr[j] = tmp;
1360
+ }
1361
+ };
1362
+ ;
1363
+ FI"asset_paths;
1364
+ F["�/Users/ali/.rvm/gems/ruby-1.9.3-p0/bundler/gems/closure-library-wrapper-b30bab11ab83/vendor/closure-library/closure/goog/array/array.jsI"dependency_paths;
1365
+ F[{I" path;
1366
+ F"�/Users/ali/.rvm/gems/ruby-1.9.3-p0/bundler/gems/closure-library-wrapper-b30bab11ab83/vendor/closure-library/closure/goog/array/array.jsI"
1367
+ mtime;
1368
+ FIu: Time
1369
+ T: offsetiI"hexdigest;
1370
+ F"%fc445b29e990f038942b0cffd6d63af2I"
1371
+ F"%46dde6621c301f4928e3b34efee9e3b5