cornerstone-source 0.1.12 → 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,3 +1,11 @@
1
1
  source :rubygems
2
2
 
3
3
  gemspec
4
+
5
+ group :development do
6
+ gem "middleman", "3.0.11"
7
+ gem "rb-inotify"
8
+ gem "sass"
9
+ gem "therubyracer"
10
+ gem "rake"
11
+ end
data/README.md CHANGED
@@ -1,19 +1,37 @@
1
- Cornerstone.coffee
2
- =======
1
+ Cornerstone
2
+ ===========
3
3
 
4
- Cornerstone is a JavaScript extension library that gives you the core classes you've always wanted. Fully tested and fully documented, Cornerstone runs in any JavaScript environment, from the browser to the server, or even on Xbox Live.
4
+ Cornerstone is a JavaScript extension library that gives you the core classes
5
+ you've always wanted. Fully tested and fully documented, Cornerstone runs in
6
+ any JavaScript environment, from the browser to the server, or even on Xbox
7
+ Live.
5
8
 
6
9
  Array Extensions
7
10
  ----------------
8
11
 
9
- Ruby's core library inspired the Cornerstone `Array` extensions. Staple methods include `each`, `remove`, `select`, and `include`. Fancier methods such as `partition`, `rand`, and `extremes` come in handy during game programming or web application development.
12
+ Ruby's core library inspired the Cornerstone `Array` extensions. Staple
13
+ methods include `each`, `remove`, `select`, and `include`. Fancier methods
14
+ such as `partition`, `rand`, and `extremes` come in handy during game
15
+ programming or web application development.
10
16
 
11
17
  Number Extensions
12
18
  -----------------
13
19
 
14
- JavaScript's `Number` class provides many useful methods, but sometimes leaves us hanging. Cornerstone extends `Number.prototype` with `clamp`, `times`, and `abs`. It also provides the classic utilities `floor`, `ceil`, and `round`. For a little spice, try `primeFactors`, `toColorPart`, or a host of other great methods for approaching and modifying numbers, and see where your imagination takes you.
20
+ JavaScript's `Number` class provides many useful methods, but sometimes leaves
21
+ us hanging. Cornerstone extends `Number.prototype` with `clamp`, `times`, and
22
+ `abs`. It also provides the classic utilities `floor`, `ceil`, and `round`.
23
+ For a little spice, try `primeFactors`, `toColorPart`, or a host of other
24
+ great methods for approaching and modifying numbers, and see where your
25
+ imagination takes you.
15
26
 
16
27
  String Extensions
17
28
  -----------------
18
29
 
19
- Default JavaScript does a lot with `String`, but Cornerstone goes even further. Inspired by the Rails inflector, there are many methods to alter strings, such as `titleize`, `underscore`, and `humanize`. Methods like `parse` and `constantize` are especially powerful for metaprogramming.
30
+ Default JavaScript does a lot with `String`, but Cornerstone goes even
31
+ further. Inspired by the Rails inflector, there are many methods to alter
32
+ strings, such as `titleize`, `underscore`, and `humanize`. Methods like
33
+ `parse` and `constantize` are especially powerful for metaprogramming.
34
+
35
+ Points and Matrices
36
+ -------------------
37
+ You need 'em, we've got 'em!
@@ -13,7 +13,6 @@ Gem::Specification.new do |gem|
13
13
  gem.files = `git ls-files`.split("\n")
14
14
  gem.require_paths = ["lib"]
15
15
 
16
- gem.add_development_dependency "rake"
17
-
16
+ gem.add_dependency "coffee-script"
18
17
  gem.add_dependency "sprockets"
19
18
  end
