dashing-beanstalk 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +9 -0
  3. data/bin/dashing +124 -0
  4. data/javascripts/batman.jquery.js +163 -0
  5. data/javascripts/batman.js +13680 -0
  6. data/javascripts/dashing.coffee +125 -0
  7. data/javascripts/es5-shim.js +1021 -0
  8. data/javascripts/jquery.js +4 -0
  9. data/lib/dashing.rb +160 -0
  10. data/lib/scheduler.rb +58 -0
  11. data/templates/dashboard/%name%.erb.tt +7 -0
  12. data/templates/job/%name%.rb +4 -0
  13. data/templates/project/.gitignore +2 -0
  14. data/templates/project/Gemfile +6 -0
  15. data/templates/project/README.md +1 -0
  16. data/templates/project/assets/fonts/fontawesome-webfont.eot +0 -0
  17. data/templates/project/assets/fonts/fontawesome-webfont.svg +399 -0
  18. data/templates/project/assets/fonts/fontawesome-webfont.ttf +0 -0
  19. data/templates/project/assets/fonts/fontawesome-webfont.woff +0 -0
  20. data/templates/project/assets/images/logo.png +0 -0
  21. data/templates/project/assets/javascripts/application.coffee +25 -0
  22. data/templates/project/assets/javascripts/d3-3.2.8.js +5 -0
  23. data/templates/project/assets/javascripts/dashing.gridster.coffee +37 -0
  24. data/templates/project/assets/javascripts/gridster/jquery.gridster.js +3263 -0
  25. data/templates/project/assets/javascripts/gridster/jquery.leanModal.min.js +5 -0
  26. data/templates/project/assets/javascripts/jquery.knob.js +646 -0
  27. data/templates/project/assets/javascripts/rickshaw-1.4.3.min.js +2 -0
  28. data/templates/project/assets/stylesheets/application.scss +257 -0
  29. data/templates/project/assets/stylesheets/font-awesome.css +1479 -0
  30. data/templates/project/assets/stylesheets/jquery.gridster.css +57 -0
  31. data/templates/project/config.ru +18 -0
  32. data/templates/project/dashboards/layout.erb +32 -0
  33. data/templates/project/dashboards/sample.erb +25 -0
  34. data/templates/project/dashboards/sampletv.erb +56 -0
  35. data/templates/project/jobs/buzzwords.rb +9 -0
  36. data/templates/project/jobs/convergence.rb +14 -0
  37. data/templates/project/jobs/sample.rb +13 -0
  38. data/templates/project/jobs/twitter.rb +28 -0
  39. data/templates/project/lib/.empty_directory +1 -0
  40. data/templates/project/public/404.html +26 -0
  41. data/templates/project/public/favicon.ico +0 -0
  42. data/templates/project/widgets/clock/clock.coffee +18 -0
  43. data/templates/project/widgets/clock/clock.html +2 -0
  44. data/templates/project/widgets/clock/clock.scss +13 -0
  45. data/templates/project/widgets/comments/comments.coffee +24 -0
  46. data/templates/project/widgets/comments/comments.html +7 -0
  47. data/templates/project/widgets/comments/comments.scss +33 -0
  48. data/templates/project/widgets/graph/graph.coffee +36 -0
  49. data/templates/project/widgets/graph/graph.html +5 -0
  50. data/templates/project/widgets/graph/graph.scss +65 -0
  51. data/templates/project/widgets/iframe/iframe.coffee +9 -0
  52. data/templates/project/widgets/iframe/iframe.html +1 -0
  53. data/templates/project/widgets/iframe/iframe.scss +8 -0
  54. data/templates/project/widgets/image/image.coffee +9 -0
  55. data/templates/project/widgets/image/image.html +1 -0
  56. data/templates/project/widgets/image/image.scss +13 -0
  57. data/templates/project/widgets/list/list.coffee +6 -0
  58. data/templates/project/widgets/list/list.html +18 -0
  59. data/templates/project/widgets/list/list.scss +60 -0
  60. data/templates/project/widgets/meter/meter.coffee +14 -0
  61. data/templates/project/widgets/meter/meter.html +7 -0
  62. data/templates/project/widgets/meter/meter.scss +35 -0
  63. data/templates/project/widgets/number/number.coffee +24 -0
  64. data/templates/project/widgets/number/number.html +11 -0
  65. data/templates/project/widgets/number/number.scss +39 -0
  66. data/templates/project/widgets/text/text.coffee +1 -0
  67. data/templates/project/widgets/text/text.html +7 -0
  68. data/templates/project/widgets/text/text.scss +32 -0
  69. data/templates/widget/%name%/%name%.coffee.tt +9 -0
  70. data/templates/widget/%name%/%name%.html +1 -0
  71. data/templates/widget/%name%/%name%.scss.tt +3 -0
  72. metadata +272 -0
