ultimate-base 0.2.3.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ # TODO list
2
+ # * load all locales
3
+
4
+ @I18n ||=
5
+ locale: "en"
6
+ translations: {}
7
+
8
+ t: (path) ->
9
+ path = path.split('.') if _.isString(path)
10
+ scope = @translations
11
+ for step in path
12
+ scope = scope[step]
13
+ return path.join('.') unless scope
14
+ scope
@@ -1,6 +1,6 @@
1
1
  // Underscore.js 1.3.3
2
2
  // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3
- // Underscore is freely distributable under the MIT license.
3
+ // Underscore may be freely distributed under the MIT license.
4
4
  // Portions of Underscore are inspired or borrowed from Prototype,
5
5
  // Oliver Steele's Functional, and John Resig's Micro-Templating.
6
6
  // For all details and documentation:
@@ -24,7 +24,8 @@
24
24
  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
25
25
 
26
26
  // Create quick reference variables for speed access to core prototypes.
27
- var slice = ArrayProto.slice,
27
+ var push = ArrayProto.push,
28
+ slice = ArrayProto.slice,
28
29
  unshift = ArrayProto.unshift,
29
30
  toString = ObjProto.toString,
30
31
  hasOwnProperty = ObjProto.hasOwnProperty;
@@ -76,7 +77,7 @@
76
77
  obj.forEach(iterator, context);
77
78
  } else if (obj.length === +obj.length) {
78
79
  for (var i = 0, l = obj.length; i < l; i++) {
79
- if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
80
+ if (iterator.call(context, obj[i], i, obj) === breaker) return;
80
81
  }
81
82
  } else {
82
83
  for (var key in obj) {
@@ -96,7 +97,6 @@
96
97
  each(obj, function(value, index, list) {
97
98
  results[results.length] = iterator.call(context, value, index, list);
98
99
  });
99
- if (obj.length === +obj.length) results.length = obj.length;
100
100
  return results;
101
101
  };
102
102
 
@@ -213,7 +213,7 @@
213
213
  _.invoke = function(obj, method) {
214
214
  var args = slice.call(arguments, 2);
215
215
  return _.map(obj, function(value) {
216
- return (_.isFunction(method) ? method || value : value[method]).apply(value, args);
216
+ return (_.isFunction(method) ? method : value[method]).apply(value, args);
217
217
  });
218
218
  };
219
219
 
@@ -223,8 +223,12 @@
223
223
  };
224
224
 
225
225
  // Return the maximum element or (element-based computation).
226
+ // Can't optimize arrays of integers longer than 65,535 elements.
227
+ // See: https://bugs.webkit.org/show_bug.cgi?id=80797
226
228
  _.max = function(obj, iterator, context) {
227
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.max.apply(Math, obj);
229
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
230
+ return Math.max.apply(Math, obj);
231
+ }
228
232
  if (!iterator && _.isEmpty(obj)) return -Infinity;
229
233
  var result = {computed : -Infinity};