data/game.js ADDED
@@ -0,0 +1,3331 @@
1
+
2
+
3
+ /**
4
+ Checks whether an object is an array.
5
+
6
+ Object.isArray([1, 2, 4])
7
+ # => true
8
+
9
+ Object.isArray({key: "value"})
10
+ # => false
11
+
12
+ @name isArray
13
+ @methodOf Object
14
+ @param {Object} object The object to check for array-ness.
15
+ @returns {Boolean} A boolean expressing whether the object is an instance of Array
16
+ */
17
+ var __slice = Array.prototype.slice;
18
+
19
+ Object.isArray = function(object) {
20
+ return Object.prototype.toString.call(object) === "[object Array]";
21
+ };
22
+
23
+ /**
24
+ Checks whether an object is a string.
25
+
26
+ Object.isString("a string")
27
+ # => true
28
+
29
+ Object.isString([1, 2, 4])
30
+ # => false
31
+
32
+ Object.isString({key: "value"})
33
+ # => false
34
+
35
+ @name isString
36
+ @methodOf Object
37
+ @param {Object} object The object to check for string-ness.
38
+ @returns {Boolean} A boolean expressing whether the object is an instance of String
39
+ */
40
+
41
+ Object.isString = function(object) {
42
+ return Object.prototype.toString.call(object) === "[object String]";
43
+ };
44
+
45
+ /**
46
+ Merges properties from objects into target without overiding.
47
+ First come, first served.
48
+
49
+ I =
50
+ a: 1
51
+ b: 2
52
+ c: 3
53
+
54
+ Object.reverseMerge I,
55
+ c: 6
56
+ d: 4
57
+
58
+ I # => {a: 1, b:2, c:3, d: 4}
59
+
60
+ @name reverseMerge
61
+ @methodOf Object
62
+ @param {Object} target The object to merge the properties into.
63
+ @returns {Object} target
64
+ */
65
+
66
+ Object.defaults = Object.reverseMerge = function() {
67
+ var name, object, objects, target, _i, _len;
68
+ target = arguments[0], objects = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
69
+ for (_i = 0, _len = objects.length; _i < _len; _i++) {
70
+ object = objects[_i];
71
+ for (name in object) {
72
+ if (!target.hasOwnProperty(name)) target[name] = object[name];
73
+ }
74
+ }
75
+ return target;
76
+ };
77
+
78
+ /**
79
+ Merges properties from sources into target with overiding.
80
+ Last in covers earlier properties.
81
+
82
+ I =
83
+ a: 1
84
+ b: 2
85
+ c: 3
86
+
87
+ Object.extend I,
88
+ c: 6
89
+ d: 4
90
+
91
+ I # => {a: 1, b:2, c:6, d: 4}
92
+
93
+ @name extend
94
+ @methodOf Object
95
+ @param {Object} target The object to merge the properties into.
96
+ @returns {Object} target
97
+ */
98
+
99
+ Object.extend = function() {
100
+ var name, source, sources, target, _i, _len;
101
+ target = arguments[0], sources = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
102
+ for (_i = 0, _len = sources.length; _i < _len; _i++) {
103
+ source = sources[_i];
104
+ for (name in source) {
105
+ target[name] = source[name];
106
+ }
107
+ }
108
+ return target;
109
+ };
110
+
111
+ /**
112
+ Helper method that tells you if something is an object.
113
+
114
+ object = {a: 1}
115
+
116
+ Object.isObject(object)
117
+ # => true
118
+
119
+ @name isObject
120
+ @methodOf Object
121
+ @param {Object} object Maybe this guy is an object.
122
+ @returns {Boolean} true if this guy is an object.
123
+ */
124
+
125
+ Object.isObject = function(object) {
126
+ return Object.prototype.toString.call(object) === '[object Object]';
127
+ };
128
+
129
+ /**
130
+ Calculate the average value of an array. Returns undefined if some elements
131
+ are not numbers.
132
+
133
+ [1, 3, 5, 7].average()
134
+ # => 4
135
+
136
+ @name average
137
+ @methodOf Array#
138
+ @returns {Number} The average (arithmetic mean) of the list of numbers.
139
+ */
140
+ var _base,
141
+ __slice = Array.prototype.slice;
142
+
143
+ Array.prototype.average = function() {
144
+ return this.sum() / this.length;
145
+ };
146
+
147
+ /**
148
+ Returns a copy of the array without null and undefined values.
149
+
150
+ [null, undefined, 3, 3, undefined, 5].compact()
151
+ # => [3, 3, 5]
152
+
153
+ @name compact
154
+ @methodOf Array#
155
+ @returns {Array} A new array that contains only the non-null values.
156
+ */
157
+
158
+ Array.prototype.compact = function() {
159
+ return this.select(function(element) {
160
+ return element != null;
161
+ });
162
+ };
163
+
164
+ /**
165
+ Creates and returns a copy of the array. The copy contains
166
+ the same objects.
167
+
168
+ a = ["a", "b", "c"]
169
+ b = a.copy()
170
+
171
+ # their elements are equal
172
+ a[0] == b[0] && a[1] == b[1] && a[2] == b[2]
173
+ # => true
174
+
175
+ # but they aren't the same object in memory
176
+ a === b
177
+ # => false
178
+
179
+ @name copy
180
+ @methodOf Array#
181
+ @returns {Array} A new array that is a copy of the array
182
+ */
183
+
184
+ Array.prototype.copy = function() {
185
+ return this.concat();
186
+ };
187
+
188
+ /**
189
+ Empties the array of its contents. It is modified in place.
190
+
191
+ fullArray = [1, 2, 3]
192
+ fullArray.clear()
193
+ fullArray
194
+ # => []
195
+
196
+ @name clear
197
+ @methodOf Array#
198
+ @returns {Array} this, now emptied.
199
+ */
200
+
201
+ Array.prototype.clear = function() {
202
+ this.length = 0;
203
+ return this;
204
+ };
205
+
206
+ /**
207
+ Flatten out an array of arrays into a single array of elements.
208
+
209
+ [[1, 2], [3, 4], 5].flatten()
210
+ # => [1, 2, 3, 4, 5]
211
+
212
+ # won't flatten twice nested arrays. call
213
+ # flatten twice if that is what you want
214
+ [[1, 2], [3, [4, 5]], 6].flatten()
215
+ # => [1, 2, 3, [4, 5], 6]
216
+
217
+ @name flatten
218
+ @methodOf Array#
219
+ @returns {Array} A new array with all the sub-arrays flattened to the top.
220
+ */
221
+
222
+ Array.prototype.flatten = function() {
223
+ return this.inject([], function(a, b) {
224
+ return a.concat(b);
225
+ });
226
+ };
227
+
228
+ /**
229
+ Invoke the named method on each element in the array
230
+ and return a new array containing the results of the invocation.
231
+
232
+ [1.1, 2.2, 3.3, 4.4].invoke("floor")
233
+ # => [1, 2, 3, 4]
234
+
235
+ ['hello', 'world', 'cool!'].invoke('substring', 0, 3)
236
+ # => ['hel', 'wor', 'coo']
237
+
238
+ @param {String} method The name of the method to invoke.
239
+ @param [arg...] Optional arguments to pass to the method being invoked.
240
+ @name invoke
241
+ @methodOf Array#
242
+ @returns {Array} A new array containing the results of invoking the named method on each element.
243
+ */
244
+
245
+ Array.prototype.invoke = function() {
246
+ var args, method;
247
+ method = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
248
+ return this.map(function(element) {
249
+ return element[method].apply(element, args);
250
+ });
251
+ };
252
+
253
+ /**
254
+ Randomly select an element from the array.
255
+
256
+ [1, 2, 3].rand()
257
+ # => 2
258
+
259
+ @name rand
260
+ @methodOf Array#
261
+ @returns {Object} A random element from an array
262
+ */
263
+
264
+ Array.prototype.rand = function() {
265
+ return this[rand(this.length)];
266
+ };
267
+
268
+ /**
269
+ Remove the first occurrence of the given object from the array if it is
270
+ present. The array is modified in place.
271
+
272
+ a = [1, 1, "a", "b"]
273
+ a.remove(1)
274
+ # => 1
275
+
276
+ a
277
+ # => [1, "a", "b"]
278
+
279
+ @name remove
280
+ @methodOf Array#
281
+ @param {Object} object The object to remove from the array if present.
282
+ @returns {Object} The removed object if present otherwise undefined.
283
+ */
284
+
285
+ Array.prototype.remove = function(object) {
286
+ var index;
287
+ index = this.indexOf(object);
288
+ if (index >= 0) {
289
+ return this.splice(index, 1)[0];
290
+ } else {
291
+ return;
292
+ }
293
+ };
294
+
295
+ /**
296
+ Returns true if the element is present in the array.
297
+
298
+ ["a", "b", "c"].include("c")
299
+ # => true
300
+
301
+ [40, "a"].include(700)
302
+ # => false
303
+
304
+ @name include
305
+ @methodOf Array#
306
+ @param {Object} element The element to check if present.
307
+ @returns {Boolean} true if the element is in the array, false otherwise.
308
+ */
309
+
310
+ Array.prototype.include = function(element) {
311
+ return this.indexOf(element) !== -1;
312
+ };
313
+
314
+ /**
315
+ Call the given iterator once for each element in the array,
316
+ passing in the element as the first argument, the index of
317
+ the element as the second argument, and <code>this</code> array as the
318
+ third argument.
319
+
320
+ word = ""
321
+ indices = []
322
+ ["r", "a", "d"].each (letter, index) ->
323
+ word += letter
324
+ indices.push(index)
325
+
326
+ # => ["r", "a", "d"]
327
+
328
+ word
329
+ # => "rad"
330
+
331
+ indices
332
+ # => [0, 1, 2]
333
+
334
+ @name each
335
+ @methodOf Array#
336
+ @param {Function} iterator Function to be called once for each element in the array.
337
+ @param {Object} [context] Optional context parameter to be used as `this` when calling the iterator function.
338
+ @returns {Array} this to enable method chaining.
339
+ */
340
+
341
+ Array.prototype.each = function(iterator, context) {
342
+ var element, i, _len;
343
+ if (this.forEach) {
344
+ this.forEach(iterator, context);
345
+ } else {
346
+ for (i = 0, _len = this.length; i < _len; i++) {
347
+ element = this[i];
348
+ iterator.call(context, element, i, this);
349
+ }
350
+ }
351
+ return this;
352
+ };
353
+
354
+ /**
355
+ Call the given iterator once for each element in the array,
356
+ passing in the element as the first argument, the index of
357
+ the element as the second argument, and `this` array as the
358
+ third argument.
359
+
360
+ [1, 2, 3].map (number) ->
361
+ number * number
362
+ # => [1, 4, 9]
363
+
364
+ @name map
365
+ @methodOf Array#
366
+ @param {Function} iterator Function to be called once for each element in the array.
367
+ @param {Object} [context] Optional context parameter to be used as `this` when calling the iterator function.
368
+ @returns {Array} An array of the results of the iterator function being called on the original array elements.
369
+ */
370
+
371
+ (_base = Array.prototype).map || (_base.map = function(iterator, context) {
372
+ var element, i, results, _len;
373
+ results = [];
374
+ for (i = 0, _len = this.length; i < _len; i++) {
375
+ element = this[i];
376
+ results.push(iterator.call(context, element, i, this));
377
+ }
378
+ return results;
379
+ });
380
+
381
+ /**
382
+ Call the given iterator once for each pair of objects in the array.
383
+
384
+ [1, 2, 3, 4].eachPair (a, b) ->
385
+ # 1, 2
386
+ # 1, 3
387
+ # 1, 4
388
+ # 2, 3
389
+ # 2, 4
390
+ # 3, 4
391
+
392
+ @name eachPair
393
+ @methodOf Array#
394
+ @param {Function} iterator Function to be called once for each pair of elements in the array.
395
+ @param {Object} [context] Optional context parameter to be used as `this` when calling the iterator function.
396
+ */
397
+
398
+ Array.prototype.eachPair = function(iterator, context) {
399
+ var a, b, i, j, length, _results;
400
+ length = this.length;
401
+ i = 0;
402
+ _results = [];
403
+ while (i < length) {
404
+ a = this[i];
405
+ j = i + 1;
406
+ i += 1;
407
+ _results.push((function() {
408
+ var _results2;
409
+ _results2 = [];
410
+ while (j < length) {
411
+ b = this[j];
412
+ j += 1;
413
+ _results2.push(iterator.call(context, a, b));
414
+ }
415
+ return _results2;
416
+ }).call(this));
417
+ }
418
+ return _results;
419
+ };
420
+
421
+ /**
422
+ Call the given iterator once for each element in the array,
423
+ passing in the element as the first argument and the given object
424
+ as the second argument. Additional arguments are passed similar to
425
+ <code>each</code>.
426
+
427
+ @see Array#each
428
+ @name eachWithObject
429
+ @methodOf Array#
430
+ @param {Object} object The object to pass to the iterator on each visit.
431
+ @param {Function} iterator Function to be called once for each element in the array.
432
+ @param {Object} [context] Optional context parameter to be used as `this` when calling the iterator function.
433
+ @returns {Array} this
434
+ */
435
+
436
+ Array.prototype.eachWithObject = function(object, iterator, context) {
437
+ this.each(function(element, i, self) {
438
+ return iterator.call(context, element, object, i, self);
439
+ });
440
+ return object;
441
+ };
442
+
443
+ /**
444
+ Call the given iterator once for each group of elements in the array,
445
+ passing in the elements in groups of n. Additional argumens are
446
+ passed as in each.
447
+
448
+ results = []
449
+ [1, 2, 3, 4].eachSlice 2, (slice) ->
450
+ results.push(slice)
451
+ # => [1, 2, 3, 4]
452
+
453
+ results
454
+ # => [[1, 2], [3, 4]]
455
+
456
+ @see Array#each
457
+ @name eachSlice
458
+ @methodOf Array#
459
+ @param {Number} n The number of elements in each group.
460
+ @param {Function} iterator Function to be called once for each group of elements in the array.
461
+ @param {Object} [context] Optional context parameter to be used as `this` when calling the iterator function.
462
+ @returns {Array} this
463
+ */
464
+
465
+ Array.prototype.eachSlice = function(n, iterator, context) {
466
+ var i, len;
467
+ if (n > 0) {
468
+ len = (this.length / n).floor();
469
+ i = -1;
470
+ while (++i < len) {
471
+ iterator.call(context, this.slice(i * n, (i + 1) * n), i * n, this);
472
+ }
473
+ }
474
+ return this;
475
+ };
476
+
477
+ /**
478
+ Pipe the input through each function in the array in turn. For example, if you have a
479
+ list of objects you can perform a series of selection, sorting, and other processing
480
+ methods and then receive the processed list. This array must contain functions that
481
+ accept a single input and return the processed input. The output of the first function
482
+ is fed to the input of the second and so on until the final processed output is returned.
483
+
484
+ @name pipeline
485
+ @methodOf Array#
486
+
487
+ @param {Object} input The initial input to pass to the first function in the pipeline.
488
+ @returns {Object} The result of processing the input by each function in the array.
489
+ */
490
+
491
+ Array.prototype.pipeline = function(input) {
492
+ var fn, _i, _len;
493
+ for (_i = 0, _len = this.length; _i < _len; _i++) {
494
+ fn = this[_i];
495
+ input = fn(input);
496
+ }
497
+ return input;
498
+ };
499
+
500
+ /**
501
+ Returns a new array with the elements all shuffled up.
502
+
503
+ a = [1, 2, 3]
504
+
505
+ a.shuffle()
506
+ # => [2, 3, 1]
507
+
508
+ a # => [1, 2, 3]
509
+
510
+ @name shuffle
511
+ @methodOf Array#
512
+ @returns {Array} A new array that is randomly shuffled.
513
+ */
514
+
515
+ Array.prototype.shuffle = function() {
516
+ var shuffledArray;
517
+ shuffledArray = [];
518
+ this.each(function(element) {
519
+ return shuffledArray.splice(rand(shuffledArray.length + 1), 0, element);
520
+ });
521
+ return shuffledArray;
522
+ };
523
+
524
+ /**
525
+ Returns the first element of the array, undefined if the array is empty.
526
+
527
+ ["first", "second", "third"].first()
528
+ # => "first"
529
+
530
+ @name first
531
+ @methodOf Array#
532
+ @returns {Object} The first element, or undefined if the array is empty.
533
+ */
534
+
535
+ Array.prototype.first = function() {
536
+ return this[0];
537
+ };
538
+
539
+ /**
540
+ Returns the last element of the array, undefined if the array is empty.
541
+
542
+ ["first", "second", "third"].last()
543
+ # => "third"
544
+
545
+ @name last
546
+ @methodOf Array#
547
+ @returns {Object} The last element, or undefined if the array is empty.
548
+ */
549
+
550
+ Array.prototype.last = function() {
551
+ return this[this.length - 1];
552
+ };
553
+
554
+ /**
555
+ Returns an object containing the extremes of this array.
556
+
557
+ [-1, 3, 0].extremes()
558
+ # => {min: -1, max: 3}
559
+
560
+ @name extremes
561
+ @methodOf Array#
562
+ @param {Function} [fn] An optional funtion used to evaluate each element to calculate its value for determining extremes.
563
+ @returns {Object} {min: minElement, max: maxElement}
564
+ */
565
+
566
+ Array.prototype.extremes = function(fn) {
567
+ var max, maxResult, min, minResult;
568
+ if (fn == null) fn = Function.identity;
569
+ min = max = void 0;
570
+ minResult = maxResult = void 0;
571
+ this.each(function(object) {
572
+ var result;
573
+ result = fn(object);
574
+ if (min != null) {
575
+ if (result < minResult) {
576
+ min = object;
577
+ minResult = result;
578
+ }
579
+ } else {
580
+ min = object;
581
+ minResult = result;
582
+ }
583
+ if (max != null) {
584
+ if (result > maxResult) {
585
+ max = object;
586
+ return maxResult = result;
587
+ }
588
+ } else {
589
+ max = object;
590
+ return maxResult = result;
591
+ }
592
+ });
593
+ return {
594
+ min: min,
595
+ max: max
596
+ };
597
+ };
598
+
599
+ Array.prototype.maxima = function(valueFunction) {
600
+ if (valueFunction == null) valueFunction = Function.identity;
601
+ return this.inject([-Infinity, []], function(memo, item) {
602
+ var maxItems, maxValue, value;
603
+ value = valueFunction(item);
604
+ maxValue = memo[0], maxItems = memo[1];
605
+ if (value > maxValue) {
606
+ return [value, [item]];
607
+ } else if (value === maxValue) {
608
+ return [value, maxItems.concat(item)];
609
+ } else {
610
+ return memo;
611
+ }
612
+ }).last();
613
+ };
614
+
615
+ Array.prototype.maximum = function(valueFunction) {
616
+ return this.maxima(valueFunction).first();
617
+ };
618
+
619
+ Array.prototype.minima = function(valueFunction) {
620
+ var inverseFn;
621
+ if (valueFunction == null) valueFunction = Function.identity;
622
+ inverseFn = function(x) {
623
+ return -valueFunction(x);
624
+ };
625
+ return this.maxima(inverseFn);
626
+ };
627
+
628
+ Array.prototype.minimum = function(valueFunction) {
629
+ return this.minima(valueFunction).first();
630
+ };
631
+
632
+ /**
633
+ Pretend the array is a circle and grab a new array containing length elements.
634
+ If length is not given return the element at start, again assuming the array
635
+ is a circle.
636
+
637
+ [1, 2, 3].wrap(-1)
638
+ # => 3
639
+
640
+ [1, 2, 3].wrap(6)
641
+ # => 1
642
+
643
+ ["l", "o", "o", "p"].wrap(0, 16)
644
+ # => ["l", "o", "o", "p", "l", "o", "o", "p", "l", "o", "o", "p", "l", "o", "o", "p"]
645
+
646
+ @name wrap
647
+ @methodOf Array#
648
+ @param {Number} start The index to start wrapping at, or the index of the sole element to return if no length is given.
649
+ @param {Number} [length] Optional length determines how long result array should be.
650
+ @returns {Object} or {Array} The element at start mod array.length, or an array of length elements, starting from start and wrapping.
651
+ */
652
+
653
+ Array.prototype.wrap = function(start, length) {
654
+ var end, i, result;
655
+ if (length != null) {
656
+ end = start + length;
657
+ i = start;
658
+ result = [];
659
+ while (i < end) {
660
+ result.push(this[i.mod(this.length)]);
661
+ i += 1;
662
+ }
663
+ return result;
664
+ } else {
665
+ return this[start.mod(this.length)];
666
+ }
667
+ };
668
+
669
+ /**
670
+ Partitions the elements into two groups: those for which the iterator returns
671
+ true, and those for which it returns false.
672
+
673
+ [evens, odds] = [1, 2, 3, 4].partition (n) ->
674
+ n.even()
675
+
676
+ evens
677
+ # => [2, 4]
678
+
679
+ odds
680
+ # => [1, 3]
681
+
682
+ @name partition
683
+ @methodOf Array#
684
+ @param {Function} iterator
685
+ @param {Object} [context] Optional context parameter to be used as `this` when calling the iterator function.
686
+ @returns {Array} An array in the form of [trueCollection, falseCollection]
687
+ */
688
+
689
+ Array.prototype.partition = function(iterator, context) {
690
+ var falseCollection, trueCollection;
691
+ trueCollection = [];
692
+ falseCollection = [];
693
+ this.each(function(element) {
694
+ if (iterator.call(context, element)) {
695
+ return trueCollection.push(element);
696
+ } else {
697
+ return falseCollection.push(element);
698
+ }
699
+ });
700
+ return [trueCollection, falseCollection];
701
+ };
702
+
703
+ /**
704
+ Return the group of elements for which the return value of the iterator is true.
705
+
706
+ @name select
707
+ @methodOf Array#
708
+ @param {Function} iterator The iterator receives each element in turn as the first agument.
709
+ @param {Object} [context] Optional context parameter to be used as `this` when calling the iterator function.
710
+ @returns {Array} An array containing the elements for which the iterator returned true.
711
+ */
712
+
713
+ Array.prototype.select = function(iterator, context) {
714
+ return this.partition(iterator, context)[0];
715
+ };
716
+
717
+ /**
718
+ Return the group of elements that are not in the passed in set.
719
+
720
+ [1, 2, 3, 4].without ([2, 3])
721
+ # => [1, 4]
722
+
723
+ @name without
724
+ @methodOf Array#
725
+ @param {Array} values List of elements to exclude.
726
+ @returns {Array} An array containing the elements that are not passed in.
727
+ */
728
+
729
+ Array.prototype.without = function(values) {
730
+ return this.reject(function(element) {
731
+ return values.include(element);
732
+ });
733
+ };
734
+
735
+ /**
736
+ Return the group of elements for which the return value of the iterator is false.
737
+
738
+ @name reject
739
+ @methodOf Array#
740
+ @param {Function} iterator The iterator receives each element in turn as the first agument.
741
+ @param {Object} [context] Optional context parameter to be used as `this` when calling the iterator function.
742
+ @returns {Array} An array containing the elements for which the iterator returned false.
743
+ */
744
+
745
+ Array.prototype.reject = function(iterator, context) {
746
+ return this.partition(iterator, context)[1];
747
+ };
748
+
749
+ /**
750
+ Combines all elements of the array by applying a binary operation.
751
+ for each element in the arra the iterator is passed an accumulator
752
+ value (memo) and the element.
753
+
754
+ @name inject
755
+ @methodOf Array#
756
+ @returns {Object} The result of a
757
+ */
758
+
759
+ Array.prototype.inject = function(initial, iterator) {
760
+ this.each(function(element) {
761
+ return initial = iterator(initial, element);
762
+ });
763
+ return initial;
764
+ };
765
+
766
+ /**
767
+ Add all the elements in the array.
768
+
769
+ [1, 2, 3, 4].sum()
770
+ # => 10
771
+
772
+ @name sum
773
+ @methodOf Array#
774
+ @returns {Number} The sum of the elements in the array.
775
+ */
776
+
777
+ Array.prototype.sum = function() {
778
+ return this.inject(0, function(sum, n) {
779
+ return sum + n;
780
+ });
781
+ };
782
+
783
+ /**
784
+ Multiply all the elements in the array.
785
+
786
+ [1, 2, 3, 4].product()
787
+ # => 24
788
+
789
+ @name product
790
+ @methodOf Array#
791
+ @returns {Number} The product of the elements in the array.
792
+ */
793
+
794
+ Array.prototype.product = function() {
795
+ return this.inject(1, function(product, n) {
796
+ return product * n;
797
+ });
798
+ };
799
+
800
+ /**
801
+ Merges together the values of each of the arrays with the values at the corresponding position.
802
+
803
+ ['a', 'b', 'c'].zip([1, 2, 3])
804
+ # => [['a', 1], ['b', 2], ['c', 3]]
805
+
806
+ @name zip
807
+ @methodOf Array#
808
+ @returns {Array} Array groupings whose values are arranged by their positions in the original input arrays.
809
+ */
810
+
811
+ Array.prototype.zip = function() {
812
+ var args;
813
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
814
+ return this.map(function(element, index) {
815
+ var output;
816
+ output = args.map(function(arr) {
817
+ return arr[index];
818
+ });
819
+ output.unshift(element);
820
+ return output;
821
+ });
822
+ };
823
+
824
+ /**
825
+ Bindable module.
826
+
827
+ player = Core
828
+ x: 5
829
+ y: 10
830
+
831
+ player.bind "update", ->
832
+ updatePlayer()
833
+ # => Uncaught TypeError: Object has no method 'bind'
834
+
835
+ player.include(Bindable)
836
+
837
+ player.bind "update", ->
838
+ updatePlayer()
839
+ # => this will call updatePlayer each time through the main loop
840
+
841
+ @name Bindable
842
+ @module
843
+ @constructor
844
+ */
845
+ var Bindable,
846
+ __slice = Array.prototype.slice;
847
+
848
+ Bindable = function(I, self) {
849
+ var eventCallbacks;
850
+ if (I == null) I = {};
851
+ eventCallbacks = {};
852
+ return {
853
+ bind: function() {
854
+ var args;
855
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
856
+ return self.on.apply(self, args);
857
+ },
858
+ unbind: function() {
859
+ var args;
860
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
861
+ return self.off.apply(self, args);
862
+ },
863
+ /**
864
+ Adds a function as an event listener.
865
+
866
+ # this will call coolEventHandler after
867
+ # yourObject.trigger "someCustomEvent" is called.
868
+ yourObject.on "someCustomEvent", coolEventHandler
869
+
870
+ #or
871
+ yourObject.on "anotherCustomEvent", ->
872
+ doSomething()
873
+
874
+ @name on
875
+ @methodOf Bindable#
876
+ @param {String} event The event to listen to.
877
+ @param {Function} callback The function to be called when the specified event
878
+ is triggered.
879
+ */
880
+ on: function(namespacedEvent, callback) {
881
+ var event, namespace, _ref;
882
+ _ref = namespacedEvent.split("."), event = _ref[0], namespace = _ref[1];
883
+ if (namespace) {
884
+ callback.__PIXIE || (callback.__PIXIE = {});
885
+ callback.__PIXIE[namespace] = true;
886
+ }
887
+ eventCallbacks[event] || (eventCallbacks[event] = []);
888
+ eventCallbacks[event].push(callback);
889
+ return this;
890
+ },
891
+ /**
892
+ Removes a specific event listener, or all event listeners if
893
+ no specific listener is given.
894
+
895
+ # removes the handler coolEventHandler from the event
896
+ # "someCustomEvent" while leaving the other events intact.
897
+ yourObject.off "someCustomEvent", coolEventHandler
898
+
899
+ # removes all handlers attached to "anotherCustomEvent"
900
+ yourObject.off "anotherCustomEvent"
901
+
902
+ @name off
903
+ @methodOf Bindable#
904
+ @param {String} event The event to remove the listener from.
905
+ @param {Function} [callback] The listener to remove.
906
+ */
907
+ off: function(namespacedEvent, callback) {
908
+ var callbacks, event, key, namespace, _ref;
909
+ _ref = namespacedEvent.split("."), event = _ref[0], namespace = _ref[1];
910
+ if (event) {
911
+ eventCallbacks[event] || (eventCallbacks[event] = []);
912
+ if (namespace) {
913
+ eventCallbacks[event] = eventCallbacks.select(function(callback) {
914
+ var _ref2;
915
+ return !(((_ref2 = callback.__PIXIE) != null ? _ref2[namespace] : void 0) != null);
916
+ });
917
+ } else {
918
+ if (callback) {
919
+ eventCallbacks[event].remove(callback);
920
+ } else {
921
+ eventCallbacks[event] = [];
922
+ }
923
+ }
924
+ } else if (namespace) {
925
+ for (key in eventCallbacks) {
926
+ callbacks = eventCallbacks[key];
927
+ eventCallbacks[key] = callbacks.select(function(callback) {
928
+ var _ref2;
929
+ return !(((_ref2 = callback.__PIXIE) != null ? _ref2[namespace] : void 0) != null);
930
+ });
931
+ }
932
+ }
933
+ return this;
934
+ },
935
+ /**
936
+ Calls all listeners attached to the specified event.
937
+
938
+ # calls each event handler bound to "someCustomEvent"
939
+ yourObject.trigger "someCustomEvent"
940
+
941
+ @name trigger
942
+ @methodOf Bindable#
943
+ @param {String} event The event to trigger.
944
+ @param {Array} [parameters] Additional parameters to pass to the event listener.
945
+ */
946
+ trigger: function() {
947
+ var callbacks, event, parameters;
948
+ event = arguments[0], parameters = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
949
+ callbacks = eventCallbacks[event];
950
+ if (callbacks && callbacks.length) {
951
+ self = this;
952
+ return callbacks.each(function(callback) {
953
+ return callback.apply(self, parameters);
954
+ });
955
+ }
956
+ }
957
+ };
958
+ };
959
+
960
+ (typeof exports !== "undefined" && exports !== null ? exports : this)["Bindable"] = Bindable;
961
+
962
+ var CommandStack;
963
+
964
+ CommandStack = function() {
965
+ var index, stack;
966
+ stack = [];
967
+ index = 0;
968
+ return {
969
+ execute: function(command) {
970
+ stack[index] = command;
971
+ command.execute();
972
+ return stack.length = index += 1;
973
+ },
974
+ undo: function() {
975
+ var command;
976
+ if (this.canUndo()) {
977
+ index -= 1;
978
+ command = stack[index];
979
+ command.undo();
980
+ return command;
981
+ }
982
+ },
983
+ redo: function() {
984
+ var command;
985
+ if (this.canRedo()) {
986
+ command = stack[index];
987
+ command.execute();
988
+ index += 1;
989
+ return command;
990
+ }
991
+ },
992
+ current: function() {
993
+ return stack[index - 1];
994
+ },
995
+ canUndo: function() {
996
+ return index > 0;
997
+ },
998
+ canRedo: function() {
999
+ return stack[index] != null;
1000
+ }
1001
+ };
1002
+ };
1003
+
1004
+ (typeof exports !== "undefined" && exports !== null ? exports : this)["CommandStack"] = CommandStack;
1005
+
1006
+ /**
1007
+ The Core class is used to add extended functionality to objects without
1008
+ extending the object class directly. Inherit from Core to gain its utility
1009
+ methods.
1010
+
1011
+ @name Core
1012
+ @constructor
1013
+
1014
+ @param {Object} I Instance variables
1015
+ */
1016
+ var __slice = Array.prototype.slice;
1017
+
1018
+ (function() {
1019
+ var root;
1020
+ root = typeof exports !== "undefined" && exports !== null ? exports : this;
1021
+ return root.Core = function(I) {
1022
+ var Module, moduleName, self, _i, _len, _ref;
1023
+ if (I == null) I = {};
1024
+ Object.reverseMerge(I, {
1025
+ includedModules: []
1026
+ });
1027
+ self = {
1028
+ /**
1029
+ External access to instance variables. Use of this property should be avoided
1030
+ in general, but can come in handy from time to time.
1031
+
1032
+ I =
1033
+ r: 255
1034
+ g: 0
1035
+ b: 100
1036
+
1037
+ myObject = Core(I)
1038
+
1039
+ # a bad idea most of the time, but it's
1040
+ # pretty convenient to have available.
1041
+ myObject.I.r
1042
+ # => 255
1043
+
1044
+ myObject.I.g
1045
+ # => 0
1046
+
1047
+ myObject.I.b
1048
+ # => 100
1049
+
1050
+ @name I
1051
+ @fieldOf Core#
1052
+ */
1053
+ I: I,
1054
+ /**
1055
+ Generates a public jQuery style getter / setter method for each
1056
+ String argument.
1057
+
1058
+ myObject = Core
1059
+ r: 255
1060
+ g: 0
1061
+ b: 100
1062
+
1063
+ myObject.attrAccessor "r", "g", "b"
1064
+
1065
+ myObject.r(254)
1066
+ myObject.r()
1067
+
1068
+ => 254
1069
+
1070
+ @name attrAccessor
1071
+ @methodOf Core#
1072
+ */
1073
+ attrAccessor: function() {
1074
+ var attrNames;
1075
+ attrNames = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1076
+ return attrNames.each(function(attrName) {
1077
+ return self[attrName] = function(newValue) {
1078
+ if (newValue != null) {
1079
+ I[attrName] = newValue;
1080
+ return self;
1081
+ } else {
1082
+ return I[attrName];
1083
+ }
1084
+ };
1085
+ });
1086
+ },
1087
+ /**
1088
+ Generates a public jQuery style getter method for each String argument.
1089
+
1090
+ myObject = Core
1091
+ r: 255
1092
+ g: 0
1093
+ b: 100
1094
+
1095
+ myObject.attrReader "r", "g", "b"
1096
+
1097
+ myObject.r()
1098
+ => 255
1099
+
1100
+ myObject.g()
1101
+ => 0
1102
+
1103
+ myObject.b()
1104
+ => 100
1105
+
1106
+ @name attrReader
1107
+ @methodOf Core#
1108
+ */
1109
+ attrReader: function() {
1110
+ var attrNames;
1111
+ attrNames = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1112
+ return attrNames.each(function(attrName) {
1113
+ return self[attrName] = function() {
1114
+ return I[attrName];
1115
+ };
1116
+ });
1117
+ },
1118
+ /**
1119
+ Extends this object with methods from the passed in object. A shortcut for Object.extend(self, methods)
1120
+
1121
+ I =
1122
+ x: 30
1123
+ y: 40
1124
+ maxSpeed: 5
1125
+
1126
+ # we are using extend to give player
1127
+ # additional methods that Core doesn't have
1128
+ player = Core(I).extend
1129
+ increaseSpeed: ->
1130
+ I.maxSpeed += 1
1131
+
1132
+ player.I.maxSpeed
1133
+ => 5
1134
+
1135
+ player.increaseSpeed()
1136
+
1137
+ player.I.maxSpeed
1138
+ => 6
1139
+
1140
+ @name extend
1141
+ @methodOf Core#
1142
+ @see Object.extend
1143
+ @returns self
1144
+ */
1145
+ extend: function(options) {
1146
+ Object.extend(self, options);
1147
+ return self;
1148
+ },
1149
+ /**
1150
+ Includes a module in this object.
1151
+
1152
+ myObject = Core()
1153
+ myObject.include(Bindable)
1154
+
1155
+ # now you can bind handlers to functions
1156
+ myObject.bind "someEvent", ->
1157
+ alert("wow. that was easy.")
1158
+
1159
+ @name include
1160
+ @methodOf Core#
1161
+ @param {String} Module the module to include. A module is a constructor that takes two parameters, I and self, and returns an object containing the public methods to extend the including object with.
1162
+ */
1163
+ include: function() {
1164
+ var Module, key, moduleName, modules, value, _i, _len;
1165
+ modules = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1166
+ for (_i = 0, _len = modules.length; _i < _len; _i++) {
1167
+ Module = modules[_i];
1168
+ if (typeof Module.isString === "function" ? Module.isString() : void 0) {
1169
+ moduleName = Module;
1170
+ Module = Module.constantize();
1171
+ } else if (moduleName = Module._name) {} else {
1172
+ for (key in root) {
1173
+ value = root[key];
1174
+ if (value === Module) Module._name = moduleName = key;
1175
+ }
1176
+ }
1177
+ if (moduleName) {
1178
+ if (!I.includedModules.include(moduleName)) {
1179
+ I.includedModules.push(moduleName);
1180
+ self.extend(Module(I, self));
1181
+ }
1182
+ } else {
1183
+ warn("Unable to discover name for module: ", Module, "\nSerialization issues may occur.");
1184
+ self.extend(Module(I, self));
1185
+ }
1186
+ }
1187
+ return self;
1188
+ },
1189
+ send: function() {
1190
+ var args, name;
1191
+ name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
1192
+ return self[name].apply(self, args);
1193
+ }
1194
+ };
1195
+ self.include("Bindable");
1196
+ _ref = I.includedModules;
1197
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1198
+ moduleName = _ref[_i];
1199
+ Module = moduleName.constantize();
1200
+ self.extend(Module(I, self));
1201
+ }
1202
+ return self;
1203
+ };
1204
+ })();
1205
+
1206
+
1207
+
1208
+
1209
+ var __slice = Array.prototype.slice;
1210
+
1211
+ Function.prototype.once = function() {
1212
+ var func, memo, ran;
1213
+ func = this;
1214
+ ran = false;
1215
+ memo = void 0;
1216
+ return function() {
1217
+ if (ran) return memo;
1218
+ ran = true;
1219
+ return memo = func.apply(this, arguments);
1220
+ };
1221
+ };
1222
+
1223
+ /**
1224
+ Calling a debounced function will postpone its execution until after
1225
+ wait milliseconds have elapsed since the last time the function was
1226
+ invoked. Useful for implementing behavior that should only happen after
1227
+ the input has stopped arriving. For example: rendering a preview of a
1228
+ Markdown comment, recalculating a layout after the window has stopped
1229
+ being resized...
1230
+
1231
+ lazyLayout = calculateLayout.debounce(300)
1232
+ $(window).resize(lazyLayout)
1233
+
1234
+ @name debounce
1235
+ @methodOf Function#
1236
+ @returns {Function} The debounced version of this function.
1237
+ */
1238
+
1239
+ Function.prototype.debounce = function(wait) {
1240
+ var func, timeout;
1241
+ timeout = null;
1242
+ func = this;
1243
+ return function() {
1244
+ var args, context, later;
1245
+ context = this;
1246
+ args = arguments;
1247
+ later = function() {
1248
+ timeout = null;
1249
+ return func.apply(context, args);
1250
+ };
1251
+ clearTimeout(timeout);
1252
+ return timeout = setTimeout(later, wait);
1253
+ };
1254
+ };
1255
+
1256
+ Function.prototype.returning = function(x) {
1257
+ var func;
1258
+ func = this;
1259
+ return function() {
1260
+ func.apply(this, arguments);
1261
+ return x;
1262
+ };
1263
+ };
1264
+
1265
+ Function.prototype.delay = function() {
1266
+ var args, func, wait;
1267
+ wait = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
1268
+ func = this;
1269
+ return setTimeout(function() {
1270
+ return func.apply(null, args);
1271
+ }, wait);
1272
+ };
1273
+
1274
+ Function.prototype.defer = function() {
1275
+ var args;
1276
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1277
+ return this.delay.apply(this, [1].concat(args));
1278
+ };
1279
+
1280
+ Object.extend(Function, {
1281
+ identity: function(x) {
1282
+ return x;
1283
+ },
1284
+ noop: function() {}
1285
+ });
1286
+
1287
+ /**
1288
+ @name Logging
1289
+ @namespace
1290
+
1291
+ Gives you some convenience methods for outputting data while developing.
1292
+
1293
+ log "Testing123"
1294
+ info "Hey, this is happening"
1295
+ warn "Be careful, this might be a problem"
1296
+ error "Kaboom!"
1297
+ */
1298
+ var __slice = Array.prototype.slice;
1299
+
1300
+ ["log", "info", "warn", "error"].each(function(name) {
1301
+ if (typeof console !== "undefined") {
1302
+ return (typeof exports !== "undefined" && exports !== null ? exports : this)[name] = function() {
1303
+ var args;
1304
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1305
+ if (console[name]) return console[name].apply(console, args);
1306
+ };
1307
+ } else {
1308
+ return (typeof exports !== "undefined" && exports !== null ? exports : this)[name] = function() {};
1309
+ }
1310
+ });
1311
+
1312
+ /**
1313
+ * Matrix.js v1.3.0pre
1314
+ *
1315
+ * Copyright (c) 2010 STRd6
1316
+ *
1317
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
1318
+ * of this software and associated documentation files (the "Software"), to deal
1319
+ * in the Software without restriction, including without limitation the rights
1320
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1321
+ * copies of the Software, and to permit persons to whom the Software is
1322
+ * furnished to do so, subject to the following conditions:
1323
+ *
1324
+ * The above copyright notice and this permission notice shall be included in
1325
+ * all copies or substantial portions of the Software.
1326
+ *
1327
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1328
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1329
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1330
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1331
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1332
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1333
+ * THE SOFTWARE.
1334
+ *
1335
+ * Loosely based on flash:
1336
+ * http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/geom/Matrix.html
1337
+ */
1338
+ (function() {
1339
+ /**
1340
+ <pre>
1341
+ _ _
1342
+ | a c tx |
1343
+ | b d ty |
1344
+ |_0 0 1 _|
1345
+ </pre>
1346
+ Creates a matrix for 2d affine transformations.
1347
+
1348
+ concat, inverse, rotate, scale and translate return new matrices with the
1349
+ transformations applied. The matrix is not modified in place.
1350
+
1351
+ Returns the identity matrix when called with no arguments.
1352
+
1353
+ @name Matrix
1354
+ @param {Number} [a]
1355
+ @param {Number} [b]
1356
+ @param {Number} [c]
1357
+ @param {Number} [d]
1358
+ @param {Number} [tx]
1359
+ @param {Number} [ty]
1360
+ @constructor
1361
+ */
1362
+ var Matrix;
1363
+ Matrix = function(a, b, c, d, tx, ty) {
1364
+ var _ref;
1365
+ if (Object.isObject(a)) {
1366
+ _ref = a, a = _ref.a, b = _ref.b, c = _ref.c, d = _ref.d, tx = _ref.tx, ty = _ref.ty;
1367
+ }
1368
+ return {
1369
+ __proto__: Matrix.prototype,
1370
+ /**
1371
+ @name a
1372
+ @fieldOf Matrix#
1373
+ */
1374
+ a: a != null ? a : 1,
1375
+ /**
1376
+ @name b
1377
+ @fieldOf Matrix#
1378
+ */
1379
+ b: b || 0,
1380
+ /**
1381
+ @name c
1382
+ @fieldOf Matrix#
1383
+ */
1384
+ c: c || 0,
1385
+ /**
1386
+ @name d
1387
+ @fieldOf Matrix#
1388
+ */
1389
+ d: d != null ? d : 1,
1390
+ /**
1391
+ @name tx
1392
+ @fieldOf Matrix#
1393
+ */
1394
+ tx: tx || 0,
1395
+ /**
1396
+ @name ty
1397
+ @fieldOf Matrix#
1398
+ */
1399
+ ty: ty || 0
1400
+ };
1401
+ };
1402
+ Matrix.prototype = {
1403
+ /**
1404
+ Returns the result of this matrix multiplied by another matrix
1405
+ combining the geometric effects of the two. In mathematical terms,
1406
+ concatenating two matrixes is the same as combining them using matrix multiplication.
1407
+ If this matrix is A and the matrix passed in is B, the resulting matrix is A x B
1408
+ http://mathworld.wolfram.com/MatrixMultiplication.html
1409
+ @name concat
1410
+ @methodOf Matrix#
1411
+ @param {Matrix} matrix The matrix to multiply this matrix by.
1412
+ @returns {Matrix} The result of the matrix multiplication, a new matrix.
1413
+ */
1414
+ concat: function(matrix) {
1415
+ return Matrix(this.a * matrix.a + this.c * matrix.b, this.b * matrix.a + this.d * matrix.b, this.a * matrix.c + this.c * matrix.d, this.b * matrix.c + this.d * matrix.d, this.a * matrix.tx + this.c * matrix.ty + this.tx, this.b * matrix.tx + this.d * matrix.ty + this.ty);
1416
+ },
1417
+ /**
1418
+ Copy this matrix.
1419
+ @name copy
1420
+ @methodOf Matrix#
1421
+ @returns {Matrix} A copy of this matrix.
1422
+ */
1423
+ copy: function() {
1424
+ return Matrix(this.a, this.b, this.c, this.d, this.tx, this.ty);
1425
+ },
1426
+ /**
1427
+ Given a point in the pretransform coordinate space, returns the coordinates of
1428
+ that point after the transformation occurs. Unlike the standard transformation
1429
+ applied using the transformPoint() method, the deltaTransformPoint() method
1430
+ does not consider the translation parameters tx and ty.
1431
+ @name deltaTransformPoint
1432
+ @methodOf Matrix#
1433
+ @see #transformPoint
1434
+ @return {Point} A new point transformed by this matrix ignoring tx and ty.
1435
+ */
1436
+ deltaTransformPoint: function(point) {
1437
+ return Point(this.a * point.x + this.c * point.y, this.b * point.x + this.d * point.y);
1438
+ },
1439
+ /**
1440
+ Returns the inverse of the matrix.
1441
+ http://mathworld.wolfram.com/MatrixInverse.html
1442
+ @name inverse
1443
+ @methodOf Matrix#
1444
+ @returns {Matrix} A new matrix that is the inverse of this matrix.
1445
+ */
1446
+ inverse: function() {
1447
+ var determinant;
1448
+ determinant = this.a * this.d - this.b * this.c;
1449
+ return Matrix(this.d / determinant, -this.b / determinant, -this.c / determinant, this.a / determinant, (this.c * this.ty - this.d * this.tx) / determinant, (this.b * this.tx - this.a * this.ty) / determinant);
1450
+ },
1451
+ /**
1452
+ Returns a new matrix that corresponds this matrix multiplied by a
1453
+ a rotation matrix.
1454
+ @name rotate
1455
+ @methodOf Matrix#
1456
+ @see Matrix.rotation
1457
+ @param {Number} theta Amount to rotate in radians.
1458
+ @param {Point} [aboutPoint] The point about which this rotation occurs. Defaults to (0,0).
1459
+ @returns {Matrix} A new matrix, rotated by the specified amount.
1460
+ */
1461
+ rotate: function(theta, aboutPoint) {
1462
+ return this.concat(Matrix.rotation(theta, aboutPoint));
1463
+ },
1464
+ /**
1465
+ Returns a new matrix that corresponds this matrix multiplied by a
1466
+ a scaling matrix.
1467
+ @name scale
1468
+ @methodOf Matrix#
1469
+ @see Matrix.scale
1470
+ @param {Number} sx
1471
+ @param {Number} [sy]
1472
+ @param {Point} [aboutPoint] The point that remains fixed during the scaling
1473
+ @returns {Matrix} A new Matrix. The original multiplied by a scaling matrix.
1474
+ */
1475
+ scale: function(sx, sy, aboutPoint) {
1476
+ return this.concat(Matrix.scale(sx, sy, aboutPoint));
1477
+ },
1478
+ /**
1479
+ Returns a new matrix that corresponds this matrix multiplied by a
1480
+ a skewing matrix.
1481
+
1482
+ @name skew
1483
+ @methodOf Matrix#
1484
+ @see Matrix.skew
1485
+ @param {Number} skewX The angle of skew in the x dimension.
1486
+ @param {Number} skewY The angle of skew in the y dimension.
1487
+ */
1488
+ skew: function(skewX, skewY) {
1489
+ return this.concat(Matrix.skew(skewX, skewY));
1490
+ },
1491
+ /**
1492
+ Returns a string representation of this matrix.
1493
+
1494
+ @name toString
1495
+ @methodOf Matrix#
1496
+ @returns {String} A string reperesentation of this matrix.
1497
+ */
1498
+ toString: function() {
1499
+ return "Matrix(" + this.a + ", " + this.b + ", " + this.c + ", " + this.d + ", " + this.tx + ", " + this.ty + ")";
1500
+ },
1501
+ /**
1502
+ Returns the result of applying the geometric transformation represented by the
1503
+ Matrix object to the specified point.
1504
+ @name transformPoint
1505
+ @methodOf Matrix#
1506
+ @see #deltaTransformPoint
1507
+ @returns {Point} A new point with the transformation applied.
1508
+ */
1509
+ transformPoint: function(point) {
1510
+ return Point(this.a * point.x + this.c * point.y + this.tx, this.b * point.x + this.d * point.y + this.ty);
1511
+ },
1512
+ /**
1513
+ Translates the matrix along the x and y axes, as specified by the tx and ty parameters.
1514
+ @name translate
1515
+ @methodOf Matrix#
1516
+ @see Matrix.translation
1517
+ @param {Number} tx The translation along the x axis.
1518
+ @param {Number} ty The translation along the y axis.
1519
+ @returns {Matrix} A new matrix with the translation applied.
1520
+ */
1521
+ translate: function(tx, ty) {
1522
+ return this.concat(Matrix.translation(tx, ty));
1523
+ }
1524
+ };
1525
+ /**
1526
+ Creates a matrix transformation that corresponds to the given rotation,
1527
+ around (0,0) or the specified point.
1528
+ @see Matrix#rotate
1529
+ @param {Number} theta Rotation in radians.
1530
+ @param {Point} [aboutPoint] The point about which this rotation occurs. Defaults to (0,0).
1531
+ @returns {Matrix} A new matrix rotated by the given amount.
1532
+ */
1533
+ Matrix.rotate = Matrix.rotation = function(theta, aboutPoint) {
1534
+ var rotationMatrix;
1535
+ rotationMatrix = Matrix(Math.cos(theta), Math.sin(theta), -Math.sin(theta), Math.cos(theta));
1536
+ if (aboutPoint != null) {
1537
+ rotationMatrix = Matrix.translation(aboutPoint.x, aboutPoint.y).concat(rotationMatrix).concat(Matrix.translation(-aboutPoint.x, -aboutPoint.y));
1538
+ }
1539
+ return rotationMatrix;
1540
+ };
1541
+ /**
1542
+ Returns a matrix that corresponds to scaling by factors of sx, sy along
1543
+ the x and y axis respectively.
1544
+ If only one parameter is given the matrix is scaled uniformly along both axis.
1545
+ If the optional aboutPoint parameter is given the scaling takes place
1546
+ about the given point.
1547
+ @see Matrix#scale
1548
+ @param {Number} sx The amount to scale by along the x axis or uniformly if no sy is given.
1549
+ @param {Number} [sy] The amount to scale by along the y axis.
1550
+ @param {Point} [aboutPoint] The point about which the scaling occurs. Defaults to (0,0).
1551
+ @returns {Matrix} A matrix transformation representing scaling by sx and sy.
1552
+ */
1553
+ Matrix.scale = function(sx, sy, aboutPoint) {
1554
+ var scaleMatrix;
1555
+ sy = sy || sx;
1556
+ scaleMatrix = Matrix(sx, 0, 0, sy);
1557
+ if (aboutPoint) {
1558
+ scaleMatrix = Matrix.translation(aboutPoint.x, aboutPoint.y).concat(scaleMatrix).concat(Matrix.translation(-aboutPoint.x, -aboutPoint.y));
1559
+ }
1560
+ return scaleMatrix;
1561
+ };
1562
+ /**
1563
+ Returns a matrix that corresponds to a skew of skewX, skewY.
1564
+
1565
+ @see Matrix#skew
1566
+ @param {Number} skewX The angle of skew in the x dimension.
1567
+ @param {Number} skewY The angle of skew in the y dimension.
1568
+ @return {Matrix} A matrix transformation representing a skew by skewX and skewY.
1569
+ */
1570
+ Matrix.skew = function(skewX, skewY) {
1571
+ return Matrix(0, Math.tan(skewY), Math.tan(skewX), 0);
1572
+ };
1573
+ /**
1574
+ Returns a matrix that corresponds to a translation of tx, ty.
1575
+ @see Matrix#translate
1576
+ @param {Number} tx The amount to translate in the x direction.
1577
+ @param {Number} ty The amount to translate in the y direction.
1578
+ @return {Matrix} A matrix transformation representing a translation by tx and ty.
1579
+ */
1580
+ Matrix.translate = Matrix.translation = function(tx, ty) {
1581
+ return Matrix(1, 0, 0, 1, tx, ty);
1582
+ };
1583
+ /**
1584
+ A constant representing the identity matrix.
1585
+ @name IDENTITY
1586
+ @fieldOf Matrix
1587
+ */
1588
+ Matrix.IDENTITY = Matrix();
1589
+ /**
1590
+ A constant representing the horizontal flip transformation matrix.
1591
+ @name HORIZONTAL_FLIP
1592
+ @fieldOf Matrix
1593
+ */
1594
+ Matrix.HORIZONTAL_FLIP = Matrix(-1, 0, 0, 1);
1595
+ /**
1596
+ A constant representing the vertical flip transformation matrix.
1597
+ @name VERTICAL_FLIP
1598
+ @fieldOf Matrix
1599
+ */
1600
+ Matrix.VERTICAL_FLIP = Matrix(1, 0, 0, -1);
1601
+ if (Object.freeze) {
1602
+ Object.freeze(Matrix.IDENTITY);
1603
+ Object.freeze(Matrix.HORIZONTAL_FLIP);
1604
+ Object.freeze(Matrix.VERTICAL_FLIP);
1605
+ }
1606
+ return (typeof exports !== "undefined" && exports !== null ? exports : this)["Matrix"] = Matrix;
1607
+ })();
1608
+
1609
+ /**
1610
+ Returns the absolute value of this number.
1611
+
1612
+ (-4).abs()
1613
+ # => 4
1614
+
1615
+ @name abs
1616
+ @methodOf Number#
1617
+ @returns {Number} The absolute value of the number.
1618
+ */
1619
+ Number.prototype.abs = function() {
1620
+ return Math.abs(this);
1621
+ };
1622
+
1623
+ /**
1624
+ Returns the mathematical ceiling of this number.
1625
+
1626
+ 4.9.ceil()
1627
+ # => 5
1628
+
1629
+ 4.2.ceil()
1630
+ # => 5
1631
+
1632
+ (-1.2).ceil()
1633
+ # => -1
1634
+
1635
+ @name ceil
1636
+ @methodOf Number#
1637
+ @returns {Number} The number truncated to the nearest integer of greater than or equal value.
1638
+ */
1639
+
1640
+ Number.prototype.ceil = function() {
1641
+ return Math.ceil(this);
1642
+ };
1643
+
1644
+ /**
1645
+ Returns the mathematical floor of this number.
1646
+
1647
+ 4.9.floor()
1648
+ # => 4
1649
+
1650
+ 4.2.floor()
1651
+ # => 4
1652
+
1653
+ (-1.2).floor()
1654
+ # => -2
1655
+
1656
+ @name floor
1657
+ @methodOf Number#
1658
+ @returns {Number} The number truncated to the nearest integer of less than or equal value.
1659
+ */
1660
+
1661
+ Number.prototype.floor = function() {
1662
+ return Math.floor(this);
1663
+ };
1664
+
1665
+ /**
1666
+ Returns this number rounded to the nearest integer.
1667
+
1668
+ 4.5.round()
1669
+ # => 5
1670
+
1671
+ 4.4.round()
1672
+ # => 4
1673
+
1674
+ @name round
1675
+ @methodOf Number#
1676
+ @returns {Number} The number rounded to the nearest integer.
1677
+ */
1678
+
1679
+ Number.prototype.round = function() {
1680
+ return Math.round(this);
1681
+ };
1682
+
1683
+ /**
1684
+ Get a bunch of points equally spaced around the unit circle.
1685
+
1686
+ 4.circularPoints (p) ->
1687
+
1688
+ # p gets Point(1, 0), Point(0, 1), Point(-1, 0), Point(0, -1)
1689
+
1690
+ @name circularPoint
1691
+ @methodOf Number#
1692
+ */
1693
+
1694
+ Number.prototype.circularPoints = function(block) {
1695
+ var n;
1696
+ n = this;
1697
+ return n.times(function(i) {
1698
+ return block(Point.fromAngle((i / n).turns), i);
1699
+ });
1700
+ };
1701
+
1702
+ /**
1703
+ Returns a number whose value is limited to the given range.
1704
+
1705
+ # limit the output of this computation to between 0 and 255
1706
+ (2 * 255).clamp(0, 255)
1707
+ # => 255
1708
+
1709
+ @name clamp
1710
+ @methodOf Number#
1711
+ @param {Number} min The lower boundary of the output range
1712
+ @param {Number} max The upper boundary of the output range
1713
+ @returns {Number} A number in the range [min, max]
1714
+ */
1715
+
1716
+ Number.prototype.clamp = function(min, max) {
1717
+ if ((min != null) && (max != null)) {
1718
+ return Math.min(Math.max(this, min), max);
1719
+ } else if (min != null) {
1720
+ return Math.max(this, min);
1721
+ } else if (max != null) {
1722
+ return Math.min(this, max);
1723
+ } else {
1724
+ return this;
1725
+ }
1726
+ };
1727
+
1728
+ /**
1729
+ A mod method useful for array wrapping. The range of the function is
1730
+ constrained to remain in bounds of array indices.
1731
+
1732
+ (-1).mod(5)
1733
+ # => 4
1734
+
1735
+ @name mod
1736
+ @methodOf Number#
1737
+ @param {Number} base
1738
+ @returns {Number} An integer between 0 and (base - 1) if base is positive.
1739
+ */
1740
+
1741
+ Number.prototype.mod = function(base) {
1742
+ var result;
1743
+ result = this % base;
1744
+ if (result < 0 && base > 0) result += base;
1745
+ return result;
1746
+ };
1747
+
1748
+ /**
1749
+ Get the sign of this number as an integer (1, -1, or 0).
1750
+
1751
+ (-5).sign()
1752
+ # => -1
1753
+
1754
+ 0.sign()
1755
+ # => 0
1756
+
1757
+ 5.sign()
1758
+ # => 1
1759
+
1760
+ @name sign
1761
+ @methodOf Number#
1762
+ @returns {Number} The sign of this number, 0 if the number is 0.
1763
+ */
1764
+
1765
+ Number.prototype.sign = function() {
1766
+ if (this > 0) {
1767
+ return 1;
1768
+ } else if (this < 0) {
1769
+ return -1;
1770
+ } else {
1771
+ return 0;
1772
+ }
1773
+ };
1774
+
1775
+ /**
1776
+ Returns true if this number is even (evenly divisible by 2).
1777
+
1778
+ 2.even()
1779
+ # => true
1780
+
1781
+ 3.even()
1782
+ # => false
1783
+
1784
+ 0.even()
1785
+ # => true
1786
+
1787
+ @name even
1788
+ @methodOf Number#
1789
+ @returns {Boolean} true if this number is an even integer, false otherwise.
1790
+ */
1791
+
1792
+ Number.prototype.even = function() {
1793
+ return this % 2 === 0;
1794
+ };
1795
+
1796
+ /**
1797
+ Returns true if this number is odd (has remainder of 1 when divided by 2).
1798
+
1799
+ 2.odd()
1800
+ # => false
1801
+
1802
+ 3.odd()
1803
+ # => true
1804
+
1805
+ 0.odd()
1806
+ # => false
1807
+
1808
+ @name odd
1809
+ @methodOf Number#
1810
+ @returns {Boolean} true if this number is an odd integer, false otherwise.
1811
+ */
1812
+
1813
+ Number.prototype.odd = function() {
1814
+ if (this > 0) {
1815
+ return this % 2 === 1;
1816
+ } else {
1817
+ return this % 2 === -1;
1818
+ }
1819
+ };
1820
+
1821
+ /**
1822
+ Calls iterator the specified number of times, passing in the number of the
1823
+ current iteration as a parameter: 0 on first call, 1 on the second call, etc.
1824
+
1825
+ output = []
1826
+
1827
+ 5.times (n) ->
1828
+ output.push(n)
1829
+
1830
+ output
1831
+ # => [0, 1, 2, 3, 4]
1832
+
1833
+ @name times
1834
+ @methodOf Number#
1835
+ @param {Function} iterator The iterator takes a single parameter, the number of the current iteration.
1836
+ @param {Object} [context] The optional context parameter specifies an object to treat as <code>this</code> in the iterator block.
1837
+ @returns {Number} The number of times the iterator was called.
1838
+ */
1839
+
1840
+ Number.prototype.times = function(iterator, context) {
1841
+ var i;
1842
+ i = -1;
1843
+ while (++i < this) {
1844
+ iterator.call(context, i);
1845
+ }
1846
+ return i;
1847
+ };
1848
+
1849
+ /**
1850
+ Returns the the nearest grid resolution less than or equal to the number.
1851
+
1852
+ 7.snap(8)
1853
+ # => 0
1854
+
1855
+ 4.snap(8)
1856
+ # => 0
1857
+
1858
+ 12.snap(8)
1859
+ # => 8
1860
+
1861
+ @name snap
1862
+ @methodOf Number#
1863
+ @param {Number} resolution The grid resolution to snap to.
1864
+ @returns {Number} The nearest multiple of resolution lower than the number.
1865
+ */
1866
+
1867
+ Number.prototype.snap = function(resolution) {
1868
+ var n;
1869
+ n = this / resolution;
1870
+ 1 / 1;
1871
+ return n.floor() * resolution;
1872
+ };
1873
+
1874
+ /**
1875
+ In number theory, integer factorization or prime factorization is the
1876
+ breaking down of a composite number into smaller non-trivial divisors,
1877
+ which when multiplied together equal the original integer.
1878
+
1879
+ Floors the number for purposes of factorization.
1880
+
1881
+ 60.primeFactors()
1882
+ # => [2, 2, 3, 5]
1883
+
1884
+ 37.primeFactors()
1885
+ # => [37]
1886
+
1887
+ @name primeFactors
1888
+ @methodOf Number#
1889
+ @returns {Array} An array containing the factorization of this number.
1890
+ */
1891
+
1892
+ Number.prototype.primeFactors = function() {
1893
+ var factors, i, iSquared, n;
1894
+ factors = [];
1895
+ n = Math.floor(this);
1896
+ if (n === 0) return;
1897
+ if (n < 0) {
1898
+ factors.push(-1);
1899
+ n /= -1;
1900
+ }
1901
+ i = 2;
1902
+ iSquared = i * i;
1903
+ while (iSquared < n) {
1904
+ while ((n % i) === 0) {
1905
+ factors.push(i);
1906
+ n /= i;
1907
+ }
1908
+ i += 1;
1909
+ iSquared = i * i;
1910
+ }
1911
+ if (n !== 1) factors.push(n);
1912
+ return factors;
1913
+ };
1914
+
1915
+ /**
1916
+ Returns the two character hexidecimal
1917
+ representation of numbers 0 through 255.
1918
+
1919
+ 255.toColorPart()
1920
+ # => "ff"
1921
+
1922
+ 0.toColorPart()
1923
+ # => "00"
1924
+
1925
+ 200.toColorPart()
1926
+ # => "c8"
1927
+
1928
+ @name toColorPart
1929
+ @methodOf Number#
1930
+ @returns {String} Hexidecimal representation of the number
1931
+ */
1932
+
1933
+ Number.prototype.toColorPart = function() {
1934
+ var s;
1935
+ s = parseInt(this.clamp(0, 255), 10).toString(16);
1936
+ if (s.length === 1) s = '0' + s;
1937
+ return s;
1938
+ };
1939
+
1940
+ /**
1941
+ Returns a number that is maxDelta closer to target.
1942
+
1943
+ 255.approach(0, 5)
1944
+ # => 250
1945
+
1946
+ 5.approach(0, 10)
1947
+ # => 0
1948
+
1949
+ @name approach
1950
+ @methodOf Number#
1951
+ @returns {Number} A number maxDelta toward target
1952
+ */
1953
+
1954
+ Number.prototype.approach = function(target, maxDelta) {
1955
+ return (target - this).clamp(-maxDelta, maxDelta) + this;
1956
+ };
1957
+
1958
+ /**
1959
+ Returns a number that is closer to the target by the ratio.
1960
+
1961
+ 255.approachByRatio(0, 0.1)
1962
+ # => 229.5
1963
+
1964
+ @name approachByRatio
1965
+ @methodOf Number#
1966
+ @returns {Number} A number toward target by the ratio
1967
+ */
1968
+
1969
+ Number.prototype.approachByRatio = function(target, ratio) {
1970
+ return this.approach(target, this * ratio);
1971
+ };
1972
+
1973
+ /**
1974
+ Returns a number that is closer to the target angle by the delta.
1975
+
1976
+ Math.PI.approachRotation(0, Math.PI/4)
1977
+ # => 2.356194490192345 # this is (3/4) * Math.PI, which is (1/4) * Math.PI closer to 0 from Math.PI
1978
+
1979
+ @name approachRotation
1980
+ @methodOf Number#
1981
+ @returns {Number} A number toward the target angle by maxDelta
1982
+ */
1983
+
1984
+ Number.prototype.approachRotation = function(target, maxDelta) {
1985
+ while (target > this + Math.PI) {
1986
+ target -= Math.TAU;
1987
+ }
1988
+ while (target < this - Math.PI) {
1989
+ target += Math.TAU;
1990
+ }
1991
+ return (target - this).clamp(-maxDelta, maxDelta) + this;
1992
+ };
1993
+
1994
+ /**
1995
+ Constrains a rotation to between -PI and PI.
1996
+
1997
+ (9/4 * Math.PI).constrainRotation()
1998
+ # => 0.7853981633974483 # this is (1/4) * Math.PI
1999
+
2000
+ @name constrainRotation
2001
+ @methodOf Number#
2002
+ @returns {Number} This number constrained between -PI and PI.
2003
+ */
2004
+
2005
+ Number.prototype.constrainRotation = function() {
2006
+ var target;
2007
+ target = this;
2008
+ while (target > Math.PI) {
2009
+ target -= Math.TAU;
2010
+ }
2011
+ while (target < -Math.PI) {
2012
+ target += Math.TAU;
2013
+ }
2014
+ return target;
2015
+ };
2016
+
2017
+ Number.prototype.truncate = function() {
2018
+ if (this > 0) {
2019
+ return Math.floor(this);
2020
+ } else if (this < 0) {
2021
+ return Math.ceil(this);
2022
+ } else {
2023
+ return this;
2024
+ }
2025
+ };
2026
+
2027
+ /**
2028
+ The mathematical d operator. Useful for simulating dice rolls.
2029
+
2030
+ @name d
2031
+ @methodOf Number#
2032
+ @returns {Number} The sum of rolling <code>this</code> many <code>sides</code>-sided dice
2033
+ */
2034
+
2035
+ Number.prototype.d = function(sides) {
2036
+ var sum;
2037
+ sum = 0;
2038
+ this.times(function() {
2039
+ return sum += rand(sides) + 1;
2040
+ });
2041
+ return sum;
2042
+ };
2043
+
2044
+ /**
2045
+ Utility method to convert a number to a duration of seconds.
2046
+
2047
+ 3.seconds
2048
+ # => 3000
2049
+
2050
+ setTimout doSometing, 3.seconds
2051
+
2052
+ @name seconds
2053
+ @propertyOf Number#
2054
+ @returns {Number} This number as a duration of seconds
2055
+ */
2056
+
2057
+ if (!5..seconds) {
2058
+ Object.defineProperty(Number.prototype, 'seconds', {
2059
+ get: function() {
2060
+ return this * 1000;
2061
+ }
2062
+ });
2063
+ }
2064
+
2065
+ if (!1..second) {
2066
+ Object.defineProperty(Number.prototype, 'second', {
2067
+ get: function() {
2068
+ return this * 1000;
2069
+ }
2070
+ });
2071
+ }
2072
+
2073
+ /**
2074
+ Utility method to convert a number to an amount of rotations.
2075
+
2076
+ 0.5.rotations
2077
+ # => 3.141592653589793
2078
+
2079
+ I.rotation = 0.25.rotations
2080
+
2081
+ @name rotations
2082
+ @propertyOf Number#
2083
+ @returns {Number} This number as an amount of rotations
2084
+ */
2085
+
2086
+ if (!5..rotations) {
2087
+ Object.defineProperty(Number.prototype, 'rotations', {
2088
+ get: function() {
2089
+ return this * Math.TAU;
2090
+ }
2091
+ });
2092
+ }
2093
+
2094
+ if (!1..rotation) {
2095
+ Object.defineProperty(Number.prototype, 'rotation', {
2096
+ get: function() {
2097
+ return this * Math.TAU;
2098
+ }
2099
+ });
2100
+ }
2101
+
2102
+ /**
2103
+ Utility method to convert a number to an amount of rotations.
2104
+
2105
+ 0.5.turns
2106
+ # => 3.141592653589793
2107
+
2108
+ I.rotation = 0.25.turns
2109
+
2110
+ 1.turn # => Math.TAU (aka 2 * Math.PI)
2111
+
2112
+ @name turns
2113
+ @propertyOf Number#
2114
+ @returns {Number} This number as an amount of rotation.
2115
+ 1 turn is one complete rotation.
2116
+ */
2117
+
2118
+ if (!5..turns) {
2119
+ Object.defineProperty(Number.prototype, 'turns', {
2120
+ get: function() {
2121
+ return this * Math.TAU;
2122
+ }
2123
+ });
2124
+ }
2125
+
2126
+ if (!1..turn) {
2127
+ Object.defineProperty(Number.prototype, 'turn', {
2128
+ get: function() {
2129
+ return this * Math.TAU;
2130
+ }
2131
+ });
2132
+ }
2133
+
2134
+ /**
2135
+ Utility method to convert a number to an amount of degrees.
2136
+
2137
+ 180.degrees
2138
+ # => 3.141592653589793
2139
+
2140
+ I.rotation = 90.degrees
2141
+
2142
+ @name degrees
2143
+ @propertyOf Number#
2144
+ @returns {Number} This number as an amount of degrees
2145
+ */
2146
+
2147
+ if (!2..degrees) {
2148
+ Object.defineProperty(Number.prototype, 'degrees', {
2149
+ get: function() {
2150
+ return this * Math.TAU / 360;
2151
+ }
2152
+ });
2153
+ }
2154
+
2155
+ if (!1..degree) {
2156
+ Object.defineProperty(Number.prototype, 'degree', {
2157
+ get: function() {
2158
+ return this * Math.TAU / 360;
2159
+ }
2160
+ });
2161
+ }
2162
+
2163
+ /**
2164
+ The mathematical circle constant of 1 turn.
2165
+
2166
+ @name TAU
2167
+ @fieldOf Math
2168
+ */
2169
+
2170
+ Math.TAU = 2 * Math.PI;
2171
+
2172
+ var __slice = Array.prototype.slice;
2173
+
2174
+ (function() {
2175
+ /**
2176
+ Create a new point with given x and y coordinates. If no arguments are given
2177
+ defaults to (0, 0).
2178
+
2179
+ point = Point()
2180
+
2181
+ p.x
2182
+ # => 0
2183
+
2184
+ p.y
2185
+ # => 0
2186
+
2187
+ point = Point(-2, 5)
2188
+
2189
+ p.x
2190
+ # => -2
2191
+
2192
+ p.y
2193
+ # => 5
2194
+
2195
+ @name Point
2196
+ @param {Number} [x]
2197
+ @param {Number} [y]
2198
+ @constructor
2199
+ */
2200
+ var Point;
2201
+ Point = function(x, y) {
2202
+ var _ref;
2203
+ if (Object.isObject(x)) _ref = x, x = _ref.x, y = _ref.y;
2204
+ return {
2205
+ __proto__: Point.prototype,
2206
+ /**
2207
+ The x coordinate of this point.
2208
+ @name x
2209
+ @fieldOf Point#
2210
+ */
2211
+ x: x || 0,
2212
+ /**
2213
+ The y coordinate of this point.
2214
+ @name y
2215
+ @fieldOf Point#
2216
+ */
2217
+ y: y || 0
2218
+ };
2219
+ };
2220
+ Point.prototype = {
2221
+ /**
2222
+ Constrain the magnitude of a vector.
2223
+
2224
+ @name clamp
2225
+ @methodOf Point#
2226
+ @param {Number} n Maximum value for magnitude.
2227
+ @returns {Point} A new point whose magnitude has been clamped to the given value.
2228
+ */
2229
+ clamp: function(n) {
2230
+ return this.copy().clamp$(n);
2231
+ },
2232
+ clamp$: function(n) {
2233
+ if (this.magnitude() > n) {
2234
+ return this.norm$(n);
2235
+ } else {
2236
+ return this;
2237
+ }
2238
+ },
2239
+ /**
2240
+ Creates a copy of this point.
2241
+
2242
+ @name copy
2243
+ @methodOf Point#
2244
+ @returns {Point} A new point with the same x and y value as this point.
2245
+
2246
+ point = Point(1, 1)
2247
+ pointCopy = point.copy()
2248
+
2249
+ point.equal(pointCopy)
2250
+ # => true
2251
+
2252
+ point == pointCopy
2253
+ # => false
2254
+ */
2255
+ copy: function() {
2256
+ return Point(this.x, this.y);
2257
+ },
2258
+ /**
2259
+ Adds a point to this one and returns the new point. You may
2260
+ also use a two argument call like <code>point.add(x, y)</code>
2261
+ to add x and y values without a second point object.
2262
+
2263
+ point = Point(2, 3).add(Point(3, 4))
2264
+
2265
+ point.x
2266
+ # => 5
2267
+
2268
+ point.y
2269
+ # => 7
2270
+
2271
+ anotherPoint = Point(2, 3).add(3, 4)
2272
+
2273
+ anotherPoint.x
2274
+ # => 5
2275
+
2276
+ anotherPoint.y
2277
+ # => 7
2278
+
2279
+ @name add
2280
+ @methodOf Point#
2281
+ @param {Point} other The point to add this point to.
2282
+ @returns {Point} A new point, the sum of both.
2283
+ */
2284
+ add: function(first, second) {
2285
+ return this.copy().add$(first, second);
2286
+ },
2287
+ /**
2288
+ Adds a point to this one, returning a modified point. You may
2289
+ also use a two argument call like <code>point.add(x, y)</code>
2290
+ to add x and y values without a second point object.
2291
+
2292
+ point = Point(2, 3)
2293
+
2294
+ point.x
2295
+ # => 2
2296
+
2297
+ point.y
2298
+ # => 3
2299
+
2300
+ point.add$(Point(3, 4))
2301
+
2302
+ point.x
2303
+ # => 5
2304
+
2305
+ point.y
2306
+ # => 7
2307
+
2308
+ anotherPoint = Point(2, 3)
2309
+ anotherPoint.add$(3, 4)
2310
+
2311
+ anotherPoint.x
2312
+ # => 5
2313
+
2314
+ anotherPoint.y
2315
+ # => 7
2316
+
2317
+ @name add$
2318
+ @methodOf Point#
2319
+ @param {Point} other The point to add this point to.
2320
+ @returns {Point} The sum of both points.
2321
+ */
2322
+ add$: function(first, second) {
2323
+ if (second != null) {
2324
+ this.x += first;
2325
+ this.y += second;
2326
+ } else {
2327
+ this.x += first.x;
2328
+ this.y += first.y;
2329
+ }
2330
+ return this;
2331
+ },
2332
+ /**
2333
+ Subtracts a point to this one and returns the new point.
2334
+
2335
+ point = Point(1, 2).subtract(Point(2, 0))
2336
+
2337
+ point.x
2338
+ # => -1
2339
+
2340
+ point.y
2341
+ # => 2
2342
+
2343
+ anotherPoint = Point(1, 2).subtract(2, 0)
2344
+
2345
+ anotherPoint.x
2346
+ # => -1
2347
+
2348
+ anotherPoint.y
2349
+ # => 2
2350
+
2351
+ @name subtract
2352
+ @methodOf Point#
2353
+ @param {Point} other The point to subtract from this point.
2354
+ @returns {Point} A new point, this - other.
2355
+ */
2356
+ subtract: function(first, second) {
2357
+ return this.copy().subtract$(first, second);
2358
+ },
2359
+ /**
2360
+ Subtracts a point to this one and returns the new point.
2361
+
2362
+ point = Point(1, 2)
2363
+
2364
+ point.x
2365
+ # => 1
2366
+
2367
+ point.y
2368
+ # => 2
2369
+
2370
+ point.subtract$(Point(2, 0))
2371
+
2372
+ point.x
2373
+ # => -1
2374
+
2375
+ point.y
2376
+ # => 2
2377
+
2378
+ anotherPoint = Point(1, 2)
2379
+ anotherPoint.subtract$(2, 0)
2380
+
2381
+ anotherPoint.x
2382
+ # => -1
2383
+
2384
+ anotherPoint.y
2385
+ # => 2
2386
+
2387
+ @name subtract$
2388
+ @methodOf Point#
2389
+ @param {Point} other The point to subtract from this point.
2390
+ @returns {Point} The difference of the two points.
2391
+ */
2392
+ subtract$: function(first, second) {
2393
+ if (second != null) {
2394
+ this.x -= first;
2395
+ this.y -= second;
2396
+ } else {
2397
+ this.x -= first.x;
2398
+ this.y -= first.y;
2399
+ }
2400
+ return this;
2401
+ },
2402
+ /**
2403
+ Scale this Point (Vector) by a constant amount.
2404
+
2405
+ point = Point(5, 6).scale(2)
2406
+
2407
+ point.x
2408
+ # => 10
2409
+
2410
+ point.y
2411
+ # => 12
2412
+
2413
+ @name scale
2414
+ @methodOf Point#
2415
+ @param {Number} scalar The amount to scale this point by.
2416
+ @returns {Point} A new point, this * scalar.
2417
+ */
2418
+ scale: function(scalar) {
2419
+ return this.copy().scale$(scalar);
2420
+ },
2421
+ /**
2422
+ Scale this Point (Vector) by a constant amount. Modifies the point in place.
2423
+
2424
+ point = Point(5, 6)
2425
+
2426
+ point.x
2427
+ # => 5
2428
+
2429
+ point.y
2430
+ # => 6
2431
+
2432
+ point.scale$(2)
2433
+
2434
+ point.x
2435
+ # => 10
2436
+
2437
+ point.y
2438
+ # => 12
2439
+
2440
+ @name scale$
2441
+ @methodOf Point#
2442
+ @param {Number} scalar The amount to scale this point by.
2443
+ @returns {Point} this * scalar.
2444
+ */
2445
+ scale$: function(scalar) {
2446
+ this.x *= scalar;
2447
+ this.y *= scalar;
2448
+ return this;
2449
+ },
2450
+ /**
2451
+ The norm of a vector is the unit vector pointing in the same direction. This method
2452
+ treats the point as though it is a vector from the origin to (x, y).
2453
+
2454
+ point = Point(2, 3).norm()
2455
+
2456
+ point.x
2457
+ # => 0.5547001962252291
2458
+
2459
+ point.y
2460
+ # => 0.8320502943378437
2461
+
2462
+ anotherPoint = Point(2, 3).norm(2)
2463
+
2464
+ anotherPoint.x
2465
+ # => 1.1094003924504583
2466
+
2467
+ anotherPoint.y
2468
+ # => 1.6641005886756874
2469
+
2470
+ @name norm
2471
+ @methodOf Point#
2472
+ @returns {Point} The unit vector pointing in the same direction as this vector.
2473
+ */
2474
+ norm: function(length) {
2475
+ if (length == null) length = 1.0;
2476
+ return this.copy().norm$(length);
2477
+ },
2478
+ /**
2479
+ The norm of a vector is the unit vector pointing in the same direction. This method
2480
+ treats the point as though it is a vector from the origin to (x, y). Modifies the point in place.
2481
+
2482
+ point = Point(2, 3).norm$()
2483
+
2484
+ point.x
2485
+ # => 0.5547001962252291
2486
+
2487
+ point.y
2488
+ # => 0.8320502943378437
2489
+
2490
+ anotherPoint = Point(2, 3).norm$(2)
2491
+
2492
+ anotherPoint.x
2493
+ # => 1.1094003924504583
2494
+
2495
+ anotherPoint.y
2496
+ # => 1.6641005886756874
2497
+
2498
+ @name norm$
2499
+ @methodOf Point#
2500
+ @returns {Point} The unit vector pointing in the same direction as this vector.
2501
+ */
2502
+ norm$: function(length) {
2503
+ var m;
2504
+ if (length == null) length = 1.0;
2505
+ if (m = this.length()) {
2506
+ return this.scale$(length / m);
2507
+ } else {
2508
+ return this;
2509
+ }
2510
+ },
2511
+ /**
2512
+ Floor the x and y values, returning a new point.
2513
+
2514
+ point = Point(3.4, 5.8).floor()
2515
+
2516
+ point.x
2517
+ # => 3
2518
+
2519
+ point.y
2520
+ # => 5
2521
+
2522
+ @name floor
2523
+ @methodOf Point#
2524
+ @returns {Point} A new point, with x and y values each floored to the largest previous integer.
2525
+ */
2526
+ floor: function() {
2527
+ return this.copy().floor$();
2528
+ },
2529
+ /**
2530
+ Floor the x and y values, returning a modified point.
2531
+
2532
+ point = Point(3.4, 5.8)
2533
+ point.floor$()
2534
+
2535
+ point.x
2536
+ # => 3
2537
+
2538
+ point.y
2539
+ # => 5
2540
+
2541
+ @name floor$
2542
+ @methodOf Point#
2543
+ @returns {Point} A modified point, with x and y values each floored to the largest previous integer.
2544
+ */
2545
+ floor$: function() {
2546
+ this.x = this.x.floor();
2547
+ this.y = this.y.floor();
2548
+ return this;
2549
+ },
2550
+ /**
2551
+ Determine whether this point is equal to another point.
2552
+
2553
+ pointA = Point(2, 3)
2554
+ pointB = Point(2, 3)
2555
+ pointC = Point(4, 5)
2556
+
2557
+ pointA.equal(pointB)
2558
+ # => true
2559
+
2560
+ pointA.equal(pointC)
2561
+ # => false
2562
+
2563
+ @name equal
2564
+ @methodOf Point#
2565
+ @param {Point} other The point to check for equality.
2566
+ @returns {Boolean} true if the other point has the same x, y coordinates, false otherwise.
2567
+ */
2568
+ equal: function(other) {
2569
+ return this.x === other.x && this.y === other.y;
2570
+ },
2571
+ /**
2572
+ Computed the length of this point as though it were a vector from (0,0) to (x,y).
2573
+
2574
+ point = Point(5, 7)
2575
+
2576
+ point.length()
2577
+ # => 8.602325267042627
2578
+
2579
+ @name length
2580
+ @methodOf Point#
2581
+ @returns {Number} The length of the vector from the origin to this point.
2582
+ */
2583
+ length: function() {
2584
+ return Math.sqrt(this.dot(this));
2585
+ },
2586
+ /**
2587
+ Calculate the magnitude of this Point (Vector).
2588
+
2589
+ point = Point(5, 7)
2590
+
2591
+ point.magnitude()
2592
+ # => 8.602325267042627
2593
+
2594
+ @name magnitude
2595
+ @methodOf Point#
2596
+ @returns {Number} The magnitude of this point as if it were a vector from (0, 0) -> (x, y).
2597
+ */
2598
+ magnitude: function() {
2599
+ return this.length();
2600
+ },
2601
+ /**
2602
+ Returns the direction in radians of this point from the origin.
2603
+
2604
+ point = Point(0, 1)
2605
+
2606
+ point.direction()
2607
+ # => 1.5707963267948966 # Math.PI / 2
2608
+
2609
+ @name direction
2610
+ @methodOf Point#
2611
+ @returns {Number} The direction in radians of this point from the origin
2612
+ */
2613
+ direction: function() {
2614
+ return Math.atan2(this.y, this.x);
2615
+ },
2616
+ /**
2617
+ Calculate the dot product of this point and another point (Vector).
2618
+ @name dot
2619
+ @methodOf Point#
2620
+ @param {Point} other The point to dot with this point.
2621
+ @returns {Number} The dot product of this point dot other as a scalar value.
2622
+ */
2623
+ dot: function(other) {
2624
+ return this.x * other.x + this.y * other.y;
2625
+ },
2626
+ /**
2627
+ Calculate the cross product of this point and another point (Vector).
2628
+ Usually cross products are thought of as only applying to three dimensional vectors,
2629
+ but z can be treated as zero. The result of this method is interpreted as the magnitude
2630
+ of the vector result of the cross product between [x1, y1, 0] x [x2, y2, 0]
2631
+ perpendicular to the xy plane.
2632
+
2633
+ @name cross
2634
+ @methodOf Point#
2635
+ @param {Point} other The point to cross with this point.
2636
+ @returns {Number} The cross product of this point with the other point as scalar value.
2637
+ */
2638
+ cross: function(other) {
2639
+ return this.x * other.y - other.x * this.y;
2640
+ },
2641
+ /**
2642
+ Compute the Euclidean distance between this point and another point.
2643
+
2644
+ pointA = Point(2, 3)
2645
+ pointB = Point(9, 2)
2646
+
2647
+ pointA.distance(pointB)
2648
+ # => 7.0710678118654755 # Math.sqrt(50)
2649
+
2650
+ @name distance
2651
+ @methodOf Point#
2652
+ @param {Point} other The point to compute the distance to.
2653
+ @returns {Number} The distance between this point and another point.
2654
+ */
2655
+ distance: function(other) {
2656
+ return Point.distance(this, other);
2657
+ },
2658
+ /**
2659
+ @name toString
2660
+ @methodOf Point#
2661
+ @returns {String} A string representation of this point.
2662
+ */
2663
+ toString: function() {
2664
+ return "Point(" + this.x + ", " + this.y + ")";
2665
+ },
2666
+ abs: function() {
2667
+ return Point({
2668
+ x: this.x.abs(),
2669
+ y: this.y.abs()
2670
+ });
2671
+ },
2672
+ snap: function(n) {
2673
+ return Point({
2674
+ x: this.x.snap(n),
2675
+ y: this.y.snap(n)
2676
+ });
2677
+ },
2678
+ angle: function() {
2679
+ return Math.atan2(this.y, this.x);
2680
+ }
2681
+ };
2682
+ /**
2683
+ Compute the Euclidean distance between two points.
2684
+
2685
+ pointA = Point(2, 3)
2686
+ pointB = Point(9, 2)
2687
+
2688
+ Point.distance(pointA, pointB)
2689
+ # => 7.0710678118654755 # Math.sqrt(50)
2690
+
2691
+ @name distance
2692
+ @fieldOf Point
2693
+ @param {Point} p1
2694
+ @param {Point} p2
2695
+ @returns {Number} The Euclidean distance between two points.
2696
+ */
2697
+ Point.distance = function(p1, p2) {
2698
+ return Math.sqrt(Point.distanceSquared(p1, p2));
2699
+ };
2700
+ /**
2701
+ pointA = Point(2, 3)
2702
+ pointB = Point(9, 2)
2703
+
2704
+ Point.distanceSquared(pointA, pointB)
2705
+ # => 50
2706
+
2707
+ @name distanceSquared
2708
+ @fieldOf Point
2709
+ @param {Point} p1
2710
+ @param {Point} p2
2711
+ @returns {Number} The square of the Euclidean distance between two points.
2712
+ */
2713
+ Point.distanceSquared = function(p1, p2) {
2714
+ return Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2);
2715
+ };
2716
+ /**
2717
+ @name interpolate
2718
+ @fieldOf Point
2719
+
2720
+ @param {Point} p1
2721
+ @param {Point} p2
2722
+ @param {Number} t
2723
+ @returns {Point} A point along the path from p1 to p2
2724
+ */
2725
+ Point.interpolate = function(p1, p2, t) {
2726
+ return p2.subtract(p1).scale(t).add(p1);
2727
+ };
2728
+ /**
2729
+ Construct a point on the unit circle for the given angle.
2730
+
2731
+ point = Point.fromAngle(Math.PI / 2)
2732
+
2733
+ point.x
2734
+ # => 0
2735
+
2736
+ point.y
2737
+ # => 1
2738
+
2739
+ @name fromAngle
2740
+ @fieldOf Point
2741
+ @param {Number} angle The angle in radians
2742
+ @returns {Point} The point on the unit circle.
2743
+ */
2744
+ Point.fromAngle = function(angle) {
2745
+ return Point(Math.cos(angle), Math.sin(angle));
2746
+ };
2747
+ /**
2748
+ If you have two dudes, one standing at point p1, and the other
2749
+ standing at point p2, then this method will return the direction
2750
+ that the dude standing at p1 will need to face to look at p2.
2751
+
2752
+ p1 = Point(0, 0)
2753
+ p2 = Point(7, 3)
2754
+
2755
+ Point.direction(p1, p2)
2756
+ # => 0.40489178628508343
2757
+
2758
+ @name direction
2759
+ @fieldOf Point
2760
+ @param {Point} p1 The starting point.
2761
+ @param {Point} p2 The ending point.
2762
+ @returns {Number} The direction from p1 to p2 in radians.
2763
+ */
2764
+ Point.direction = function(p1, p2) {
2765
+ return Math.atan2(p2.y - p1.y, p2.x - p1.x);
2766
+ };
2767
+ /**
2768
+ The centroid of a set of points is their arithmetic mean.
2769
+
2770
+ @name centroid
2771
+ @methodOf Point
2772
+ @param points... The points to find the centroid of.
2773
+ */
2774
+ Point.centroid = function() {
2775
+ var points;
2776
+ points = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
2777
+ return points.inject(Point(0, 0), function(sumPoint, point) {
2778
+ return sumPoint.add(point);
2779
+ }).scale(1 / points.length);
2780
+ };
2781
+ /**
2782
+ Generate a random point on the unit circle.
2783
+
2784
+ @returns {Point} A random point on the unit circle.
2785
+ */
2786
+ Point.random = function() {
2787
+ return Point.fromAngle(Random.angle());
2788
+ };
2789
+ /**
2790
+ @name ZERO
2791
+ @fieldOf Point
2792
+ @returns {Point} The point (0, 0)
2793
+ */
2794
+ Point.ZERO = Point(0, 0);
2795
+ /**
2796
+ @name LEFT
2797
+ @fieldOf Point
2798
+ @returns {Point} The point (-1, 0)
2799
+ */
2800
+ Point.LEFT = Point(-1, 0);
2801
+ /**
2802
+ @name RIGHT
2803
+ @fieldOf Point
2804
+ @returns {Point} The point (1, 0)
2805
+ */
2806
+ Point.RIGHT = Point(1, 0);
2807
+ /**
2808
+ @name UP
2809
+ @fieldOf Point
2810
+ @returns {Point} The point (0, -1)
2811
+ */
2812
+ Point.UP = Point(0, -1);
2813
+ /**
2814
+ @name DOWN
2815
+ @fieldOf Point
2816
+ @returns {Point} The point (0, 1)
2817
+ */
2818
+ Point.DOWN = Point(0, 1);
2819
+ if (Object.freeze) {
2820
+ Object.freeze(Point.ZERO);
2821
+ Object.freeze(Point.LEFT);
2822
+ Object.freeze(Point.RIGHT);
2823
+ Object.freeze(Point.UP);
2824
+ Object.freeze(Point.DOWN);
2825
+ }
2826
+ return (typeof exports !== "undefined" && exports !== null ? exports : this)["Point"] = Point;
2827
+ })();
2828
+
2829
+
2830
+ (function() {
2831
+ /**
2832
+ @name Random
2833
+ @namespace Some useful methods for generating random things.
2834
+ */ (typeof exports !== "undefined" && exports !== null ? exports : this)["Random"] = {
2835
+ /**
2836
+ Returns a random angle, uniformly distributed, between 0 and 2pi.
2837
+
2838
+ @name angle
2839
+ @methodOf Random
2840
+ @returns {Number} A random angle between 0 and 2pi
2841
+ */
2842
+ angle: function() {
2843
+ return rand() * Math.TAU;
2844
+ },
2845
+ /**
2846
+ Returns a random angle between the given angles.
2847
+
2848
+ @name angleBetween
2849
+ @methodOf Random
2850
+ @returns {Number} A random angle between the angles given.
2851
+ */
2852
+ angleBetween: function(min, max) {
2853
+ return rand() * (max - min) + min;
2854
+ },
2855
+ /**
2856
+ Returns a random color.
2857
+
2858
+ @name color
2859
+ @methodOf Random
2860
+ @returns {Color} A random color
2861
+ */
2862
+ color: function() {
2863
+ return Color.random();
2864
+ },
2865
+ /**
2866
+ Happens often.
2867
+
2868
+ @name often
2869
+ @methodOf Random
2870
+ */
2871
+ often: function() {
2872
+ return rand(3);
2873
+ },
2874
+ /**
2875
+ Happens sometimes.
2876
+
2877
+ @name sometimes
2878
+ @methodOf Random
2879
+ */
2880
+ sometimes: function() {
2881
+ return !rand(3);
2882
+ }
2883
+ };
2884
+ /**
2885
+ Returns random integers from [0, n) if n is given.
2886
+ Otherwise returns random float between 0 and 1.
2887
+
2888
+ @name rand
2889
+ @methodOf window
2890
+ @param {Number} n
2891
+ @returns {Number} A random integer from 0 to n - 1 if n is given. If n is not given, a random float between 0 and 1.
2892
+ */
2893
+ (typeof exports !== "undefined" && exports !== null ? exports : this)["rand"] = function(n) {
2894
+ if (n) {
2895
+ return Math.floor(n * Math.random());
2896
+ } else {
2897
+ return Math.random();
2898
+ }
2899
+ };
2900
+ /**
2901
+ Returns random float from [-n / 2, n / 2] if n is given.
2902
+ Otherwise returns random float between -0.5 and 0.5.
2903
+
2904
+ @name signedRand
2905
+ @methodOf window
2906
+ @param {Number} n
2907
+ @returns {Number} A random float from -n / 2 to n / 2 if n is given. If n is not given, a random float between -0.5 and 0.5.
2908
+ */
2909
+ return (typeof exports !== "undefined" && exports !== null ? exports : this)["signedRand"] = function(n) {
2910
+ if (n) {
2911
+ return (n * Math.random()) - (n / 2);
2912
+ } else {
2913
+ return Math.random() - 0.5;
2914
+ }
2915
+ };
2916
+ })();
2917
+
2918
+
2919
+ (function() {
2920
+ var Rectangle;
2921
+ Rectangle = function(_arg) {
2922
+ var height, width, x, y;
2923
+ x = _arg.x, y = _arg.y, width = _arg.width, height = _arg.height;
2924
+ return {
2925
+ __proto__: Rectangle.prototype,
2926
+ x: x || 0,
2927
+ y: y || 0,
2928
+ width: width || 0,
2929
+ height: height || 0
2930
+ };
2931
+ };
2932
+ Rectangle.prototype = {
2933
+ center: function() {
2934
+ return Point(this.x + this.width / 2, this.y + this.height / 2);
2935
+ },
2936
+ equal: function(other) {
2937
+ return this.x === other.x && this.y === other.y && this.width === other.width && this.height === other.height;
2938
+ }
2939
+ };
2940
+ Rectangle.prototype.__defineGetter__('left', function() {
2941
+ return this.x;
2942
+ });
2943
+ Rectangle.prototype.__defineGetter__('right', function() {
2944
+ return this.x + this.width;
2945
+ });
2946
+ Rectangle.prototype.__defineGetter__('top', function() {
2947
+ return this.y;
2948
+ });
2949
+ Rectangle.prototype.__defineGetter__('bottom', function() {
2950
+ return this.y + this.height;
2951
+ });
2952
+ return (typeof exports !== "undefined" && exports !== null ? exports : this)["Rectangle"] = Rectangle;
2953
+ })();
2954
+
2955
+ /**
2956
+ Returns true if this string only contains whitespace characters.
2957
+
2958
+ "".blank()
2959
+ # => true
2960
+
2961
+ "hello".blank()
2962
+ # => false
2963
+
2964
+ " ".blank()
2965
+ # => true
2966
+
2967
+ @name blank
2968
+ @methodOf String#
2969
+ @returns {Boolean} Whether or not this string is blank.
2970
+ */
2971
+ String.prototype.blank = function() {
2972
+ return /^\s*$/.test(this);
2973
+ };
2974
+
2975
+ /**
2976
+ Returns a new string that is a camelCase version.
2977
+
2978
+ "camel_case".camelize()
2979
+ "camel-case".camelize()
2980
+ "camel case".camelize()
2981
+
2982
+ # => "camelCase"
2983
+
2984
+ @name camelize
2985
+ @methodOf String#
2986
+ @returns {String} A new string. camelCase version of `this`.
2987
+ */
2988
+
2989
+ String.prototype.camelize = function() {
2990
+ return this.trim().replace(/(\-|_|\s)+(.)?/g, function(match, separator, chr) {
2991
+ if (chr) {
2992
+ return chr.toUpperCase();
2993
+ } else {
2994
+ return '';
2995
+ }
2996
+ });
2997
+ };
2998
+
2999
+ /**
3000
+ Returns a new string with the first letter capitalized and the rest lower cased.
3001
+
3002
+ "capital".capitalize()
3003
+ "cAPITAL".capitalize()
3004
+ "cApItAl".capitalize()
3005
+ "CAPITAL".capitalize()
3006
+
3007
+ # => "Capital"
3008
+
3009
+ @name capitalize
3010
+ @methodOf String#
3011
+ @returns {String} A new string. Capitalized version of `this`
3012
+ */
3013
+
3014
+ String.prototype.capitalize = function() {
3015
+ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
3016
+ };
3017
+
3018
+ /**
3019
+ Return the class or constant named in this string.
3020
+
3021
+
3022
+ "Constant".constantize()
3023
+ # => Constant
3024
+ # notice this isn't a string. Useful for calling methods on class with the same name as `this`.
3025
+
3026
+ @name constantize
3027
+ @methodOf String#
3028
+ @returns {Object} The class or constant named in this string.
3029
+ */
3030
+
3031
+ String.prototype.constantize = function() {
3032
+ var item, target, _i, _len, _ref;
3033
+ target = typeof exports !== "undefined" && exports !== null ? exports : window;
3034
+ _ref = this.split('.');
3035
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
3036
+ item = _ref[_i];
3037
+ target = target[item];
3038
+ }
3039
+ return target;
3040
+ };
3041
+
3042
+ /**
3043
+ Get the file extension of a string.
3044
+
3045
+ "README.md".extension() # => "md"
3046
+ "README".extension() # => ""
3047
+
3048
+ @name extension
3049
+ @methodOf String#
3050
+ @returns {String} File extension
3051
+ */
3052
+
3053
+ String.prototype.extension = function() {
3054
+ var extension, _ref;
3055
+ if (extension = (_ref = this.match(/\.([^\.]*)$/, '')) != null ? _ref.last() : void 0) {
3056
+ return extension;
3057
+ } else {
3058
+ return '';
3059
+ }
3060
+ };
3061
+
3062
+ /**
3063
+ Returns a new string that is a more human readable version.
3064
+
3065
+ "player_id".humanize()
3066
+ # => "Player"
3067
+
3068
+ "player_ammo".humanize()
3069
+ # => "Player ammo"
3070
+
3071
+ @name humanize
3072
+ @methodOf String#
3073
+ @returns {String} A new string. Replaces _id and _ with "" and capitalizes the word.
3074
+ */
3075
+
3076
+ String.prototype.humanize = function() {
3077
+ return this.replace(/_id$/, "").replace(/_/g, " ").capitalize();
3078
+ };
3079
+
3080
+ /**
3081
+ Returns true.
3082
+
3083
+ @name isString
3084
+ @methodOf String#
3085
+ @returns {Boolean} true
3086
+ */
3087
+
3088
+ String.prototype.isString = function() {
3089
+ return true;
3090
+ };
3091
+
3092
+ /**
3093
+ Parse this string as though it is JSON and return the object it represents. If it
3094
+ is not valid JSON returns the string itself.
3095
+
3096
+ # this is valid json, so an object is returned
3097
+ '{"a": 3}'.parse()
3098
+ # => {a: 3}
3099
+
3100
+ # double quoting instead isn't valid JSON so a string is returned
3101
+ "{'a': 3}".parse()
3102
+ # => "{'a': 3}"
3103
+
3104
+
3105
+ @name parse
3106
+ @methodOf String#
3107
+ @returns {Object} Returns an object from the JSON this string contains. If it is not valid JSON returns the string itself.
3108
+ */
3109
+
3110
+ String.prototype.parse = function() {
3111
+ try {
3112
+ return JSON.parse(this.toString());
3113
+ } catch (e) {
3114
+ return this.toString();
3115
+ }
3116
+ };
3117
+
3118
+ /**
3119
+ Returns true if this string starts with the given string.
3120
+
3121
+ @name startsWith
3122
+ @methodOf String#
3123
+ @param {String} str The string to check.
3124
+
3125
+ @returns {Boolean} True if this string starts with the given string, false otherwise.
3126
+ */
3127
+
3128
+ String.prototype.startsWith = function(str) {
3129
+ return this.lastIndexOf(str, 0) === 0;
3130
+ };
3131
+
3132
+ /**
3133
+ Returns a new string in Title Case.
3134
+
3135
+ "title-case".titleize()
3136
+ # => "Title Case"
3137
+
3138
+ "title case".titleize()
3139
+ # => "Title Case"
3140
+
3141
+ @name titleize
3142
+ @methodOf String#
3143
+ @returns {String} A new string. Title Cased.
3144
+ */
3145
+
3146
+ String.prototype.titleize = function() {
3147
+ return this.split(/[- ]/).map(function(word) {
3148
+ return word.capitalize();
3149
+ }).join(' ');
3150
+ };
3151
+
3152
+ /**
3153
+ Underscore a word, changing camelCased with under_scored.
3154
+
3155
+ "UNDERScore".underscore()
3156
+ # => "under_score"
3157
+
3158
+ "UNDER-SCORE".underscore()
3159
+ # => "under_score"
3160
+
3161
+ "UnDEr-SCorE".underscore()
3162
+ # => "un_d_er_s_cor_e"
3163
+
3164
+ @name underscore
3165
+ @methodOf String#
3166
+ @returns {String} A new string. Separated by _.
3167
+ */
3168
+
3169
+ String.prototype.underscore = function() {
3170
+ return this.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2').replace(/([a-z\d])([A-Z])/g, '$1_$2').replace(/-/g, '_').toLowerCase();
3171
+ };
3172
+
3173
+ /**
3174
+ Assumes the string is something like a file name and returns the
3175
+ contents of the string without the extension.
3176
+
3177
+ "neat.png".witouthExtension()
3178
+ # => "neat"
3179
+
3180
+ @name withoutExtension
3181
+ @methodOf String#
3182
+ @returns {String} A new string without the extension name.
3183
+ */
3184
+
3185
+ String.prototype.withoutExtension = function() {
3186
+ return this.replace(/\.[^\.]*$/, '');
3187
+ };
3188
+
3189
+ String.prototype.toInt = function(base) {
3190
+ if (base == null) base = 10;
3191
+ return parseInt(this, base);
3192
+ };
3193
+
3194
+ String.prototype.parseHex = function() {
3195
+ var alpha, hexString, i, rgb;
3196
+ hexString = this.replace(/#/, '');
3197
+ switch (hexString.length) {
3198
+ case 3:
3199
+ case 4:
3200
+ if (hexString.length === 4) {
3201
+ alpha = (parseInt(hexString.substr(3, 1), 16) * 0x11) / 255;
3202
+ } else {
3203
+ alpha = 1;
3204
+ }
3205
+ rgb = (function() {
3206
+ var _results;
3207
+ _results = [];
3208
+ for (i = 0; i <= 2; i++) {
3209
+ _results.push(parseInt(hexString.substr(i, 1), 16) * 0x11);
3210
+ }
3211
+ return _results;
3212
+ })();
3213
+ rgb.push(alpha);
3214
+ return rgb;
3215
+ case 6:
3216
+ case 8:
3217
+ if (hexString.length === 8) {
3218
+ alpha = parseInt(hexString.substr(6, 2), 16) / 255;
3219
+ } else {
3220
+ alpha = 1;
3221
+ }
3222
+ rgb = (function() {
3223
+ var _results;
3224
+ _results = [];
3225
+ for (i = 0; i <= 2; i++) {
3226
+ _results.push(parseInt(hexString.substr(2 * i, 2), 16));
3227
+ }
3228
+ return _results;
3229
+ })();
3230
+ rgb.push(alpha);
3231
+ return rgb;
3232
+ }
3233
+ };
3234
+
3235
+ /*!
3236
+ Math.uuid.js (v1.4)
3237
+ http://www.broofa.com
3238
+ mailto:robert@broofa.com
3239
+
3240
+ Copyright (c) 2010 Robert Kieffer
3241
+ Dual licensed under the MIT and GPL licenses.
3242
+ */
3243
+
3244
+ /**
3245
+ Generate a random uuid.
3246
+
3247
+ <code><pre>
3248
+ // No arguments - returns RFC4122, version 4 ID
3249
+ Math.uuid()
3250
+ => "92329D39-6F5C-4520-ABFC-AAB64544E172"
3251
+
3252
+ // One argument - returns ID of the specified length
3253
+ Math.uuid(15) // 15 character ID (default base=62)
3254
+ => "VcydxgltxrVZSTV"
3255
+
3256
+ // Two arguments - returns ID of the specified length, and radix. (Radix must be <= 62)
3257
+ Math.uuid(8, 2) // 8 character ID (base=2)
3258
+ => "01001010"
3259
+
3260
+ Math.uuid(8, 10) // 8 character ID (base=10)
3261
+ => "47473046"
3262
+
3263
+ Math.uuid(8, 16) // 8 character ID (base=16)
3264
+ => "098F4D35"
3265
+ </pre></code>
3266
+
3267
+ @name uuid
3268
+ @methodOf Math
3269
+ @param length The desired number of characters
3270
+ @param radix The number of allowable values for each character.
3271
+ */
3272
+ (function() {
3273
+ // Private array of chars to use
3274
+ var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
3275
+
3276
+ Math.uuid = function (len, radix) {
3277
+ var chars = CHARS, uuid = [];
3278
+ radix = radix || chars.length;
3279
+
3280
+ if (len) {
3281
+ // Compact form
3282
+ for (var i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
3283
+ } else {
3284
+ // rfc4122, version 4 form
3285
+ var r;
3286
+
3287
+ // rfc4122 requires these characters
3288
+ uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
3289
+ uuid[14] = '4';
3290
+
3291
+ // Fill in random data. At i==19 set the high bits of clock sequence as
3292
+ // per rfc4122, sec. 4.1.5
3293
+ for (var i = 0; i < 36; i++) {
3294
+ if (!uuid[i]) {
3295
+ r = 0 | Math.random()*16;
3296
+ uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
3297
+ }
3298
+ }
3299
+ }
3300
+
3301
+ return uuid.join('');
3302
+ };
3303
+
3304
+ // A more performant, but slightly bulkier, RFC4122v4 solution. We boost performance
3305
+ // by minimizing calls to random()
3306
+ Math.uuidFast = function() {
3307
+ var chars = CHARS, uuid = new Array(36), rnd=0, r;
3308
+ for (var i = 0; i < 36; i++) {
3309
+ if (i==8 || i==13 || i==18 || i==23) {
3310
+ uuid[i] = '-';
3311
+ } else if (i==14) {
3312
+ uuid[i] = '4';
3313
+ } else {
3314
+ if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0;
3315
+ r = rnd & 0xf;
3316
+ rnd = rnd >> 4;
3317
+ uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
3318
+ }
3319
+ }
3320
+ return uuid.join('');
3321
+ };
3322
+
3323
+ // A more compact, but less performant, RFC4122v4 solution:
3324
+ Math.uuidCompact = function() {
3325
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
3326
+ var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
3327
+ return v.toString(16);
3328
+ }).toUpperCase();
3329
+ };
3330
+ })();
3331
+