@@ -0,0 +1,125 @@
1
+ #= require jquery
2
+ #= require es5-shim
3
+ #= require batman
4
+ #= require batman.jquery
5
+
6
+
7
+ Batman.Filters.prettyNumber = (num) ->
8
+ num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") unless isNaN(num)
9
+
10
+ Batman.Filters.dashize = (str) ->
11
+ dashes_rx1 = /([A-Z]+)([A-Z][a-z])/g;
12
+ dashes_rx2 = /([a-z\d])([A-Z])/g;
13
+
14
+ return str.replace(dashes_rx1, '$1_$2').replace(dashes_rx2, '$1_$2').replace(/_/g, '-').toLowerCase()
15
+
16
+ Batman.Filters.shortenedNumber = (num) ->
17
+ return num if isNaN(num)
18
+ if num >= 1000000000
19
+ (num / 1000000000).toFixed(1) + 'B'
20
+ else if num >= 1000000
21
+ (num / 1000000).toFixed(1) + 'M'
22
+ else if num >= 1000
23
+ (num / 1000).toFixed(1) + 'K'
24
+ else
25
+ num
26
+
27
+ class window.Dashing extends Batman.App
28
+ @on 'reload', (data) ->
29
+ window.location.reload(true)
30
+
31
+ @root ->
32
+ Dashing.params = Batman.URI.paramsFromQuery(window.location.search.slice(1));
33
+
34
+ class Dashing.Widget extends Batman.View
35
+ constructor: ->
36
+ # Set the view path
37
+ @constructor::source = Batman.Filters.underscore(@constructor.name)
38
+ super
39
+
40
+ @mixin($(@node).data())
41
+ Dashing.widgets[@id] ||= []
42
+ Dashing.widgets[@id].push(@)
43
+ @mixin(Dashing.lastEvents[@id]) # in case the events from the server came before the widget was rendered
44
+
45
+ type = Batman.Filters.dashize(@view)
46
+ $(@node).addClass("widget widget-#{type} #{@id}")
47
+
48
+ @accessor 'updatedAtMessage', ->
49
+ if updatedAt = @get('updatedAt')
50
+ timestamp = new Date(updatedAt * 1000)
51
+ hours = timestamp.getHours()
52
+ minutes = ("0" + timestamp.getMinutes()).slice(-2)
53
+ "Last updated at #{hours}:#{minutes}"
54
+
55
+ @::on 'ready', ->
56
+ Dashing.Widget.fire 'ready'
57
+
58
+ receiveData: (data) =>
59
+ @mixin(data)
60
+ @onData(data)
61
+
62
+ onData: (data) =>
63
+ # Widgets override this to handle incoming data
64
+
65
+ Dashing.AnimatedValue =
66
+ get: Batman.Property.defaultAccessor.get
67
+ set: (k, to) ->
68
+ if !to? || isNaN(to)
69
+ @[k] = to
70
+ else
71
+ timer = "interval_#{k}"
72
+ num = if (!isNaN(@[k]) && @[k]?) then @[k] else 0
73
+ unless @[timer] || num == to
74
+ to = parseFloat(to)
75
+ num = parseFloat(num)
76
+ up = to > num
77
+ num_interval = Math.abs(num - to) / 90
78
+ @[timer] =
79
+ setInterval =>
80
+ num = if up then Math.ceil(num+num_interval) else Math.floor(num-num_interval)
81
+ if (up && num > to) || (!up && num < to)
82
+ num = to
83
+ clearInterval(@[timer])
84
+ @[timer] = null
85
+ delete @[timer]
86
+ @[k] = num
87
+ @set k, to
88
+ , 10
89
+ @[k] = num
90
+
91
+ Dashing.widgets = widgets = {}
92
+ Dashing.lastEvents = lastEvents = {}
93
+ Dashing.debugMode = false
94
+
95
+ source = new EventSource('events')
96
+ source.addEventListener 'open', (e) ->
97
+ console.log("Connection opened", e)
98
+
99
+ source.addEventListener 'error', (e)->
100
+ console.log("Connection error", e)
101
+ if (e.currentTarget.readyState == EventSource.CLOSED)
102
+ console.log("Connection closed")
103
+ setTimeout (->
104
+ window.location.reload()
105
+ ), 5*60*1000
106
+
107
+ source.addEventListener 'message', (e) ->
108
+ data = JSON.parse(e.data)
109
+ if lastEvents[data.id]?.updatedAt != data.updatedAt
110
+ if Dashing.debugMode
111
+ console.log("Received data for #{data.id}", data)
112
+ lastEvents[data.id] = data
113
+ if widgets[data.id]?.length > 0
114
+ for widget in widgets[data.id]
115
+ widget.receiveData(data)
116
+
117
+ source.addEventListener 'dashboards', (e) ->
118
+ data = JSON.parse(e.data)
119
+ if Dashing.debugMode
120
+ console.log("Received data for dashboards", data)
121
+ if data.dashboard is '*' or window.location.pathname is "/#{data.dashboard}"
122
+ Dashing.fire data.event, data
123
+
124
+ $(document).ready ->
125
+ Dashing.run()
@@ -0,0 +1,1021 @@
1
+ // vim: ts=4 sts=4 sw=4 expandtab
2
+ // -- kriskowal Kris Kowal Copyright (C) 2009-2011 MIT License
3
+ // -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project)
4
+ // -- dantman Daniel Friesen Copyright (C) 2010 XXX TODO License or CLA
5
+ // -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License
6
+ // -- Gozala Irakli Gozalishvili Copyright (C) 2010 MIT License
7
+ // -- kitcambridge Kit Cambridge Copyright (C) 2011 MIT License
8
+ // -- kossnocorp Sasha Koss XXX TODO License or CLA
9
+ // -- bryanforbes Bryan Forbes XXX TODO License or CLA
10
+ // -- killdream Quildreen Motta Copyright (C) 2011 MIT Licence
11
+ // -- michaelficarra Michael Ficarra Copyright (C) 2011 3-clause BSD License
12
+ // -- sharkbrainguy Gerard Paapu Copyright (C) 2011 MIT License
13
+ // -- bbqsrc Brendan Molloy XXX TODO License or CLA
14
+ // -- iwyg XXX TODO License or CLA
15
+ // -- DomenicDenicola Domenic Denicola XXX TODO License or CLA
16
+ // -- xavierm02 Montillet Xavier XXX TODO License or CLA
17
+ // -- Raynos Raynos XXX TODO License or CLA
18
+ // -- samsonjs Sami Samhuri XXX TODO License or CLA
19
+ // -- rwldrn Rick Waldron Copyright (C) 2011 MIT License
20
+ // -- lexer Alexey Zakharov XXX TODO License or CLA
21
+
22
+ /*!
23
+ Copyright (c) 2009, 280 North Inc. http://280north.com/
24
+ MIT License. http://github.com/280north/narwhal/blob/master/README.md
25
+ */
26
+
27
+ // Module systems magic dance
28
+ (function (definition) {
29
+ // RequireJS
30
+ if (typeof define == "function") {
31
+ define(definition);
32
+ // CommonJS and <script>
33
+ } else {
34
+ definition();
35
+ }
36
+ })(function () {
37
+
38
+ /**
39
+ * Brings an environment as close to ECMAScript 5 compliance
40
+ * as is possible with the facilities of erstwhile engines.
41
+ *
42
+ * ES5 Draft
43
+ * http://www.ecma-international.org/publications/files/drafts/tc39-2009-050.pdf
44
+ *
45
+ * NOTE: this is a draft, and as such, the URL is subject to change. If the
46
+ * link is broken, check in the parent directory for the latest TC39 PDF.
47
+ * http://www.ecma-international.org/publications/files/drafts/
48
+ *
49
+ * Previous ES5 Draft
50
+ * http://www.ecma-international.org/publications/files/drafts/tc39-2009-025.pdf
51
+ * This is a broken link to the previous draft of ES5 on which most of the
52
+ * numbered specification references and quotes herein were taken. Updating
53
+ * these references and quotes to reflect the new document would be a welcome
54
+ * volunteer project.
55
+ *
56
+ * @module
57
+ */
58
+
59
+ /*whatsupdoc*/
60
+
61
+ //
62
+ // Function
63
+ // ========
64
+ //
65
+
66
+ // ES-5 15.3.4.5
67
+ // http://www.ecma-international.org/publications/files/drafts/tc39-2009-025.pdf
68
+
69
+ if (!Function.prototype.bind) {
70
+ Function.prototype.bind = function bind(that) { // .length is 1
71
+ // 1. Let Target be the this value.
72
+ var target = this;
73
+ // 2. If IsCallable(Target) is false, throw a TypeError exception.
74
+ if (typeof target != "function")
75
+ throw new TypeError(); // TODO message
76
+ // 3. Let A be a new (possibly empty) internal list of all of the
77
+ // argument values provided after thisArg (arg1, arg2 etc), in order.
78
+ // XXX slicedArgs will stand in for "A" if used
79
+ var args = slice.call(arguments, 1); // for normal call
80
+ // 4. Let F be a new native ECMAScript object.
81
+ // 9. Set the [[Prototype]] internal property of F to the standard
82
+ // built-in Function prototype object as specified in 15.3.3.1.
83
+ // 10. Set the [[Call]] internal property of F as described in
84
+ // 15.3.4.5.1.
85
+ // 11. Set the [[Construct]] internal property of F as described in
86
+ // 15.3.4.5.2.
87
+ // 12. Set the [[HasInstance]] internal property of F as described in
88
+ // 15.3.4.5.3.
89
+ // 13. The [[Scope]] internal property of F is unused and need not
90
+ // exist.
91
+ var bound = function () {
92
+
93
+ if (this instanceof bound) {
94
+ // 15.3.4.5.2 [[Construct]]
95
+ // When the [[Construct]] internal method of a function object,
96
+ // F that was created using the bind function is called with a
97
+ // list of arguments ExtraArgs the following steps are taken:
98
+ // 1. Let target be the value of F's [[TargetFunction]]
99
+ // internal property.
100
+ // 2. If target has no [[Construct]] internal method, a
101
+ // TypeError exception is thrown.
102
+ // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
103
+ // property.
104
+ // 4. Let args be a new list containing the same values as the
105
+ // list boundArgs in the same order followed by the same
106
+ // values as the list ExtraArgs in the same order.
107
+
108
+ var F = function(){};
109
+ F.prototype = target.prototype;
110
+ var self = new F;
111
+
112
+ var result = target.apply(
113
+ self,
114
+ args.concat(slice.call(arguments))
115
+ );
116
+ if (result !== null && Object(result) === result)
117
+ return result;
118
+ return self;
119
+
120
+ } else {
121
+ // 15.3.4.5.1 [[Call]]
122
+ // When the [[Call]] internal method of a function object, F,
123
+ // which was created using the bind function is called with a
124
+ // this value and a list of arguments ExtraArgs the following
125
+ // steps are taken:
126
+ // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
127
+ // property.
128
+ // 2. Let boundThis be the value of F's [[BoundThis]] internal
129
+ // property.
130
+ // 3. Let target be the value of F's [[TargetFunction]] internal
131
+ // property.
132
+ // 4. Let args be a new list containing the same values as the list
133
+ // boundArgs in the same order followed by the same values as
134
+ // the list ExtraArgs in the same order. 5. Return the
135
+ // result of calling the [[Call]] internal method of target
136
+ // providing boundThis as the this value and providing args
137
+ // as the arguments.
138
+
139
+ // equiv: target.call(this, ...boundArgs, ...args)
140
+ return target.apply(
141
+ that,
142
+ args.concat(slice.call(arguments))
143
+ );
144
+
145
+ }
146
+
147
+ };
148
+ // XXX bound.length is never writable, so don't even try
149
+ //
150
+ // 16. The length own property of F is given attributes as specified in
151
+ // 15.3.5.1.
152
+ // TODO
153
+ // 17. Set the [[Extensible]] internal property of F to true.
154
+ // TODO
155
+ // 18. Call the [[DefineOwnProperty]] internal method of F with
156
+ // arguments "caller", PropertyDescriptor {[[Value]]: null,
157
+ // [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]:
158
+ // false}, and false.
159
+ // TODO
160
+ // 19. Call the [[DefineOwnProperty]] internal method of F with
161
+ // arguments "arguments", PropertyDescriptor {[[Value]]: null,
162
+ // [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]:
163
+ // false}, and false.
164
+ // TODO
165
+ // NOTE Function objects created using Function.prototype.bind do not
166
+ // have a prototype property.
167
+ // XXX can't delete it in pure-js.
168
+ return bound;
169
+ };
170
+ }
171
+
172
+ // Shortcut to an often accessed properties, in order to avoid multiple
173
+ // dereference that costs universally.
174
+ // _Please note: Shortcuts are defined after `Function.prototype.bind` as we
175
+ // us it in defining shortcuts.
176
+ var call = Function.prototype.call;
177
+ var prototypeOfArray = Array.prototype;
178
+ var prototypeOfObject = Object.prototype;
179
+ var slice = prototypeOfArray.slice;
180
+ var toString = call.bind(prototypeOfObject.toString);
181
+ var owns = call.bind(prototypeOfObject.hasOwnProperty);
182
+
183
+ // If JS engine supports accessors creating shortcuts.
184
+ var defineGetter;
185
+ var defineSetter;
186
+ var lookupGetter;
187
+ var lookupSetter;
188
+ var supportsAccessors;
189
+ if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
190
+ defineGetter = call.bind(prototypeOfObject.__defineGetter__);
191
+ defineSetter = call.bind(prototypeOfObject.__defineSetter__);
192
+ lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
193
+ lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
194
+ }
195
+
196
+ //
197
+ // Array
198
+ // =====
199
+ //
200
+
201
+ // ES5 15.4.3.2
202
+ if (!Array.isArray) {
203
+ Array.isArray = function isArray(obj) {
204
+ return toString(obj) == "[object Array]";
205
+ };
206
+ }
207
+
208
+ // The IsCallable() check in the Array functions
209
+ // has been replaced with a strict check on the
210
+ // internal class of the object to trap cases where
211
+ // the provided function was actually a regular
212
+ // expression literal, which in V8 and
213
+ // JavaScriptCore is a typeof "function". Only in
214
+ // V8 are regular expression literals permitted as
215
+ // reduce parameters, so it is desirable in the
216
+ // general case for the shim to match the more
217
+ // strict and common behavior of rejecting regular
218
+ // expressions.
219
+
220
+ // ES5 15.4.4.18
221
+ // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach
222
+ if (!Array.prototype.forEach) {
223
+ Array.prototype.forEach = function forEach(fun /*, thisp*/) {
224
+ var self = toObject(this),
225
+ thisp = arguments[1],
226
+ i = 0,
227
+ length = self.length >>> 0;
228
+
229
+ // If no callback function or if callback is not a callable function
230
+ if (toString(fun) != "[object Function]") {
231
+ throw new TypeError(); // TODO message
232
+ }
233
+
234
+ while (i < length) {
235
+ if (i in self) {
236
+ // Invoke the callback function with call, passing arguments:
237
+ // context, property value, property key, thisArg object context
238
+ fun.call(thisp, self[i], i, self);
239
+ }
240
+ i++;
241
+ }
242
+ };
243
+ }
244
+
245
+ // ES5 15.4.4.19
246
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
247
+ if (!Array.prototype.map) {
248
+ Array.prototype.map = function map(fun /*, thisp*/) {
249
+ var self = toObject(this),
250
+ length = self.length >>> 0,
251
+ result = Array(length),
252
+ thisp = arguments[1];
253
+
254
+ // If no callback function or if callback is not a callable function
255
+ if (toString(fun) != "[object Function]") {
256
+ throw new TypeError(); // TODO message
257
+ }
258
+
259
+ for (var i = 0; i < length; i++) {
260
+ if (i in self)
261
+ result[i] = fun.call(thisp, self[i], i, self);
262
+ }
263
+ return result;
264
+ };
265
+ }
266
+
267
+ // ES5 15.4.4.20
268
+ if (!Array.prototype.filter) {
269
+ Array.prototype.filter = function filter(fun /*, thisp */) {
270
+ var self = toObject(this),
271
+ length = self.length >>> 0,
272
+ result = [],
273
+ thisp = arguments[1];
274
+
275
+ // If no callback function or if callback is not a callable function
276
+ if (toString(fun) != "[object Function]") {
277
+ throw new TypeError(); // TODO message
278
+ }
279
+
280
+ for (var i = 0; i < length; i++) {
281
+ if (i in self && fun.call(thisp, self[i], i, self))
282
+ result.push(self[i]);
283
+ }
284
+ return result;
285
+ };
286
+ }
287
+
288
+ // ES5 15.4.4.16
289
+ if (!Array.prototype.every) {
290
+ Array.prototype.every = function every(fun /*, thisp */) {
291
+ var self = toObject(this),
292
+ length = self.length >>> 0,
293
+ thisp = arguments[1];
294
+
295
+ // If no callback function or if callback is not a callable function
296
+ if (toString(fun) != "[object Function]") {
297
+ throw new TypeError(); // TODO message
298
+ }
299
+
300
+ for (var i = 0; i < length; i++) {
301
+ if (i in self && !fun.call(thisp, self[i], i, self))
302
+ return false;
303
+ }
304
+ return true;
305
+ };
306
+ }
307
+
308
+ // ES5 15.4.4.17
309
+ // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
310
+ if (!Array.prototype.some) {
311
+ Array.prototype.some = function some(fun /*, thisp */) {
312
+ var self = toObject(this),
313
+ length = self.length >>> 0,
314
+ thisp = arguments[1];
315
+
316
+ // If no callback function or if callback is not a callable function
317
+ if (toString(fun) != "[object Function]") {
318
+ throw new TypeError(); // TODO message
319
+ }
320
+
321
+ for (var i = 0; i < length; i++) {
322
+ if (i in self && fun.call(thisp, self[i], i, self))
323
+ return true;
324
+ }
325
+ return false;
326
+ };
327
+ }
328
+
329
+ // ES5 15.4.4.21
330
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
331
+ if (!Array.prototype.reduce) {
332
+ Array.prototype.reduce = function reduce(fun /*, initial*/) {
333
+ var self = toObject(this),
334
+ length = self.length >>> 0;
335
+
336
+ // If no callback function or if callback is not a callable function
337
+ if (toString(fun) != "[object Function]") {
338
+ throw new TypeError(); // TODO message
339
+ }
340
+
341
+ // no value to return if no initial value and an empty array
342
+ if (!length && arguments.length == 1)
343
+ throw new TypeError(); // TODO message
344
+
345
+ var i = 0;
346
+ var result;
347
+ if (arguments.length >= 2) {
348
+ result = arguments[1];
349
+ } else {
350
+ do {
351
+ if (i in self) {
352
+ result = self[i++];
353
+ break;
354
+ }
355
+
356
+ // if array contains no values, no initial value to return
357
+ if (++i >= length)
358
+ throw new TypeError(); // TODO message
359
+ } while (true);
360
+ }
361
+
362
+ for (; i < length; i++) {
363
+ if (i in self)
364
+ result = fun.call(void 0, result, self[i], i, self);
365
+ }
366
+
367
+ return result;
368
+ };
369
+ }
370
+
371
+ // ES5 15.4.4.22
372
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
373
+ if (!Array.prototype.reduceRight) {
374
+ Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
375
+ var self = toObject(this),
376
+ length = self.length >>> 0;
377
+
378
+ // If no callback function or if callback is not a callable function
379
+ if (toString(fun) != "[object Function]") {
380
+ throw new TypeError(); // TODO message
381
+ }
382
+
383
+ // no value to return if no initial value, empty array
384
+ if (!length && arguments.length == 1)
385
+ throw new TypeError(); // TODO message
386
+
387
+ var result, i = length - 1;
388
+ if (arguments.length >= 2) {
389
+ result = arguments[1];
390
+ } else {
391
+ do {
392
+ if (i in self) {
393
+ result = self[i--];
394
+ break;
395
+ }
396
+
397
+ // if array contains no values, no initial value to return
398
+ if (--i < 0)
399
+ throw new TypeError(); // TODO message
400
+ } while (true);
401
+ }
402
+
403
+ do {
404
+ if (i in this)
405
+ result = fun.call(void 0, result, self[i], i, self);
406
+ } while (i--);
407
+
408
+ return result;
409
+ };
410
+ }
411
+
412
+ // ES5 15.4.4.14
413
+ // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
414
+ if (!Array.prototype.indexOf) {
415
+ Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
416
+ var self = toObject(this),
417
+ length = self.length >>> 0;
418
+
419
+ if (!length)
420
+ return -1;
421
+
422
+ var i = 0;
423
+ if (arguments.length > 1)
424
+ i = toInteger(arguments[1]);
425
+
426
+ // handle negative indices
427
+ i = i >= 0 ? i : length - Math.abs(i);
428
+ for (; i < length; i++) {
429
+ if (i in self && self[i] === sought) {
430
+ return i;
431
+ }
432
+ }
433
+ return -1;
434
+ };
435
+ }
436
+
437
+ // ES5 15.4.4.15
438
+ if (!Array.prototype.lastIndexOf) {
439
+ Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
440
+ var self = toObject(this),
441
+ length = self.length >>> 0;
442
+
443
+ if (!length)
444
+ return -1;
445
+ var i = length - 1;
446
+ if (arguments.length > 1)
447
+ i = toInteger(arguments[1]);
448
+ // handle negative indices
449
+ i = i >= 0 ? i : length - Math.abs(i);
450
+ for (; i >= 0; i--) {
451
+ if (i in self && sought === self[i])
452
+ return i;
453
+ }
454
+ return -1;
455
+ };
456
+ }
457
+
458
+ //
459
+ // Object
460
+ // ======
461
+ //
462
+
463
+ // ES5 15.2.3.2
464
+ if (!Object.getPrototypeOf) {
465
+ // https://github.com/kriskowal/es5-shim/issues#issue/2
466
+ // http://ejohn.org/blog/objectgetprototypeof/
467
+ // recommended by fschaefer on github
468
+ Object.getPrototypeOf = function getPrototypeOf(object) {
469
+ return object.__proto__ || (
470
+ object.constructor ?
471
+ object.constructor.prototype :
472
+ prototypeOfObject
473
+ );
474
+ };
475
+ }
476
+
477
+ // ES5 15.2.3.3
478
+ if (!Object.getOwnPropertyDescriptor) {
479
+ var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " +
480
+ "non-object: ";
481
+ Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
482
+ if ((typeof object != "object" && typeof object != "function") || object === null)
483
+ throw new TypeError(ERR_NON_OBJECT + object);
484
+ // If object does not owns property return undefined immediately.
485
+ if (!owns(object, property))
486
+ return;
487
+
488
+ var descriptor, getter, setter;
489
+
490
+ // If object has a property then it's for sure both `enumerable` and
491
+ // `configurable`.
492
+ descriptor = { enumerable: true, configurable: true };
493
+
494
+ // If JS engine supports accessor properties then property may be a
495
+ // getter or setter.
496
+ if (supportsAccessors) {
497
+ // Unfortunately `__lookupGetter__` will return a getter even
498
+ // if object has own non getter property along with a same named
499
+ // inherited getter. To avoid misbehavior we temporary remove
500
+ // `__proto__` so that `__lookupGetter__` will return getter only
501
+ // if it's owned by an object.
502
+ var prototype = object.__proto__;
503
+ object.__proto__ = prototypeOfObject;
504
+
505
+ var getter = lookupGetter(object, property);
506
+ var setter = lookupSetter(object, property);
507
+
508
+ // Once we have getter and setter we can put values back.
509
+ object.__proto__ = prototype;
510
+
511
+ if (getter || setter) {
512
+ if (getter) descriptor.get = getter;
513
+ if (setter) descriptor.set = setter;
514
+
515
+ // If it was accessor property we're done and return here
516
+ // in order to avoid adding `value` to the descriptor.
517
+ return descriptor;
518
+ }
519
+ }
520
+
521
+ // If we got this far we know that object has an own property that is
522
+ // not an accessor so we set it as a value and return descriptor.
523
+ descriptor.value = object[property];
524
+ return descriptor;
525
+ };
526
+ }
527
+
528
+ // ES5 15.2.3.4
529
+ if (!Object.getOwnPropertyNames) {
530
+ Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
531
+ return Object.keys(object);
532
+ };
533
+ }
534
+
535
+ // ES5 15.2.3.5
536
+ if (!Object.create) {
537
+ Object.create = function create(prototype, properties) {
538
+ var object;
539
+ if (prototype === null) {
540
+ object = { "__proto__": null };
541
+ } else {
542
+ if (typeof prototype != "object")
543
+ throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
544
+ var Type = function () {};
545
+ Type.prototype = prototype;
546
+ object = new Type();
547
+ // IE has no built-in implementation of `Object.getPrototypeOf`
548
+ // neither `__proto__`, but this manually setting `__proto__` will
549
+ // guarantee that `Object.getPrototypeOf` will work as expected with
550
+ // objects created using `Object.create`
551
+ object.__proto__ = prototype;
552
+ }
553
+ if (properties !== void 0)
554
+ Object.defineProperties(object, properties);
555
+ return object;
556
+ };
557
+ }
558
+
559
+ // ES5 15.2.3.6
560
+
561
+ // Patch for WebKit and IE8 standard mode
562
+ // Designed by hax <hax.github.com>
563
+ // related issue: https://github.com/kriskowal/es5-shim/issues#issue/5
564
+ // IE8 Reference:
565
+ // http://msdn.microsoft.com/en-us/library/dd282900.aspx
566
+ // http://msdn.microsoft.com/en-us/library/dd229916.aspx
567
+ // WebKit Bugs:
568
+ // https://bugs.webkit.org/show_bug.cgi?id=36423
569
+
570
+ function doesDefinePropertyWork(object) {
571
+ try {
572
+ Object.defineProperty(object, "sentinel", {});
573
+ return "sentinel" in object;
574
+ } catch (exception) {
575
+ // returns falsy
576
+ }
577
+ }
578
+
579
+ // check whether defineProperty works if it's given. Otherwise,
580
+ // shim partially.
581
+ if (Object.defineProperty) {
582
+ var definePropertyWorksOnObject = doesDefinePropertyWork({});
583
+ var definePropertyWorksOnDom = typeof document == "undefined" ||
584
+ doesDefinePropertyWork(document.createElement("div"));
585
+ if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
586
+ var definePropertyFallback = Object.defineProperty;
587
+ }
588
+ }
589
+
590
+ if (!Object.defineProperty || definePropertyFallback) {
591
+ var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
592
+ var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "
593
+ var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
594
+ "on this javascript engine";
595
+
596
+ Object.defineProperty = function defineProperty(object, property, descriptor) {
597
+ if ((typeof object != "object" && typeof object != "function") || object === null)
598
+ throw new TypeError(ERR_NON_OBJECT_TARGET + object);
599
+ if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null)
600
+ throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
601
+
602
+ // make a valiant attempt to use the real defineProperty
603
+ // for I8's DOM elements.
604
+ if (definePropertyFallback) {
605
+ try {
606
+ return definePropertyFallback.call(Object, object, property, descriptor);
607
+ } catch (exception) {
608
+ // try the shim if the real one doesn't work
609
+ }
610
+ }
611
+
612
+ // If it's a data property.
613
+ if (owns(descriptor, "value")) {
614
+ // fail silently if "writable", "enumerable", or "configurable"
615
+ // are requested but not supported
616
+ /*
617
+ // alternate approach:
618
+ if ( // can't implement these features; allow false but not true
619
+ !(owns(descriptor, "writable") ? descriptor.writable : true) ||
620
+ !(owns(descriptor, "enumerable") ? descriptor.enumerable : true) ||
621
+ !(owns(descriptor, "configurable") ? descriptor.configurable : true)
622
+ )
623
+ throw new RangeError(
624
+ "This implementation of Object.defineProperty does not " +
625
+ "support configurable, enumerable, or writable."
626
+ );
627
+ */
628
+
629
+ if (supportsAccessors && (lookupGetter(object, property) ||
630
+ lookupSetter(object, property)))
631
+ {
632
+ // As accessors are supported only on engines implementing
633
+ // `__proto__` we can safely override `__proto__` while defining
634
+ // a property to make sure that we don't hit an inherited
635
+ // accessor.
636
+ var prototype = object.__proto__;
637
+ object.__proto__ = prototypeOfObject;
638
+ // Deleting a property anyway since getter / setter may be
639
+ // defined on object itself.
640
+ delete object[property];
641
+ object[property] = descriptor.value;
642
+ // Setting original `__proto__` back now.
643
+ object.__proto__ = prototype;
644
+ } else {
645
+ object[property] = descriptor.value;
646
+ }
647
+ } else {
648
+ if (!supportsAccessors)
649
+ throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
650
+ // If we got that far then getters and setters can be defined !!
651
+ if (owns(descriptor, "get"))
652
+ defineGetter(object, property, descriptor.get);
653
+ if (owns(descriptor, "set"))
654
+ defineSetter(object, property, descriptor.set);
655
+ }
656
+
657
+ return object;
658
+ };
659
+ }
660
+
661
+ // ES5 15.2.3.7
662
+ if (!Object.defineProperties) {
663
+ Object.defineProperties = function defineProperties(object, properties) {
664
+ for (var property in properties) {
665
+ if (owns(properties, property))
666
+ Object.defineProperty(object, property, properties[property]);
667
+ }
668
+ return object;
669
+ };
670
+ }
671
+
672
+ // ES5 15.2.3.8
673
+ if (!Object.seal) {
674
+ Object.seal = function seal(object) {
675
+ // this is misleading and breaks feature-detection, but
676
+ // allows "securable" code to "gracefully" degrade to working
677
+ // but insecure code.
678
+ return object;
679
+ };
680
+ }
681
+
682
+ // ES5 15.2.3.9
683
+ if (!Object.freeze) {
684
+ Object.freeze = function freeze(object) {
685
+ // this is misleading and breaks feature-detection, but
686
+ // allows "securable" code to "gracefully" degrade to working
687
+ // but insecure code.
688
+ return object;
689
+ };
690
+ }
691
+
692
+ // detect a Rhino bug and patch it
693
+ try {
694
+ Object.freeze(function () {});
695
+ } catch (exception) {
696
+ Object.freeze = (function freeze(freezeObject) {
697
+ return function freeze(object) {
698
+ if (typeof object == "function") {
699
+ return object;
700
+ } else {
701
+ return freezeObject(object);
702
+ }
703
+ };
704
+ })(Object.freeze);
705
+ }
706
+
707
+ // ES5 15.2.3.10
708
+ if (!Object.preventExtensions) {
709
+ Object.preventExtensions = function preventExtensions(object) {
710
+ // this is misleading and breaks feature-detection, but
711
+ // allows "securable" code to "gracefully" degrade to working
712
+ // but insecure code.
713
+ return object;
714
+ };
715
+ }
716
+
717
+ // ES5 15.2.3.11
718
+ if (!Object.isSealed) {
719
+ Object.isSealed = function isSealed(object) {
720
+ return false;
721
+ };
722
+ }
723
+
724
+ // ES5 15.2.3.12
725
+ if (!Object.isFrozen) {
726
+ Object.isFrozen = function isFrozen(object) {
727
+ return false;
728
+ };
729
+ }
730
+
731
+ // ES5 15.2.3.13
732
+ if (!Object.isExtensible) {
733
+ Object.isExtensible = function isExtensible(object) {
734
+ // 1. If Type(O) is not Object throw a TypeError exception.
735
+ if (Object(object) === object) {
736
+ throw new TypeError(); // TODO message
737
+ }
738
+ // 2. Return the Boolean value of the [[Extensible]] internal property of O.
739
+ var name = '';
740
+ while (owns(object, name)) {
741
+ name += '?';
742
+ }
743
+ object[name] = true;
744
+ var returnValue = owns(object, name);
745
+ delete object[name];
746
+ return returnValue;
747
+ };
748
+ }
749
+
750
+ // ES5 15.2.3.14
751
+ // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
752
+ if (!Object.keys) {
753
+
754
+ var hasDontEnumBug = true,
755
+ dontEnums = [
756
+ "toString",
757
+ "toLocaleString",
758
+ "valueOf",
759
+ "hasOwnProperty",
760
+ "isPrototypeOf",
761
+ "propertyIsEnumerable",
762
+ "constructor"
763
+ ],
764
+ dontEnumsLength = dontEnums.length;
765
+
766
+ for (var key in {"toString": null})
767
+ hasDontEnumBug = false;
768
+
769
+ Object.keys = function keys(object) {
770
+
771
+ if ((typeof object != "object" && typeof object != "function") || object === null)
772
+ throw new TypeError("Object.keys called on a non-object");
773
+
774
+ var keys = [];
775
+ for (var name in object) {
776
+ if (owns(object, name)) {
777
+ keys.push(name);
778
+ }
779
+ }
780
+
781
+ if (hasDontEnumBug) {
782
+ for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
783
+ var dontEnum = dontEnums[i];
784
+ if (owns(object, dontEnum)) {
785
+ keys.push(dontEnum);
786
+ }
787
+ }
788
+ }
789
+
790
+ return keys;
791
+ };
792
+
793
+ }
794
+
795
+ //
796
+ // Date
797
+ // ====
798
+ //
799
+
800
+ // ES5 15.9.5.43
801
+ // Format a Date object as a string according to a simplified subset of the ISO 8601
802
+ // standard as defined in 15.9.1.15.
803
+ if (!Date.prototype.toISOString) {
804
+ Date.prototype.toISOString = function toISOString() {
805
+ var result, length, value;
806
+ if (!isFinite(this))
807
+ throw new RangeError;
808
+
809
+ // the date time string format is specified in 15.9.1.15.
810
+ result = [this.getUTCFullYear(), this.getUTCMonth() + 1, this.getUTCDate(),
811
+ this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
812
+
813
+ length = result.length;
814
+ while (length--) {
815
+ value = result[length];
816
+ // pad months, days, hours, minutes, and seconds to have two digits.
817
+ if (value < 10)
818
+ result[length] = "0" + value;
819
+ }
820
+ // pad milliseconds to have three digits.
821
+ return result.slice(0, 3).join("-") + "T" + result.slice(3).join(":") + "." +
822
+ ("000" + this.getUTCMilliseconds()).slice(-3) + "Z";
823
+ }
824
+ }
825
+
826
+ // ES5 15.9.4.4
827
+ if (!Date.now) {
828
+ Date.now = function now() {
829
+ return new Date().getTime();
830
+ };
831
+ }
832
+
833
+ // ES5 15.9.5.44
834
+ if (!Date.prototype.toJSON) {
835
+ Date.prototype.toJSON = function toJSON(key) {
836
+ // This function provides a String representation of a Date object for
837
+ // use by JSON.stringify (15.12.3). When the toJSON method is called
838
+ // with argument key, the following steps are taken:
839
+
840
+ // 1. Let O be the result of calling ToObject, giving it the this
841
+ // value as its argument.
842
+ // 2. Let tv be ToPrimitive(O, hint Number).
843
+ // 3. If tv is a Number and is not finite, return null.
844
+ // XXX
845
+ // 4. Let toISO be the result of calling the [[Get]] internal method of
846
+ // O with argument "toISOString".
847
+ // 5. If IsCallable(toISO) is false, throw a TypeError exception.
848
+ if (typeof this.toISOString != "function")
849
+ throw new TypeError(); // TODO message
850
+ // 6. Return the result of calling the [[Call]] internal method of
851
+ // toISO with O as the this value and an empty argument list.
852
+ return this.toISOString();
853
+
854
+ // NOTE 1 The argument is ignored.
855
+
856
+ // NOTE 2 The toJSON function is intentionally generic; it does not
857
+ // require that its this value be a Date object. Therefore, it can be
858
+ // transferred to other kinds of objects for use as a method. However,
859
+ // it does require that any such object have a toISOString method. An
860
+ // object is free to use the argument key to filter its
861
+ // stringification.
862
+ };
863
+ }
864
+
865
+ // 15.9.4.2 Date.parse (string)
866
+ // 15.9.1.15 Date Time String Format
867
+ // Date.parse
868
+ // based on work shared by Daniel Friesen (dantman)
869
+ // http://gist.github.com/303249
870
+ if (isNaN(Date.parse("2011-06-15T21:40:05+06:00"))) {
871
+ // XXX global assignment won't work in embeddings that use
872
+ // an alternate object for the context.
873
+ Date = (function(NativeDate) {
874
+
875
+ // Date.length === 7
876
+ var Date = function Date(Y, M, D, h, m, s, ms) {
877
+ var length = arguments.length;
878
+ if (this instanceof NativeDate) {
879
+ var date = length == 1 && String(Y) === Y ? // isString(Y)
880
+ // We explicitly pass it through parse:
881
+ new NativeDate(Date.parse(Y)) :
882
+ // We have to manually make calls depending on argument
883
+ // length here
884
+ length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
885
+ length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
886
+ length >= 5 ? new NativeDate(Y, M, D, h, m) :
887
+ length >= 4 ? new NativeDate(Y, M, D, h) :
888
+ length >= 3 ? new NativeDate(Y, M, D) :
889
+ length >= 2 ? new NativeDate(Y, M) :
890
+ length >= 1 ? new NativeDate(Y) :
891
+ new NativeDate();
892
+ // Prevent mixups with unfixed Date object
893
+ date.constructor = Date;
894
+ return date;
895
+ }
896
+ return NativeDate.apply(this, arguments);
897
+ };
898
+
899
+ // 15.9.1.15 Date Time String Format. This pattern does not implement
900
+ // extended years (15.9.1.15.1), as `Date.UTC` cannot parse them.
901
+ var isoDateExpression = new RegExp("^" +
902
+ "(\\d{4})" + // four-digit year capture
903
+ "(?:-(\\d{2})" + // optional month capture
904
+ "(?:-(\\d{2})" + // optional day capture
905
+ "(?:" + // capture hours:minutes:seconds.milliseconds
906
+ "T(\\d{2})" + // hours capture
907
+ ":(\\d{2})" + // minutes capture
908
+ "(?:" + // optional :seconds.milliseconds
909
+ ":(\\d{2})" + // seconds capture
910
+ "(?:\\.(\\d{3}))?" + // milliseconds capture
911
+ ")?" +
912
+ "(?:" + // capture UTC offset component
913
+ "Z|" + // UTC capture
914
+ "(?:" + // offset specifier +/-hours:minutes
915
+ "([-+])" + // sign capture
916
+ "(\\d{2})" + // hours offset capture
917
+ ":(\\d{2})" + // minutes offset capture
918
+ ")" +
919
+ ")?)?)?)?" +
920
+ "$");
921
+
922
+ // Copy any custom methods a 3rd party library may have added
923
+ for (var key in NativeDate)
924
+ Date[key] = NativeDate[key];
925
+
926
+ // Copy "native" methods explicitly; they may be non-enumerable
927
+ Date.now = NativeDate.now;
928
+ Date.UTC = NativeDate.UTC;
929
+ Date.prototype = NativeDate.prototype;
930
+ Date.prototype.constructor = Date;
931
+
932
+ // Upgrade Date.parse to handle simplified ISO 8601 strings
933
+ Date.parse = function parse(string) {
934
+ var match = isoDateExpression.exec(string);
935
+ if (match) {
936
+ match.shift(); // kill match[0], the full match
937
+ // parse months, days, hours, minutes, seconds, and milliseconds
938
+ for (var i = 1; i < 7; i++) {
939
+ // provide default values if necessary
940
+ match[i] = +(match[i] || (i < 3 ? 1 : 0));
941
+ // match[1] is the month. Months are 0-11 in JavaScript
942
+ // `Date` objects, but 1-12 in ISO notation, so we
943
+ // decrement.
944
+ if (i == 1)
945
+ match[i]--;
946
+ }
947
+
948
+ // parse the UTC offset component
949
+ var minuteOffset = +match.pop(), hourOffset = +match.pop(), sign = match.pop();
950
+
951
+ // compute the explicit time zone offset if specified
952
+ var offset = 0;
953
+ if (sign) {
954
+ // detect invalid offsets and return early
955
+ if (hourOffset > 23 || minuteOffset > 59)
956
+ return NaN;
957
+
958
+ // express the provided time zone offset in minutes. The offset is
959
+ // negative for time zones west of UTC; positive otherwise.
960
+ offset = (hourOffset * 60 + minuteOffset) * 6e4 * (sign == "+" ? -1 : 1);
961
+ }
962
+
963
+ // compute a new UTC date value, accounting for the optional offset
964
+ return NativeDate.UTC.apply(this, match) + offset;
965
+ }
966
+ return NativeDate.parse.apply(this, arguments);
967
+ };
968
+
969
+ return Date;
970
+ })(Date);
971
+ }
972
+
973
+ //
974
+ // String
975
+ // ======
976
+ //
977
+
978
+ // ES5 15.5.4.20
979
+ var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
980
+ "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
981
+ "\u2029\uFEFF";
982
+ if (!String.prototype.trim || ws.trim()) {
983
+ // http://blog.stevenlevithan.com/archives/faster-trim-javascript
984
+ // http://perfectionkills.com/whitespace-deviations/
985
+ ws = "[" + ws + "]";
986
+ var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
987
+ trimEndRegexp = new RegExp(ws + ws + "*$");
988
+ String.prototype.trim = function trim() {
989
+ return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
990
+ };
991
+ }
992
+
993
+ //
994
+ // Util
995
+ // ======
996
+ //
997
+
998
+ // http://jsperf.com/to-integer
999
+ var toInteger = function (n) {
1000
+ n = +n;
1001
+ if (n !== n) // isNaN
1002
+ n = -1;
1003
+ else if (n !== 0 && n !== (1/0) && n !== -(1/0))
1004
+ n = (n > 0 || -1) * Math.floor(Math.abs(n));
1005
+ return n;
1006
+ };
1007
+
1008
+ var prepareString = "a"[0] != "a",
1009
+ // ES5 9.9
1010
+ toObject = function (o) {
1011
+ if (o == null) { // this matches both null and undefined
1012
+ throw new TypeError(); // TODO message
1013
+ }
1014
+ // If the implementation doesn't support by-index access of
1015
+ // string characters (ex. IE < 7), split the string
1016
+ if (prepareString && typeof o == "string" && o) {
1017
+ return o.split("");
1018
+ }
1019
+ return Object(o);
1020
+ };
1021
+ });