230
234
  each(obj, function(value, index, list) {
@@ -236,7 +240,9 @@
236
240
 
237
241
  // Return the minimum element (or element-based computation).
238
242
  _.min = function(obj, iterator, context) {
239
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.min.apply(Math, obj);
243
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
244
+ return Math.min.apply(Math, obj);
245
+ }
240
246
  if (!iterator && _.isEmpty(obj)) return Infinity;
241
247
  var result = {computed : Infinity};
242
248
  each(obj, function(value, index, list) {
@@ -248,10 +254,12 @@
248
254
 
249
255
  // Shuffle an array.
250
256
  _.shuffle = function(obj) {
251
- var shuffled = [], rand;
252
- each(obj, function(value, index, list) {
253
- rand = Math.floor(Math.random() * (index + 1));
254
- shuffled[index] = shuffled[rand];
257
+ var rand;
258
+ var index = 0;
259
+ var shuffled = [];
260
+ each(obj, function(value) {
261
+ rand = Math.floor(Math.random() * ++index);
262
+ shuffled[index - 1] = shuffled[rand];
255
263
  shuffled[rand] = value;
256
264
  });
257
265
  return shuffled;
@@ -259,7 +267,7 @@
259
267
 
260
268
  // Sort the object's values by a criterion produced by an iterator.
261
269
  _.sortBy = function(obj, val, context) {
262
- var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
270
+ var iterator = lookupIterator(obj, val);
263
271
  return _.pluck(_.map(obj, function(value, index, list) {
264
272
  return {
265
273
  value : value,
@@ -273,26 +281,49 @@
273
281
  }), 'value');
274
282
  };
275
283
 
276
- // Groups the object's values by a criterion. Pass either a string attribute
277
- // to group by, or a function that returns the criterion.
278
- _.groupBy = function(obj, val) {
284
+ // An internal function to generate lookup iterators.
285
+ var lookupIterator = function(obj, val) {
286
+ return _.isFunction(val) ? val : function(obj) { return obj[val]; };
287
+ };
288
+
289
+ // An internal function used for aggregate "group by" operations.
290
+ var group = function(obj, val, behavior) {
279
291
  var result = {};
280
- var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
292
+ var iterator = lookupIterator(obj, val);
281
293
  each(obj, function(value, index) {
282
294
  var key = iterator(value, index);
283
- (result[key] || (result[key] = [])).push(value);
295
+ behavior(result, key, value);
284
296
  });
285
297
  return result;
286
298
  };
287
299
 
288
- // Use a comparator function to figure out at what index an object should
289
- // be inserted so as to maintain order. Uses binary search.
300
+ // Groups the object's values by a criterion. Pass either a string attribute
301
+ // to group by, or a function that returns the criterion.
302
+ _.groupBy = function(obj, val) {
303
+ return group(obj, val, function(result, key, value) {
304
+ (result[key] || (result[key] = [])).push(value);
305
+ });
306
+ };
307
+
308
+ // Counts instances of an object that group by a certain criterion. Pass
309
+ // either a string attribute to count by, or a function that returns the
310
+ // criterion.
311
+ _.countBy = function(obj, val) {
312
+ return group(obj, val, function(result, key, value) {
313
+ result[key] || (result[key] = 0);
314
+ result[key]++;
315
+ });
316
+ };
317
+
318
+ // Use a comparator function to figure out the smallest index at which
319
+ // an object should be inserted so as to maintain order. Uses binary search.
290
320
  _.sortedIndex = function(array, obj, iterator) {
291
321
  iterator || (iterator = _.identity);
322
+ var value = iterator(obj);
292
323
  var low = 0, high = array.length;
293
324
  while (low < high) {
294
325
  var mid = (low + high) >> 1;
295
- iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
326
+ iterator(array[mid]) < value ? low = mid + 1 : high = mid;
296
327
  }
297
328
  return low;
298
329
  };
@@ -321,7 +352,7 @@
321
352
  return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
322
353
  };
323
354
 
324
- // Returns everything but the last entry of the array. Especcialy useful on
355
+ // Returns everything but the last entry of the array. Especially useful on
325
356
  // the arguments object. Passing **n** will return all the values in
326
357
  // the array, excluding the last N. The **guard** check allows it to work with
327
358
  // `_.map`.
@@ -352,13 +383,21 @@
352
383
  return _.filter(array, function(value){ return !!value; });
353
384
  };
354
385
 
386
+ // Internal implementation of a recursive `flatten` function.
387
+ var flatten = function(input, shallow, output) {
388
+ each(input, function(value) {
389
+ if (_.isArray(value)) {
390
+ shallow ? push.apply(output, value) : flatten(value, shallow, output);
391
+ } else {
392
+ output.push(value);
393
+ }
394
+ });
395
+ return output;
396
+ };
397
+
355
398
  // Return a completely flattened version of an array.
356
399
  _.flatten = function(array, shallow) {
357
- return _.reduce(array, function(memo, value) {
358
- if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
359
- memo[memo.length] = value;
360
- return memo;
361
- }, []);
400
+ return flatten(array, shallow, []);
362
401
  };
363
402
 
364
403
  // Return a version of the array that does not contain the specified value(s).
@@ -372,10 +411,8 @@
372
411
  _.uniq = _.unique = function(array, isSorted, iterator) {
373
412
  var initial = iterator ? _.map(array, iterator) : array;
374
413
  var results = [];
375
- // The `isSorted` flag is irrelevant if the array only contains two elements.
376
- if (array.length < 3) isSorted = true;
377
- _.reduce(initial, function (memo, value, index) {
378
- if (isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) {
414
+ _.reduce(initial, function(memo, value, index) {
415
+ if (isSorted ? (_.last(memo) !== value || !memo.length) : !_.include(memo, value)) {
379
416
  memo.push(value);
380
417
  results.push(array[index]);
381
418
  }
@@ -387,12 +424,12 @@
387
424
  // Produce an array that contains the union: each distinct element from all of
388
425
  // the passed-in arrays.
389
426
  _.union = function() {
390
- return _.uniq(_.flatten(arguments, true));
427
+ return _.uniq(flatten(arguments, true, []));
391
428
  };
392
429
 
393
430
  // Produce an array that contains every item shared between all the
394
- // passed-in arrays. (Aliased as "intersect" for back-compat.)
395
- _.intersection = _.intersect = function(array) {
431
+ // passed-in arrays.
432
+ _.intersection = function(array) {
396
433
  var rest = slice.call(arguments, 1);
397
434
  return _.filter(_.uniq(array), function(item) {
398
435
  return _.every(rest, function(other) {
@@ -404,7 +441,7 @@
404
441
  // Take the difference between one array and a number of other arrays.
405
442
  // Only the elements present in just the first array will remain.
406
443
  _.difference = function(array) {
407
- var rest = _.flatten(slice.call(arguments, 1), true);
444
+ var rest = flatten(slice.call(arguments, 1), true, []);
408
445
  return _.filter(array, function(value){ return !_.include(rest, value); });
409
446
  };
410
447
 
@@ -414,10 +451,22 @@
414
451
  var args = slice.call(arguments);
415
452
  var length = _.max(_.pluck(args, 'length'));
416
453
  var results = new Array(length);
417
- for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
454
+ for (var i = 0; i < length; i++) {
455
+ results[i] = _.pluck(args, "" + i);
456
+ }
418
457
  return results;
419
458
  };
420
459
 
460
+ // Zip together two arrays -- an array of keys and an array of values -- into
461
+ // a single object.
462
+ _.zipObject = function(keys, values) {
463
+ var result = {};
464
+ for (var i = 0, l = keys.length; i < l; i++) {
465
+ result[keys[i]] = values[i];
466
+ }
467
+ return result;
468
+ };
469
+
421
470
  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
422
471
  // we need this function. Return the position of the first occurrence of an
423
472
  // item in an array, or -1 if the item is not included in the array.
@@ -432,7 +481,7 @@
432
481
  return array[i] === item ? i : -1;
433
482
  }
434
483
  if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
435
- for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
484
+ for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
436
485
  return -1;
437
486
  };
438
487
 
@@ -441,7 +490,7 @@
441
490
  if (array == null) return -1;
442
491
  if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
443
492
  var i = array.length;
444
- while (i--) if (i in array && array[i] === item) return i;
493
+ while (i--) if (array[i] === item) return i;
445
494
  return -1;
446
495
  };
447
496
 
@@ -540,10 +589,10 @@
540
589
  if (throttling) {
541
590
  more = true;
542
591
  } else {
592
+ throttling = true;
543
593
  result = func.apply(context, args);
544
594
  }
545
595
  whenDone();
546
- throttling = true;
547
596
  return result;
548
597
  };
549
598
  };
@@ -560,9 +609,10 @@
560
609
  timeout = null;
561
610
  if (!immediate) func.apply(context, args);
562
611
  };
563
- if (immediate && !timeout) func.apply(context, args);
612
+ var callNow = immediate && !timeout;
564
613
  clearTimeout(timeout);
565
614
  timeout = setTimeout(later, wait);
615
+ if (callNow) func.apply(context, args);
566
616
  };
567
617
  };
568
618
 
@@ -604,7 +654,9 @@
604
654
  _.after = function(times, func) {
605
655
  if (times <= 0) return func();
606
656
  return function() {
607
- if (--times < 1) { return func.apply(this, arguments); }
657
+ if (--times < 1) {
658
+ return func.apply(this, arguments);
659
+ }
608
660
  };
609
661
  };
610
662
 
@@ -648,7 +700,7 @@
648
700
  // Return a copy of the object only containing the whitelisted properties.
649
701
  _.pick = function(obj) {
650
702
  var result = {};
651
- each(_.flatten(slice.call(arguments, 1)), function(key) {
703
+ each(flatten(slice.call(arguments, 1), true, []), function(key) {
652
704
  if (key in obj) result[key] = obj[key];
653
705
  });
654
706
  return result;
@@ -678,8 +730,8 @@
678
730
  return obj;
679
731
  };
680
732
 
681
- // Internal recursive comparison function.
682
- function eq(a, b, stack) {
733
+ // Internal recursive comparison function for `isEqual`.
734
+ var eq = function(a, b, stack) {
683
735
  // Identical objects are equal. `0 === -0`, but they aren't identical.
684
736
  // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
685
737
  if (a === b) return a !== 0 || 1 / a == 1 / b;
@@ -764,7 +816,7 @@
764
816
  // Remove the first object from the stack of traversed objects.
765
817
  stack.pop();
766
818
  return result;
767
- }
819
+ };
768
820
 
769
821
  // Perform a deep comparison to check if two objects are equal.
770
822
  _.isEqual = function(a, b) {
@@ -796,31 +848,21 @@
796
848
  return obj === Object(obj);
797
849
  };
798
850
 
799
- // Is a given variable an arguments object?
800
- _.isArguments = function(obj) {
801
- return toString.call(obj) == '[object Arguments]';
802
- };
851
+ // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
852
+ each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
853
+ _['is' + name] = function(obj) {
854
+ return toString.call(obj) == '[object ' + name + ']';
855
+ };
856
+ });
857
+
858
+ // Define a fallback version of the method in browsers (ahem, IE), where
859
+ // there isn't any inspectable "Arguments" type.
803
860
  if (!_.isArguments(arguments)) {
804
861
  _.isArguments = function(obj) {
805
862
  return !!(obj && _.has(obj, 'callee'));
806
863
  };
807
864
  }
808
865
 
809
- // Is a given value a function?
810
- _.isFunction = function(obj) {
811
- return toString.call(obj) == '[object Function]';
812
- };
813
-
814
- // Is a given value a string?
815
- _.isString = function(obj) {
816
- return toString.call(obj) == '[object String]';
817
- };
818
-
819
- // Is a given value a number?
820
- _.isNumber = function(obj) {
821
- return toString.call(obj) == '[object Number]';
822
- };
823
-
824
866
  // Is a given object a finite number?
825
867
  _.isFinite = function(obj) {
826
868
  return _.isNumber(obj) && isFinite(obj);
@@ -837,16 +879,6 @@
837
879
  return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
838
880
  };
839
881
 
840
- // Is a given value a date?
841
- _.isDate = function(obj) {
842
- return toString.call(obj) == '[object Date]';
843
- };
844
-
845
- // Is the given value a regular expression?
846
- _.isRegExp = function(obj) {
847
- return toString.call(obj) == '[object RegExp]';
848
- };
849
-
850
882
  // Is a given value equal to null?
851
883
  _.isNull = function(obj) {
852
884
  return obj === null;
@@ -857,7 +889,8 @@
857
889
  return obj === void 0;
858
890
  };
859
891
 
860
- // Has own property?
892
+ // Shortcut function for checking if an object has a given property directly
893
+ // on itself (in other words, not on a prototype).
861
894
  _.has = function(obj, key) {
862
895
  return hasOwnProperty.call(obj, key);
863
896
  };
@@ -878,13 +911,28 @@
878
911
  };
879
912
 
880
913
  // Run a function **n** times.
881
- _.times = function (n, iterator, context) {
914
+ _.times = function(n, iterator, context) {
882
915
  for (var i = 0; i < n; i++) iterator.call(context, i);
883
916
  };
884
917
 
918
+ // List of HTML entities for escaping.
919
+ var htmlEscapes = {
920
+ '&': '&amp;',
921
+ '<': '&lt;',
922
+ '>': '&gt;',
923
+ '"': '&quot;',
924
+ "'": '&#x27;',
925
+ '/': '&#x2F;'
926
+ };
927
+
928
+ // Regex containing the keys listed immediately above.
929
+ var htmlEscaper = /[&<>"'\/]/g;
930
+
885
931
  // Escape a string for HTML interpolation.
886
932
  _.escape = function(string) {
887
- return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
933
+ return ('' + string).replace(htmlEscaper, function(match) {
934
+ return htmlEscapes[match];
935
+ });
888
936
  };
889
937
 
890
938
  // If the value of the named property is a function then invoke it;
@@ -927,16 +975,16 @@
927
975
  // Certain characters need to be escaped so that they can be put into a
928
976
  // string literal.
929
977
  var escapes = {
930
- '\\': '\\',
931
- "'": "'",
932
- 'r': '\r',
933
- 'n': '\n',
934
- 't': '\t',
935
- 'u2028': '\u2028',
936
- 'u2029': '\u2029'
978
+ '\\': '\\',
979
+ "'": "'",
980
+ r: '\r',
981
+ n: '\n',
982
+ t: '\t',
983
+ u2028: '\u2028',
984
+ u2029: '\u2029'
937
985
  };
938
986
 
939
- for (var p in escapes) escapes[escapes[p]] = p;
987
+ for (var key in escapes) escapes[escapes[key]] = key;
940
988
  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
941
989
  var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g;
942
990
 
@@ -962,20 +1010,20 @@
962
1010
  return '\\' + escapes[match];
963
1011
  })
964
1012
  .replace(settings.escape || noMatch, function(match, code) {
965
- return "'+\n_.escape(" + unescape(code) + ")+\n'";
1013
+ return "'+\n((__t=(" + unescape(code) + "))==null?'':_.escape(__t))+\n'";
966
1014
  })
967
1015
  .replace(settings.interpolate || noMatch, function(match, code) {
968
- return "'+\n(" + unescape(code) + ")+\n'";
1016
+ return "'+\n((__t=(" + unescape(code) + "))==null?'':__t)+\n'";
969
1017
  })
970
1018
  .replace(settings.evaluate || noMatch, function(match, code) {
971
- return "';\n" + unescape(code) + "\n;__p+='";
1019
+ return "';\n" + unescape(code) + "\n__p+='";
972
1020
  }) + "';\n";
973
1021
 
974
1022
  // If a variable is not specified, place data values in local scope.
975
1023
  if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
976
1024
 
977
- source = "var __p='';" +
978
- "var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" +
1025
+ source = "var __t,__p='',__j=Array.prototype.join," +
1026
+ "print=function(){__p+=__j.call(arguments,'')};\n" +
979
1027
  source + "return __p;\n";
980
1028
 
981
1029
  var render = new Function(settings.variable || 'obj', '_', source);
@@ -984,10 +1032,8 @@
984
1032
  return render.call(this, data, _);
985
1033
  };
986
1034
 
987
- // Provide the compiled function source as a convenience for build time
988
- // precompilation.
989
- template.source = 'function(' + (settings.variable || 'obj') + '){\n' +
990
- source + '}';
1035
+ // Provide the compiled function source as a convenience for precompilation.
1036
+ template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
991
1037
 
992
1038
  return template;
993
1039
  };
@@ -1029,11 +1075,10 @@
1029
1075
  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1030
1076
  var method = ArrayProto[name];
1031
1077
  wrapper.prototype[name] = function() {
1032
- var wrapped = this._wrapped;
1033
- method.apply(wrapped, arguments);
1034
- var length = wrapped.length;
1035
- if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];
1036
- return result(wrapped, this._chain);
1078
+ var obj = this._wrapped;
1079
+ method.apply(obj, arguments);
1080
+ if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
1081
+ return result(obj, this._chain);
1037
1082
  };
1038
1083
  });
1039
1084