acts_as_dashboard 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +54 -0
  5. data/Rakefile +23 -0
  6. data/VERSION +1 -0
  7. data/acts_as_dashboard.gemspec +166 -0
  8. data/generators/dashboard/USAGE +23 -0
  9. data/generators/dashboard/dashboard_generator.rb +105 -0
  10. data/generators/dashboard/templates/controller.erb +39 -0
  11. data/generators/dashboard/templates/dashboard.css +66 -0
  12. data/generators/dashboard/templates/dashboard.js +305 -0
  13. data/generators/dashboard/templates/jqplot-0.9.7/jquery.jqplot.min.js +14 -0
  14. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.barRenderer.js +404 -0
  15. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.barRenderer.min.js +14 -0
  16. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasAxisLabelRenderer.js +200 -0
  17. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasAxisLabelRenderer.min.js +14 -0
  18. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasAxisTickRenderer.js +232 -0
  19. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasAxisTickRenderer.min.js +14 -0
  20. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasTextRenderer.js +408 -0
  21. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasTextRenderer.min.js +14 -0
  22. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.categoryAxisRenderer.js +238 -0
  23. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.categoryAxisRenderer.min.js +14 -0
  24. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.cursor.js +812 -0
  25. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.cursor.min.js +14 -0
  26. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.dateAxisRenderer.js +313 -0
  27. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.dateAxisRenderer.min.js +14 -0
  28. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.dragable.js +203 -0
  29. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.dragable.min.js +14 -0
  30. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.highlighter.js +359 -0
  31. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.highlighter.min.js +14 -0
  32. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.logAxisRenderer.js +434 -0
  33. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.logAxisRenderer.min.js +14 -0
  34. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.mekkoAxisRenderer.js +595 -0
  35. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.mekkoAxisRenderer.min.js +14 -0
  36. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.mekkoRenderer.js +308 -0
  37. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.mekkoRenderer.min.js +14 -0
  38. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.ohlcRenderer.js +343 -0
  39. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.ohlcRenderer.min.js +14 -0
  40. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.pieRenderer.js +333 -0
  41. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.pieRenderer.min.js +14 -0
  42. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.pointLabels.js +307 -0
  43. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.pointLabels.js.orig +273 -0
  44. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.pointLabels.min.js +14 -0
  45. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.trendline.js +208 -0
  46. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.trendline.min.js +14 -0
  47. data/generators/dashboard/templates/jquery.jqplot.min.css +1 -0
  48. data/generators/dashboard/templates/js.class-2.1.4/CHANGELOG +269 -0
  49. data/generators/dashboard/templates/js.class-2.1.4/MIT-LICENSE +30 -0
  50. data/generators/dashboard/templates/js.class-2.1.4/README +30 -0
  51. data/generators/dashboard/templates/js.class-2.1.4/min/command.js +1 -0
  52. data/generators/dashboard/templates/js.class-2.1.4/min/comparable.js +1 -0
  53. data/generators/dashboard/templates/js.class-2.1.4/min/constant_scope.js +1 -0
  54. data/generators/dashboard/templates/js.class-2.1.4/min/core.js +1 -0
  55. data/generators/dashboard/templates/js.class-2.1.4/min/decorator.js +1 -0
  56. data/generators/dashboard/templates/js.class-2.1.4/min/enumerable.js +1 -0
  57. data/generators/dashboard/templates/js.class-2.1.4/min/forwardable.js +1 -0
  58. data/generators/dashboard/templates/js.class-2.1.4/min/hash.js +1 -0
  59. data/generators/dashboard/templates/js.class-2.1.4/min/linked_list.js +1 -0
  60. data/generators/dashboard/templates/js.class-2.1.4/min/loader.js +1 -0
  61. data/generators/dashboard/templates/js.class-2.1.4/min/method_chain.js +1 -0
  62. data/generators/dashboard/templates/js.class-2.1.4/min/observable.js +1 -0
  63. data/generators/dashboard/templates/js.class-2.1.4/min/package.js +1 -0
  64. data/generators/dashboard/templates/js.class-2.1.4/min/proxy.js +1 -0
  65. data/generators/dashboard/templates/js.class-2.1.4/min/ruby.js +1 -0
  66. data/generators/dashboard/templates/js.class-2.1.4/min/set.js +1 -0
  67. data/generators/dashboard/templates/js.class-2.1.4/min/stack_trace.js +1 -0
  68. data/generators/dashboard/templates/js.class-2.1.4/min/state.js +1 -0
  69. data/generators/dashboard/templates/js.class-2.1.4/min/stdlib.js +16 -0
  70. data/generators/dashboard/templates/js.class-2.1.4/src/command.js +93 -0
  71. data/generators/dashboard/templates/js.class-2.1.4/src/comparable.js +37 -0
  72. data/generators/dashboard/templates/js.class-2.1.4/src/constant_scope.js +48 -0
  73. data/generators/dashboard/templates/js.class-2.1.4/src/core.js +1060 -0
  74. data/generators/dashboard/templates/js.class-2.1.4/src/decorator.js +50 -0
  75. data/generators/dashboard/templates/js.class-2.1.4/src/enumerable.js +505 -0
  76. data/generators/dashboard/templates/js.class-2.1.4/src/forwardable.js +22 -0
  77. data/generators/dashboard/templates/js.class-2.1.4/src/hash.js +334 -0
  78. data/generators/dashboard/templates/js.class-2.1.4/src/linked_list.js +114 -0
  79. data/generators/dashboard/templates/js.class-2.1.4/src/loader.js +458 -0
  80. data/generators/dashboard/templates/js.class-2.1.4/src/method_chain.js +172 -0
  81. data/generators/dashboard/templates/js.class-2.1.4/src/observable.js +55 -0
  82. data/generators/dashboard/templates/js.class-2.1.4/src/package.js +377 -0
  83. data/generators/dashboard/templates/js.class-2.1.4/src/proxy.js +58 -0
  84. data/generators/dashboard/templates/js.class-2.1.4/src/ruby.js +44 -0
  85. data/generators/dashboard/templates/js.class-2.1.4/src/set.js +332 -0
  86. data/generators/dashboard/templates/js.class-2.1.4/src/stack_trace.js +151 -0
  87. data/generators/dashboard/templates/js.class-2.1.4/src/state.js +95 -0
  88. data/generators/dashboard/templates/js.class-2.1.4/src/stdlib.js +2517 -0
  89. data/generators/dashboard/templates/show.html.erb +67 -0
  90. data/lib/acts_as_dashboard/app/views/dashboards/show.html.erb +67 -0
  91. data/lib/acts_as_dashboard/class_methods.rb +58 -0
  92. data/lib/acts_as_dashboard/config.rb +25 -0
  93. data/lib/acts_as_dashboard/instance_methods.rb +32 -0
  94. data/lib/acts_as_dashboard/line_graph_widget.rb +68 -0
  95. data/lib/acts_as_dashboard/public/javascripts/dashboard.js +305 -0
  96. data/lib/acts_as_dashboard/public/stylesheets/dashboard.css +66 -0
  97. data/lib/acts_as_dashboard/short_messages_widget.rb +25 -0
  98. data/lib/acts_as_dashboard/widget.rb +55 -0
  99. data/lib/acts_as_dashboard.rb +17 -0
  100. data/spec/acts_as_dashboard/class_method_specs.rb +188 -0
  101. data/spec/acts_as_dashboard/config_spec.rb +57 -0
  102. data/spec/acts_as_dashboard/instance_methods_spec.rb +134 -0
  103. data/spec/acts_as_dashboard/line_graph_widget_spec.rb +165 -0
  104. data/spec/acts_as_dashboard/short_messages_widget_spec.rb +69 -0
  105. data/spec/acts_as_dashboard/widget_spec.rb +6 -0
  106. data/spec/acts_as_dashboard_spec.rb +15 -0
  107. data/spec/shared/widget_behaviours.rb +171 -0
  108. data/spec/spec.opts +1 -0
  109. data/spec/spec_helper.rb +10 -0
  110. data/tasks/install.rake +8 -0
  111. data/tasks/install_javascript.rake +7 -0
  112. data/tasks/install_stylesheets.rake +7 -0
  113. metadata +209 -0
@@ -0,0 +1,2517 @@
1
+ JS.MethodChain = function(base) {
2
+ var queue = [],
3
+ baseObject = base || {};
4
+
5
+ this.____ = function(method, args) {
6
+ queue.push({func: method, args: args});
7
+ };
8
+
9
+ this.fire = function(base) {
10
+ return JS.MethodChain.fire(queue, base || baseObject);
11
+ };
12
+ };
13
+
14
+ JS.MethodChain.fire = function(queue, object) {
15
+ var method, property, i, n;
16
+ loop: for (i = 0, n = queue.length; i < n; i++) {
17
+ method = queue[i];
18
+ if (object instanceof JS.MethodChain) {
19
+ object.____(method.func, method.args);
20
+ continue;
21
+ }
22
+ switch (typeof method.func) {
23
+ case 'string': property = object[method.func]; break;
24
+ case 'function': property = method.func; break;
25
+ case 'object': object = method.func; continue loop; break;
26
+ }
27
+ object = (typeof property === 'function')
28
+ ? property.apply(object, method.args)
29
+ : property;
30
+ }
31
+ return object;
32
+ };
33
+
34
+ JS.MethodChain.prototype = {
35
+ _: function() {
36
+ var base = arguments[0],
37
+ args, i, n;
38
+
39
+ switch (typeof base) {
40
+ case 'object': case 'function':
41
+ args = [];
42
+ for (i = 1, n = arguments.length; i < n; i++) args.push(arguments[i]);
43
+ this.____(base, args);
44
+ }
45
+ return this;
46
+ },
47
+
48
+ toFunction: function() {
49
+ var chain = this;
50
+ return function(object) { return chain.fire(object); };
51
+ }
52
+ };
53
+
54
+ JS.MethodChain.reserved = (function() {
55
+ var names = [], key;
56
+ for (key in new JS.MethodChain) names.push(key);
57
+ return new RegExp('^(?:' + names.join('|') + ')$');
58
+ })();
59
+
60
+ JS.MethodChain.addMethod = function(name) {
61
+ if (this.reserved.test(name)) return;
62
+ var func = this.prototype[name] = function() {
63
+ this.____(name, arguments);
64
+ return this;
65
+ };
66
+ func.displayName = 'MethodChain#' + name;
67
+ };
68
+
69
+ JS.MethodChain.displayName = 'MethodChain';
70
+
71
+ JS.MethodChain.addMethods = function(object) {
72
+ var methods = [], property, i;
73
+
74
+ for (property in object)
75
+ Number(property) !== property && methods.push(property);
76
+
77
+ if (object instanceof Array) {
78
+ i = object.length;
79
+ while (i--)
80
+ typeof object[i] === 'string' && methods.push(object[i]);
81
+ }
82
+ i = methods.length;
83
+ while (i--) this.addMethod(methods[i]);
84
+
85
+ object.__fns__ && this.addMethods(object.__fns__);
86
+ object.prototype && this.addMethods(object.prototype);
87
+ };
88
+
89
+ it = its = function() { return new JS.MethodChain; };
90
+
91
+ JS.Module.methodAdded(function(name) {
92
+ JS.MethodChain.addMethod(name);
93
+ });
94
+
95
+ JS.Kernel.include({
96
+ wait: function(time) {
97
+ var chain = new JS.MethodChain;
98
+
99
+ typeof time === 'number' &&
100
+ setTimeout(chain.fire.bind(chain, this), time * 1000);
101
+
102
+ this.forEach && typeof time === 'function' &&
103
+ this.forEach(function() {
104
+ setTimeout(chain.fire.bind(chain, arguments[0]), time.apply(this, arguments) * 1000);
105
+ });
106
+
107
+ return chain;
108
+ },
109
+
110
+ _: function() {
111
+ var base = arguments[0],
112
+ args = [],
113
+ i, n;
114
+
115
+ for (i = 1, n = arguments.length; i < n; i++) args.push(arguments[i]);
116
+ return (typeof base === 'object' && base) ||
117
+ (typeof base === 'function' && base.apply(this, args)) ||
118
+ this;
119
+ }
120
+ }, true);
121
+
122
+ (function() {
123
+ var queue = JS.Module.__chainq__,
124
+ n = queue.length;
125
+
126
+ while (n--) JS.MethodChain.addMethods(queue[n]);
127
+ JS.Module.__chainq__ = null;
128
+ })();
129
+
130
+ JS.MethodChain.addMethods([
131
+ "abbr", "abs", "accept", "acceptCharset", "accesskey", "acos", "action", "addEventListener",
132
+ "adjacentNode", "align", "alignWithTop", "alink", "alt", "anchor", "appendChild", "appendedNode",
133
+ "apply", "archive", "arguments", "arity", "asin", "atan", "atan2", "attrNode", "attributes",
134
+ "axis", "background", "bgcolor", "big", "blink", "blur", "bold", "border", "call", "caller",
135
+ "ceil", "cellpadding", "cellspacing", "char", "charAt", "charCodeAt", "charoff", "charset",
136
+ "checked", "childNodes", "cite", "className", "classid", "clear", "click", "clientHeight",
137
+ "clientLeft", "clientTop", "clientWidth", "cloneNode", "code", "codebase", "codetype", "color",
138
+ "cols", "colspan", "compact", "concat", "content", "coords", "cos", "data", "datetime", "declare",
139
+ "deep", "defer", "dir", "disabled", "dispatchEvent", "enctype", "event", "every", "exec", "exp",
140
+ "face", "filter", "firstChild", "fixed", "floor", "focus", "fontcolor", "fontsize", "forEach",
141
+ "frame", "frameborder", "fromCharCode", "getAttribute", "getAttributeNS", "getAttributeNode",
142
+ "getAttributeNodeNS", "getDate", "getDay", "getElementsByTagName", "getElementsByTagNameNS",
143
+ "getFullYear", "getHours", "getMilliseconds", "getMinutes", "getMonth", "getSeconds", "getTime",
144
+ "getTimezoneOffset", "getUTCDate", "getUTCDay", "getUTCFullYear", "getUTCHours",
145
+ "getUTCMilliseconds", "getUTCMinutes", "getUTCMonth", "getUTCSeconds", "getYear", "global",
146
+ "handler", "hasAttribute", "hasAttributeNS", "hasAttributes", "hasChildNodes", "hasOwnProperty",
147
+ "headers", "height", "href", "hreflang", "hspace", "htmlFor", "httpEquiv", "id", "ignoreCase",
148
+ "index", "indexOf", "innerHTML", "input", "insertBefore", "insertedNode", "isPrototypeOf", "ismap",
149
+ "italics", "join", "label", "lang", "language", "lastChild", "lastIndex", "lastIndexOf", "length",
150
+ "link", "listener", "localName", "log", "longdesc", "map", "marginheight", "marginwidth", "match",
151
+ "max", "maxlength", "media", "method", "min", "multiline", "multiple", "name", "namespace",
152
+ "namespaceURI", "nextSibling", "node", "nodeName", "nodeType", "nodeValue", "nohref", "noresize",
153
+ "normalize", "noshade", "now", "nowrap", "object", "offsetHeight", "offsetLeft", "offsetParent",
154
+ "offsetTop", "offsetWidth", "onblur", "onchange", "onclick", "ondblclick", "onfocus", "onkeydown",
155
+ "onkeypress", "onkeyup", "onload", "onmousedown", "onmousemove", "onmouseout", "onmouseover",
156
+ "onmouseup", "onreset", "onselect", "onsubmit", "onunload", "ownerDocument", "parentNode", "parse",
157
+ "pop", "pow", "prefix", "previousSibling", "profile", "prompt", "propertyIsEnumerable", "push",
158
+ "random", "readonly", "reduce", "reduceRight", "rel", "removeAttribute", "removeAttributeNS",
159
+ "removeAttributeNode", "removeChild", "removeEventListener", "removedNode", "replace",
160
+ "replaceChild", "replacedNode", "rev", "reverse", "round", "rows", "rowspan", "rules", "scheme",
161
+ "scope", "scrollHeight", "scrollIntoView", "scrollLeft", "scrollTop", "scrollWidth", "scrolling",
162
+ "search", "selected", "setAttribute", "setAttributeNS", "setAttributeNode", "setAttributeNodeNS",
163
+ "setDate", "setFullYear", "setHours", "setMilliseconds", "setMinutes", "setMonth", "setSeconds",
164
+ "setTime", "setUTCDate", "setUTCFullYear", "setUTCHours", "setUTCMilliseconds", "setUTCMinutes",
165
+ "setUTCMonth", "setUTCSeconds", "setYear", "shape", "shift", "sin", "size", "slice", "small",
166
+ "some", "sort", "source", "span", "splice", "split", "sqrt", "src", "standby", "start", "strike",
167
+ "style", "sub", "substr", "substring", "summary", "sup", "tabIndex", "tabindex", "tagName", "tan",
168
+ "target", "test", "text", "textContent", "title", "toArray", "toFunction", "toGMTString",
169
+ "toLocaleDateString", "toLocaleFormat", "toLocaleString", "toLocaleTimeString", "toLowerCase",
170
+ "toSource", "toString", "toUTCString", "toUpperCase", "type", "unshift", "unwatch", "useCapture",
171
+ "usemap", "valign", "value", "valueOf", "valuetype", "version", "vlink", "vspace", "watch", "width"
172
+ ]);
173
+
174
+
175
+ this.JS = this.JS || {};
176
+
177
+ JS.Package = function(loader) {
178
+ var Set = JS.Package.OrderedSet;
179
+ JS.Package._index(this);
180
+
181
+ this._loader = loader;
182
+ this._names = new Set();
183
+ this._deps = new Set();
184
+ this._uses = new Set();
185
+ this._observers = {};
186
+ this._events = {};
187
+ };
188
+
189
+ (function(klass) {
190
+ //================================================================
191
+ // Ordered list of unique elements, for storing dependencies
192
+
193
+ var Set = klass.OrderedSet = function(list, transform) {
194
+ this._members = this.list = [];
195
+ this._index = {};
196
+ if (!list) return;
197
+
198
+ for (var i = 0, n = list.length; i < n; i++)
199
+ this.push(transform ? transform(list[i]) : list[i]);
200
+ };
201
+
202
+ Set.prototype.push = function(item) {
203
+ var key = (item.id !== undefined) ? item.id : item,
204
+ index = this._index;
205
+
206
+ if (index.hasOwnProperty(key)) return;
207
+ index[key] = this._members.length;
208
+ this._members.push(item);
209
+ };
210
+
211
+ //================================================================
212
+ // Environment settings
213
+
214
+ klass._env = this;
215
+
216
+ if ((this.document || {}).getElementsByTagName) {
217
+ var script = document.getElementsByTagName('script')[0];
218
+ klass._isIE = (script.readyState !== undefined);
219
+ }
220
+
221
+
222
+ //================================================================
223
+ // Configuration methods, called by the DSL
224
+
225
+ var instance = klass.prototype;
226
+
227
+ instance.addDependency = function(pkg) {
228
+ this._deps.push(pkg);
229
+ };
230
+
231
+ instance.addSoftDependency = function(pkg) {
232
+ this._uses.push(pkg);
233
+ };
234
+
235
+ instance.addName = function(name) {
236
+ this._names.push(name);
237
+ klass.getFromCache(name).pkg = this;
238
+ };
239
+
240
+ instance.onload = function(block) {
241
+ this._onload = block;
242
+ };
243
+
244
+ //================================================================
245
+ // Event dispatchers, for communication between packages
246
+
247
+ instance.on = function(eventType, block, scope) {
248
+ if (this._events[eventType]) return block.call(scope);
249
+ var list = this._observers[eventType] = this._observers[eventType] || [];
250
+ list.push([block, scope]);
251
+ };
252
+
253
+ instance.fire = function(eventType) {
254
+ if (this._events[eventType]) return false;
255
+ this._events[eventType] = true;
256
+
257
+ var list = this._observers[eventType];
258
+ if (!list) return true;
259
+ delete this._observers[eventType];
260
+
261
+ for (var i = 0, n = list.length; i < n; i++)
262
+ list[i][0].call(list[i][1]);
263
+
264
+ return true;
265
+ };
266
+
267
+ //================================================================
268
+ // Loading frontend and other miscellany
269
+
270
+ instance.isLoaded = function(withExceptions) {
271
+ if (!withExceptions && this._isLoaded !== undefined) return this._isLoaded;
272
+
273
+ var names = this._names.list,
274
+ i = names.length,
275
+ name, object;
276
+
277
+ while (i--) { name = names[i];
278
+ object = klass.getObject(name);
279
+ if (object !== undefined) continue;
280
+ if (withExceptions)
281
+ throw new Error('Expected package at ' + this._loader + ' to define ' + name);
282
+ else
283
+ return this._isLoaded = false;
284
+ }
285
+ return this._isLoaded = true;
286
+ };
287
+
288
+ instance.load = function() {
289
+ if (!this.fire('request')) return;
290
+
291
+ var allDeps = this._deps.list.concat(this._uses.list),
292
+ startEvent = 'load', // could potentially use 'download' event in
293
+ listener = {}; // browsers that guarantee execution order
294
+
295
+ listener[startEvent] = this._deps.list;
296
+
297
+ klass.when(listener, function() {
298
+ klass.when({complete: allDeps, load: [this]}, function() {
299
+ this.fire('complete');
300
+ }, this);
301
+
302
+ var self = this, fireOnLoad = function() {
303
+ if (self._onload) self._onload();
304
+ self.isLoaded(true);
305
+ self.fire('load');
306
+ };
307
+
308
+ if (this.isLoaded()) {
309
+ this.fire('download');
310
+ return this.fire('load');
311
+ }
312
+
313
+ if (this._loader === undefined)
314
+ throw new Error('No load path found for ' + this._names.list[0]);
315
+
316
+ typeof this._loader === 'function'
317
+ ? this._loader(fireOnLoad)
318
+ : klass.Loader.loadFile(this._loader, fireOnLoad);
319
+
320
+ this.fire('download');
321
+ }, this);
322
+ };
323
+
324
+ instance.toString = function() {
325
+ return 'Package:' + this._names.list.join(',');
326
+ };
327
+
328
+ //================================================================
329
+ // Class-level event API, handles group listeners
330
+
331
+ klass.when = function(eventTable, block, scope) {
332
+ var eventList = [], event, packages, i;
333
+ for (event in eventTable) {
334
+ if (!eventTable.hasOwnProperty(event)) continue;
335
+ packages = new klass.OrderedSet(eventTable[event], function(name) { return klass.getByName(name) });
336
+ i = packages.list.length;
337
+ while (i--) eventList.push([event, packages.list[i]]);
338
+ }
339
+
340
+ var waiting = i = eventList.length;
341
+ if (waiting === 0) return block && block.call(scope);
342
+
343
+ while (i--) {
344
+ eventList[i][1].on(eventList[i][0], function() {
345
+ waiting -= 1;
346
+ if (waiting === 0 && block) block.call(scope);
347
+ });
348
+ eventList[i][1].load();
349
+ }
350
+ };
351
+
352
+ //================================================================
353
+ // Indexes for fast lookup by path and name, and assigning IDs
354
+
355
+ klass._autoIncrement = 1;
356
+ klass._indexByPath = {};
357
+ klass._indexByName = {};
358
+
359
+ klass._index = function(pkg) {
360
+ pkg.id = this._autoIncrement;
361
+ this._autoIncrement += 1;
362
+ };
363
+
364
+ klass.getByPath = function(loader) {
365
+ var path = loader.toString();
366
+ return this._indexByPath[path] = this._indexByPath[path] || new this(loader);
367
+ };
368
+
369
+ klass.getByName = function(name) {
370
+ if (typeof name !== 'string') return name;
371
+ var cached = this.getFromCache(name);
372
+ if (cached.pkg) return cached.pkg;
373
+
374
+ var placeholder = new this();
375
+ placeholder.addName(name);
376
+ return placeholder;
377
+ };
378
+
379
+ //================================================================
380
+ // Cache for named packages and runtime objects
381
+
382
+ klass.getFromCache = function(name) {
383
+ return this._indexByName[name] = this._indexByName[name] || {};
384
+ };
385
+
386
+ klass.getObject = function(name) {
387
+ var cached = this.getFromCache(name);
388
+ if (cached.obj !== undefined) return cached.obj;
389
+
390
+ var object = this._env,
391
+ parts = name.split('.'), part;
392
+
393
+ while (part = parts.shift()) object = object && object[part];
394
+
395
+ return this.getFromCache(name).obj = object;
396
+ };
397
+
398
+ })(JS.Package);
399
+
400
+
401
+ JS.Package.DomLoader = {
402
+ usable: function() {
403
+ return !!JS.Package.getObject('window.document.getElementsByTagName');
404
+ },
405
+
406
+ __FILE__: function() {
407
+ var scripts = document.getElementsByTagName('script');
408
+ return scripts[scripts.length - 1].src;
409
+ },
410
+
411
+ loadFile: function(path, fireCallbacks) {
412
+ var self = this,
413
+ tag = document.createElement('script');
414
+
415
+ tag.type = 'text/javascript';
416
+ tag.src = path;
417
+
418
+ tag.onload = tag.onreadystatechange = function() {
419
+ var state = tag.readyState, status = tag.status;
420
+ if ( !state || state === 'loaded' || state === 'complete' || (state === 4 && status === 200) ) {
421
+ fireCallbacks();
422
+ tag.onload = tag.onreadystatechange = self._K;
423
+ tag = null;
424
+ }
425
+ };
426
+
427
+ if (window.console && console.info)
428
+ console.info('Loading ' + path);
429
+
430
+ document.getElementsByTagName('head')[0].appendChild(tag);
431
+ },
432
+
433
+ _K: function() {}
434
+ };
435
+
436
+ JS.Package.ServerLoader = {
437
+ usable: function() {
438
+ return typeof JS.Package.getObject('load') === 'function' &&
439
+ typeof JS.Package.getObject('version') === 'function';
440
+ },
441
+
442
+ setup: function() {
443
+ var self = this;
444
+ load = (function(origLoad) {
445
+ return function() {
446
+ self._currentPath = arguments[0];
447
+ return origLoad.apply(JS.Package._env, arguments);
448
+ };
449
+ })(load);
450
+ },
451
+
452
+ __FILE__: function() {
453
+ return this._currentPath;
454
+ },
455
+
456
+ loadFile: function(path, fireCallbacks) {
457
+ load(path);
458
+ fireCallbacks();
459
+ }
460
+ };
461
+
462
+ (function() {
463
+ var candidates = [ JS.Package.DomLoader,
464
+ JS.Package.ServerLoader ],
465
+
466
+ n = candidates.length,
467
+ i, candidate;
468
+
469
+ for (i = 0; i < n; i++) {
470
+ candidate = candidates[i];
471
+ if (candidate.usable()) {
472
+ JS.Package.Loader = candidate;
473
+ if (candidate.setup) candidate.setup();
474
+ break;
475
+ }
476
+ }
477
+ })();
478
+
479
+
480
+ JS.Package.DSL = {
481
+ __FILE__: function() {
482
+ return JS.Package.Loader.__FILE__();
483
+ },
484
+
485
+ pkg: function(name, path) {
486
+ var pkg = path
487
+ ? JS.Package.getByPath(path)
488
+ : JS.Package.getByName(name);
489
+ pkg.addName(name);
490
+ return new JS.Package.Description(pkg);
491
+ },
492
+
493
+ file: function(path) {
494
+ var pkg = JS.Package.getByPath(path);
495
+ return new JS.Package.Description(pkg);
496
+ },
497
+
498
+ load: function(path, fireCallbacks) {
499
+ JS.Package.Loader.loadFile(path, fireCallbacks);
500
+ }
501
+ };
502
+
503
+ JS.Package.Description = function(pkg) {
504
+ this._pkg = pkg;
505
+ };
506
+
507
+ (function(klass) {
508
+
509
+ klass._batch = function(method, args) {
510
+ var n = args.length, method = this._pkg[method], i;
511
+ for (i = 0; i < n; i++) method.call(this._pkg, args[i]);
512
+ return this;
513
+ };
514
+
515
+ klass.provides = function() {
516
+ return this._batch('addName', arguments);
517
+ };
518
+
519
+ klass.requires = function() {
520
+ return this._batch('addDependency', arguments);
521
+ };
522
+
523
+ klass.uses = function() {
524
+ return this._batch('addSoftDependency', arguments);
525
+ };
526
+
527
+ klass.setup = function(block) {
528
+ this._pkg.onload(block);
529
+ return this;
530
+ };
531
+
532
+ })(JS.Package.Description.prototype);
533
+
534
+ JS.Package.DSL.loader = JS.Package.DSL.file;
535
+
536
+ JS.Packages = function(declaration) {
537
+ declaration.call(JS.Package.DSL);
538
+ };
539
+
540
+ JS.require = function() {
541
+ var requirements = [], i = 0;
542
+
543
+ while (typeof arguments[i] === 'string'){
544
+ requirements.push(arguments[i]);
545
+ i += 1;
546
+ }
547
+
548
+ JS.Package.when({complete: requirements}, arguments[i], arguments[i+1]);
549
+ };
550
+
551
+ require = JS.require;
552
+
553
+
554
+ JS.Comparable = new JS.Module('Comparable', {
555
+ extend: {
556
+ ClassMethods: new JS.Module({
557
+ compare: function(one, another) {
558
+ return one.compareTo(another);
559
+ }
560
+ }),
561
+
562
+ included: function(base) {
563
+ base.extend(this.ClassMethods);
564
+ }
565
+ },
566
+
567
+ lt: function(other) {
568
+ return this.compareTo(other) < 0;
569
+ },
570
+
571
+ lte: function(other) {
572
+ return this.compareTo(other) < 1;
573
+ },
574
+
575
+ gt: function(other) {
576
+ return this.compareTo(other) > 0;
577
+ },
578
+
579
+ gte: function(other) {
580
+ return this.compareTo(other) > -1;
581
+ },
582
+
583
+ eq: function(other) {
584
+ return this.compareTo(other) === 0;
585
+ },
586
+
587
+ between: function(a, b) {
588
+ return this.gte(a) && this.lte(b);
589
+ }
590
+ });
591
+
592
+
593
+ JS.Enumerable = new JS.Module('Enumerable', {
594
+ extend: {
595
+ forEach: function(block, context) {
596
+ if (!block) return new JS.Enumerator(this, 'forEach');
597
+ for (var i = 0, n = this.length; i < n; i++) {
598
+ if (this[i] !== undefined)
599
+ block.call(context || null, this[i]);
600
+ }
601
+ return this;
602
+ },
603
+
604
+ isComparable: function(list) {
605
+ return list.all(function(item) { return JS.isFn(item.compareTo) });
606
+ },
607
+
608
+ areEqual: function(one, another) {
609
+ return one.equals
610
+ ? one.equals(another)
611
+ : (one === another);
612
+ },
613
+
614
+ Collection: new JS.Class({
615
+ initialize: function(array) {
616
+ this.length = 0;
617
+ var push = Array.prototype.push;
618
+ JS.Enumerable.forEach.call(array, function(item) {
619
+ push.call(this, item);
620
+ }, this);
621
+ }
622
+ })
623
+ },
624
+
625
+ all: function(block, context) {
626
+ block = JS.Enumerable.toFn(block);
627
+ var truth = true;
628
+ this.forEach(function(item) {
629
+ truth = truth && (block ? block.apply(context || null, arguments) : item);
630
+ });
631
+ return !!truth;
632
+ },
633
+
634
+ any: function(block, context) {
635
+ block = JS.Enumerable.toFn(block);
636
+ var truth = false;
637
+ this.forEach(function(item) {
638
+ truth = truth || (block ? block.apply(context || null, arguments) : item);
639
+ });
640
+ return !!truth;
641
+ },
642
+
643
+ count: function(block, context) {
644
+ if (JS.isFn(this.size)) return this.size();
645
+ var count = 0, object = block;
646
+
647
+ if (block && !JS.isFn(block))
648
+ block = function(x) { return JS.Enumerable.areEqual(x, object) };
649
+
650
+ this.forEach(function() {
651
+ if (!block || block.apply(context || null, arguments))
652
+ count += 1;
653
+ });
654
+ return count;
655
+ },
656
+
657
+ cycle: function(n, block, context) {
658
+ if (!block) return this.enumFor('cycle', n);
659
+ block = JS.Enumerable.toFn(block);
660
+ while (n--) this.forEach(block, context);
661
+ },
662
+
663
+ drop: function(n) {
664
+ var entries = [];
665
+ this.forEachWithIndex(function(item, i) {
666
+ if (i >= n) entries.push(item);
667
+ });
668
+ return entries;
669
+ },
670
+
671
+ dropWhile: function(block, context) {
672
+ if (!block) return this.enumFor('dropWhile');
673
+ block = JS.Enumerable.toFn(block);
674
+
675
+ var entries = [],
676
+ drop = true;
677
+
678
+ this.forEach(function(item) {
679
+ if (drop) drop = drop && block.apply(context || null, arguments);
680
+ if (!drop) entries.push(item);
681
+ });
682
+ return entries;
683
+ },
684
+
685
+ forEachCons: function(n, block, context) {
686
+ if (!block) return this.enumFor('forEachCons', n);
687
+ block = JS.Enumerable.toFn(block);
688
+
689
+ var entries = this.toArray(),
690
+ size = entries.length,
691
+ limit = size - n,
692
+ i;
693
+
694
+ for (i = 0; i <= limit; i++)
695
+ block.call(context || null, entries.slice(i, i+n));
696
+
697
+ return this;
698
+ },
699
+
700
+ forEachSlice: function(n, block, context) {
701
+ if (!block) return this.enumFor('forEachSlice', n);
702
+ block = JS.Enumerable.toFn(block);
703
+
704
+ var entries = this.toArray(),
705
+ size = entries.length,
706
+ m = Math.ceil(size/n),
707
+ i;
708
+
709
+ for (i = 0; i < m; i++)
710
+ block.call(context || null, entries.slice(i*n, (i+1)*n));
711
+
712
+ return this;
713
+ },
714
+
715
+ forEachWithIndex: function(offset, block, context) {
716
+ if (JS.isFn(offset)) {
717
+ context = block;
718
+ block = offset;
719
+ offset = 0;
720
+ }
721
+ offset = offset || 0;
722
+
723
+ if (!block) return this.enumFor('forEachWithIndex', offset);
724
+ block = JS.Enumerable.toFn(block);
725
+
726
+ return this.forEach(function(item) {
727
+ var result = block.call(context || null, item, offset);
728
+ offset += 1;
729
+ return result;
730
+ });
731
+ },
732
+
733
+ forEachWithObject: function(object, block, context) {
734
+ if (!block) return this.enumFor('forEachWithObject', object);
735
+ block = JS.Enumerable.toFn(block);
736
+
737
+ this.forEach(function() {
738
+ var args = [object].concat(JS.array(arguments));
739
+ block.apply(context || null, args);
740
+ });
741
+ return object;
742
+ },
743
+
744
+ find: function(block, context) {
745
+ if (!block) return this.enumFor('find');
746
+ block = JS.Enumerable.toFn(block);
747
+
748
+ var needle = {}, K = needle;
749
+ this.forEach(function(item) {
750
+ if (needle !== K) return;
751
+ needle = block.apply(context || null, arguments) ? item : needle;
752
+ });
753
+ return needle === K ? null : needle;
754
+ },
755
+
756
+ findIndex: function(needle, context) {
757
+ if (needle === undefined) return this.enumFor('findIndex');
758
+
759
+ var index = null,
760
+ block = JS.isFn(needle);
761
+
762
+ this.forEachWithIndex(function(item, i) {
763
+ if (index !== null) return;
764
+ if (JS.Enumerable.areEqual(needle, item) || (block && needle.apply(context || null, arguments)))
765
+ index = i;
766
+ });
767
+ return index;
768
+ },
769
+
770
+ first: function(n) {
771
+ var entries = this.toArray();
772
+ return (n === undefined) ? entries[0] : entries.slice(0,n);
773
+ },
774
+
775
+ grep: function(pattern, block, context) {
776
+ block = JS.Enumerable.toFn(block);
777
+ var results = [];
778
+ this.forEach(function(item) {
779
+ var match = JS.isFn(pattern.match) ? pattern.match(item) : pattern(item);
780
+ if (!match) return;
781
+ if (block) item = block.apply(context || null, arguments);
782
+ results.push(item);
783
+ });
784
+ return results;
785
+ },
786
+
787
+ groupBy: function(block, context) {
788
+ if (!block) return this.enumFor('groupBy');
789
+ block = JS.Enumerable.toFn(block);
790
+
791
+ var hash = new JS.Hash();
792
+ this.forEach(function(item) {
793
+ var value = block.apply(context || null, arguments);
794
+ if (!hash.hasKey(value)) hash.store(value, []);
795
+ hash.get(value).push(item);
796
+ });
797
+ return hash;
798
+ },
799
+
800
+ inject: function(memo, block, context) {
801
+ var args = JS.array(arguments),
802
+ counter = 0,
803
+ K = {};
804
+
805
+ switch (args.length) {
806
+ case 1: memo = K;
807
+ block = args[0];
808
+ break;
809
+
810
+ case 2: if (JS.isFn(memo)) {
811
+ memo = K;
812
+ block = args[0];
813
+ context = args[1];
814
+ }
815
+ }
816
+ block = JS.Enumerable.toFn(block);
817
+
818
+ this.forEach(function(item) {
819
+ if (!counter++ && memo === K) return memo = item;
820
+ var args = [memo].concat(JS.array(arguments));
821
+ memo = block.apply(context || null, args);
822
+ });
823
+ return memo;
824
+ },
825
+
826
+ map: function(block, context) {
827
+ if (!block) return this.enumFor('map');
828
+ block = JS.Enumerable.toFn(block);
829
+
830
+ var map = [];
831
+ this.forEach(function() {
832
+ map.push(block.apply(context || null, arguments));
833
+ });
834
+ return map;
835
+ },
836
+
837
+ max: function(block, context) {
838
+ return this.minmax(block, context)[1];
839
+ },
840
+
841
+ maxBy: function(block, context) {
842
+ if (!block) return this.enumFor('maxBy');
843
+ return this.minmaxBy(block, context)[1];
844
+ },
845
+
846
+ member: function(needle) {
847
+ return this.any(function(item) { return JS.Enumerable.areEqual(item, needle) });
848
+ },
849
+
850
+ min: function(block, context) {
851
+ return this.minmax(block, context)[0];
852
+ },
853
+
854
+ minBy: function(block, context) {
855
+ if (!block) return this.enumFor('minBy');
856
+ return this.minmaxBy(block, context)[0];
857
+ },
858
+
859
+ minmax: function(block, context) {
860
+ var list = this.sort(block, context);
861
+ return [list[0], list[list.length - 1]];
862
+ },
863
+
864
+ minmaxBy: function(block, context) {
865
+ if (!block) return this.enumFor('minmaxBy');
866
+ var list = this.sortBy(block, context);
867
+ return [list[0], list[list.length - 1]];
868
+ },
869
+
870
+ none: function(block, context) {
871
+ return !this.any(block, context);
872
+ },
873
+
874
+ one: function(block, context) {
875
+ block = JS.Enumerable.toFn(block);
876
+ var count = 0;
877
+ this.forEach(function(item) {
878
+ if (block ? block.apply(context || null, arguments) : item) count += 1;
879
+ });
880
+ return count === 1;
881
+ },
882
+
883
+ partition: function(block, context) {
884
+ if (!block) return this.enumFor('partition');
885
+ block = JS.Enumerable.toFn(block);
886
+
887
+ var ayes = [], noes = [];
888
+ this.forEach(function(item) {
889
+ (block.apply(context || null, arguments) ? ayes : noes).push(item);
890
+ });
891
+ return [ayes, noes];
892
+ },
893
+
894
+ reject: function(block, context) {
895
+ if (!block) return this.enumFor('reject');
896
+ block = JS.Enumerable.toFn(block);
897
+
898
+ var map = [];
899
+ this.forEach(function(item) {
900
+ if (!block.apply(context || null, arguments)) map.push(item);
901
+ });
902
+ return map;
903
+ },
904
+
905
+ reverseForEach: function(block, context) {
906
+ if (!block) return this.enumFor('reverseForEach');
907
+ block = JS.Enumerable.toFn(block);
908
+
909
+ var entries = this.toArray(),
910
+ n = entries.length;
911
+
912
+ while (n--) block.call(context || null, entries[n]);
913
+ return this;
914
+ },
915
+
916
+ select: function(block, context) {
917
+ if (!block) return this.enumFor('select');
918
+ block = JS.Enumerable.toFn(block);
919
+
920
+ var map = [];
921
+ this.forEach(function(item) {
922
+ if (block.apply(context || null, arguments)) map.push(item);
923
+ });
924
+ return map;
925
+ },
926
+
927
+ sort: function(block, context) {
928
+ var comparable = JS.Enumerable.isComparable(this),
929
+ entries = this.toArray();
930
+
931
+ block = block || (comparable
932
+ ? function(a,b) { return a.compareTo(b); }
933
+ : null);
934
+ return block
935
+ ? entries.sort(function(a,b) { return block.call(context || null, a, b); })
936
+ : entries.sort();
937
+ },
938
+
939
+ sortBy: function(block, context) {
940
+ if (!block) return this.enumFor('sortBy');
941
+ block = JS.Enumerable.toFn(block);
942
+
943
+ var util = JS.Enumerable,
944
+ map = new util.Collection(this.map(block, context)),
945
+ comparable = util.isComparable(map);
946
+
947
+ return new util.Collection(map.zip(this).sort(function(a, b) {
948
+ a = a[0]; b = b[0];
949
+ return comparable ? a.compareTo(b) : (a < b ? -1 : (a > b ? 1 : 0));
950
+ })).map(function(item) { return item[1]; });
951
+ },
952
+
953
+ take: function(n) {
954
+ var entries = [];
955
+ this.forEachWithIndex(function(item, i) {
956
+ if (i < n) entries.push(item);
957
+ });
958
+ return entries;
959
+ },
960
+
961
+ takeWhile: function(block, context) {
962
+ if (!block) return this.enumFor('takeWhile');
963
+ block = JS.Enumerable.toFn(block);
964
+
965
+ var entries = [],
966
+ take = true;
967
+ this.forEach(function(item) {
968
+ if (take) take = take && block.apply(context || null, arguments);
969
+ if (take) entries.push(item);
970
+ });
971
+ return entries;
972
+ },
973
+
974
+ toArray: function() {
975
+ return this.drop(0);
976
+ },
977
+
978
+ zip: function() {
979
+ var util = JS.Enumerable,
980
+ args = [],
981
+ counter = 0,
982
+ n = arguments.length,
983
+ block, context;
984
+
985
+ if (JS.isFn(arguments[n-1])) {
986
+ block = arguments[n-1]; context = {};
987
+ }
988
+ if (JS.isFn(arguments[n-2])) {
989
+ block = arguments[n-2]; context = arguments[n-1];
990
+ }
991
+ util.forEach.call(arguments, function(arg) {
992
+ if (arg === block || arg === context) return;
993
+ if (arg.toArray) arg = arg.toArray();
994
+ if (JS.isType(arg, Array)) args.push(arg);
995
+ });
996
+ var results = this.map(function(item) {
997
+ var zip = [item];
998
+ util.forEach.call(args, function(arg) {
999
+ zip.push(arg[counter] === undefined ? null : arg[counter]);
1000
+ });
1001
+ return ++counter && zip;
1002
+ });
1003
+ if (!block) return results;
1004
+ util.forEach.call(results, block, context);
1005
+ }
1006
+ });
1007
+
1008
+ // http://developer.mozilla.org/en/docs/index.php?title=Core_JavaScript_1.5_Reference:Global_Objects:Array&oldid=58326
1009
+ JS.Enumerable.include({
1010
+ forEach: JS.Enumerable.forEach,
1011
+ collect: JS.Enumerable.instanceMethod('map'),
1012
+ detect: JS.Enumerable.instanceMethod('find'),
1013
+ entries: JS.Enumerable.instanceMethod('toArray'),
1014
+ every: JS.Enumerable.instanceMethod('all'),
1015
+ findAll: JS.Enumerable.instanceMethod('select'),
1016
+ filter: JS.Enumerable.instanceMethod('select'),
1017
+ some: JS.Enumerable.instanceMethod('any'),
1018
+
1019
+ extend: {
1020
+ toFn: function(object) {
1021
+ if (!object) return object;
1022
+ if (object.toFunction) return object.toFunction();
1023
+ if (this.OPS[object]) return this.OPS[object];
1024
+ if (JS.isType(object, 'string') || JS.isType(object, String))
1025
+ return function() {
1026
+ var args = JS.array(arguments),
1027
+ target = args.shift(),
1028
+ method = target[object];
1029
+ return JS.isFn(method) ? method.apply(target, args) : method;
1030
+ };
1031
+ return object;
1032
+ },
1033
+
1034
+ OPS: {
1035
+ '+': function(a,b) { return a + b },
1036
+ '-': function(a,b) { return a - b },
1037
+ '*': function(a,b) { return a * b },
1038
+ '/': function(a,b) { return a / b },
1039
+ '%': function(a,b) { return a % b },
1040
+ '^': function(a,b) { return a ^ b },
1041
+ '&': function(a,b) { return a & b },
1042
+ '&&': function(a,b) { return a && b },
1043
+ '|': function(a,b) { return a | b },
1044
+ '||': function(a,b) { return a || b },
1045
+ '==': function(a,b) { return a == b },
1046
+ '!=': function(a,b) { return a != b },
1047
+ '>': function(a,b) { return a > b },
1048
+ '>=': function(a,b) { return a >= b },
1049
+ '<': function(a,b) { return a < b },
1050
+ '<=': function(a,b) { return a <= b },
1051
+ '===': function(a,b) { return a === b },
1052
+ '!==': function(a,b) { return a !== b },
1053
+ '[]': function(a,b) { return a[b] },
1054
+ '()': function(a,b) { return a(b) }
1055
+ },
1056
+
1057
+ Enumerator: new JS.Class({
1058
+ include: JS.Enumerable,
1059
+
1060
+ extend: {
1061
+ DEFAULT_METHOD: 'forEach'
1062
+ },
1063
+
1064
+ initialize: function(object, method, args) {
1065
+ this._object = object;
1066
+ this._method = method || this.klass.DEFAULT_METHOD;
1067
+ this._args = (args || []).slice();
1068
+ },
1069
+
1070
+ forEach: function(block, context) {
1071
+ if (!block) return this;
1072
+ var args = this._args.slice();
1073
+ args.push(block);
1074
+ if (context) args.push(context);
1075
+ return this._object[this._method].apply(this._object, args);
1076
+ },
1077
+
1078
+ cons: JS.Enumerable.instanceMethod('forEachCons'),
1079
+ reverse: JS.Enumerable.instanceMethod('reverseForEach'),
1080
+ slice: JS.Enumerable.instanceMethod('forEachSlice'),
1081
+ withIndex: JS.Enumerable.instanceMethod('forEachWithIndex'),
1082
+ withObject: JS.Enumerable.instanceMethod('forEachWithObject')
1083
+ })
1084
+ }
1085
+ }, false);
1086
+
1087
+ JS.Enumerable.Collection.include(JS.Enumerable, true);
1088
+
1089
+ JS.Kernel.include({
1090
+ enumFor: function(method) {
1091
+ var args = JS.array(arguments),
1092
+ method = args.shift();
1093
+ return new JS.Enumerable.Enumerator(this, method, args);
1094
+ }
1095
+ }, false);
1096
+
1097
+ JS.Kernel.define('toEnum', JS.Kernel.instanceMethod('enumFor'), true);
1098
+
1099
+
1100
+ JS.LinkedList = new JS.Class('LinkedList', {
1101
+ include: JS.Enumerable || {},
1102
+
1103
+ initialize: function(array, useNodes) {
1104
+ this.length = 0;
1105
+ this.first = this.last = null;
1106
+ if (!array) return;
1107
+ for (var i = 0, n = array.length; i < n; i++)
1108
+ this.push( useNodes ? new this.klass.Node(array[i]) : array[i] );
1109
+ },
1110
+
1111
+ forEach: function(block, context) {
1112
+ if (!block) return this.enumFor('forEach');
1113
+ block = JS.Enumerable.toFn(block);
1114
+
1115
+ var node = this.first,
1116
+ next, i, n;
1117
+
1118
+ for (i = 0, n = this.length; i < n; i++) {
1119
+ next = node.next;
1120
+ block.call(context || null, node, i);
1121
+ if (node === this.last) break;
1122
+ node = next;
1123
+ }
1124
+ return this;
1125
+ },
1126
+
1127
+ at: function(n) {
1128
+ if (n < 0 || n >= this.length) return undefined;
1129
+ var node = this.first;
1130
+ while (n--) node = node.next;
1131
+ return node;
1132
+ },
1133
+
1134
+ pop: function() {
1135
+ return this.length ? this.remove(this.last) : undefined;
1136
+ },
1137
+
1138
+ shift: function() {
1139
+ return this.length ? this.remove(this.first) : undefined;
1140
+ },
1141
+
1142
+ // stubs - should be implemented by concrete list types
1143
+ insertAfter: function() {},
1144
+ push: function() {},
1145
+ remove: function() {},
1146
+
1147
+ extend: {
1148
+ Node: new JS.Class({
1149
+ initialize: function(data) {
1150
+ this.data = data;
1151
+ this.prev = this.next = this.list = null;
1152
+ }
1153
+ })
1154
+ }
1155
+ });
1156
+
1157
+ JS.LinkedList.Doubly = new JS.Class('LinkedList.Doubly', JS.LinkedList, {
1158
+ insertAt: function(n, newNode) {
1159
+ if (n < 0 || n >= this.length) return;
1160
+ this.insertBefore(this.at(n), newNode);
1161
+ },
1162
+
1163
+ unshift: function(newNode) {
1164
+ this.length > 0
1165
+ ? this.insertBefore(this.first, newNode)
1166
+ : this.push(newNode);
1167
+ },
1168
+
1169
+ insertBefore: function() {}
1170
+ });
1171
+
1172
+ JS.LinkedList.insertTemplate = function(prev, next, pos) {
1173
+ return function(node, newNode) {
1174
+ if (node.list !== this) return;
1175
+ newNode[prev] = node;
1176
+ newNode[next] = node[next];
1177
+ node[next] = (node[next][prev] = newNode);
1178
+ if (newNode[prev] === this[pos]) this[pos] = newNode;
1179
+ newNode.list = this;
1180
+ this.length++;
1181
+ };
1182
+ };
1183
+
1184
+ JS.LinkedList.Doubly.Circular = new JS.Class('LinkedList.Doubly.Circular', JS.LinkedList.Doubly, {
1185
+ insertAfter: JS.LinkedList.insertTemplate('prev', 'next', 'last'),
1186
+ insertBefore: JS.LinkedList.insertTemplate('next', 'prev', 'first'),
1187
+
1188
+ push: function(newNode) {
1189
+ if (this.length)
1190
+ return this.insertAfter(this.last, newNode);
1191
+
1192
+ this.first = this.last =
1193
+ newNode.prev = newNode.next = newNode;
1194
+
1195
+ newNode.list = this;
1196
+ this.length = 1;
1197
+ },
1198
+
1199
+ remove: function(removed) {
1200
+ if (removed.list !== this || this.length === 0) return null;
1201
+ if (this.length > 1) {
1202
+ removed.prev.next = removed.next;
1203
+ removed.next.prev = removed.prev;
1204
+ if (removed === this.first) this.first = removed.next;
1205
+ if (removed === this.last) this.last = removed.prev;
1206
+ } else {
1207
+ this.first = this.last = null;
1208
+ }
1209
+ removed.prev = removed.next = removed.list = null;
1210
+ this.length--;
1211
+ return removed;
1212
+ }
1213
+ });
1214
+
1215
+
1216
+ JS.Hash = new JS.Class('Hash', {
1217
+ include: JS.Enumerable || {},
1218
+
1219
+ extend: {
1220
+ Pair: new JS.Class({
1221
+ include: JS.Comparable || {},
1222
+
1223
+ setKey: function(key) {
1224
+ this[0] = this.key = key;
1225
+ },
1226
+
1227
+ hasKey: function(key) {
1228
+ var my = this.key;
1229
+ return my.equals ? my.equals(key) : my === key;
1230
+ },
1231
+
1232
+ setValue: function(value) {
1233
+ this[1] = this.value = value;
1234
+ },
1235
+
1236
+ hasValue: function(value) {
1237
+ var my = this.value;
1238
+ return my.equals ? my.equals(value) : my === value;
1239
+ },
1240
+
1241
+ compareTo: function(other) {
1242
+ return this.key.compareTo
1243
+ ? this.key.compareTo(other.key)
1244
+ : (this.key < other.key ? -1 : (this.key > other.key ? 1 : 0));
1245
+ },
1246
+
1247
+ hash: function() {
1248
+ var key = JS.Hash.codeFor(this.key),
1249
+ value = JS.Hash.codeFor(this.value);
1250
+
1251
+ return [key, value].sort().join('');
1252
+ }
1253
+ }),
1254
+
1255
+ codeFor: function(object) {
1256
+ if (typeof object !== 'object') return String(object);
1257
+ return JS.isFn(object.hash)
1258
+ ? object.hash()
1259
+ : object.toString();
1260
+ }
1261
+ },
1262
+
1263
+ initialize: function(object) {
1264
+ this.clear();
1265
+ if (!JS.isType(object, Array)) return this.setDefault(object);
1266
+ for (var i = 0, n = object.length; i < n; i += 2)
1267
+ this.store(object[i], object[i+1]);
1268
+ },
1269
+
1270
+ forEach: function(block, context) {
1271
+ if (!block) return this.enumFor('forEach');
1272
+ block = JS.Enumerable.toFn(block);
1273
+
1274
+ var hash, bucket, i;
1275
+
1276
+ for (hash in this._buckets) {
1277
+ if (!this._buckets.hasOwnProperty(hash)) continue;
1278
+ bucket = this._buckets[hash];
1279
+ i = bucket.length;
1280
+ while (i--) block.call(context || null, bucket[i]);
1281
+ }
1282
+ return this;
1283
+ },
1284
+
1285
+ _bucketForKey: function(key, createIfAbsent) {
1286
+ var hash = this.klass.codeFor(key),
1287
+ bucket = this._buckets[hash];
1288
+
1289
+ if (!bucket && createIfAbsent)
1290
+ bucket = this._buckets[hash] = [];
1291
+
1292
+ return bucket;
1293
+ },
1294
+
1295
+ _indexInBucket: function(bucket, key) {
1296
+ var i = bucket.length,
1297
+ ident = !!this._compareByIdentity;
1298
+
1299
+ while (i--) {
1300
+ if (ident ? (bucket[i].key === key) : bucket[i].hasKey(key))
1301
+ return i;
1302
+ }
1303
+ return -1;
1304
+ },
1305
+
1306
+ assoc: function(key, createIfAbsent) {
1307
+ var bucket, index, pair;
1308
+
1309
+ bucket = this._bucketForKey(key, createIfAbsent);
1310
+ if (!bucket) return null;
1311
+
1312
+ index = this._indexInBucket(bucket, key);
1313
+ if (index > -1) return bucket[index];
1314
+ if (!createIfAbsent) return null;
1315
+
1316
+ this.size += 1; this.length += 1;
1317
+ pair = new this.klass.Pair;
1318
+ pair.setKey(key);
1319
+ bucket.push(pair);
1320
+ return pair;
1321
+ },
1322
+
1323
+ rassoc: function(value) {
1324
+ var key = this.key(value);
1325
+ return key ? this.assoc(key) : null;
1326
+ },
1327
+
1328
+ clear: function() {
1329
+ this._buckets = {};
1330
+ this.length = this.size = 0;
1331
+ },
1332
+
1333
+ compareByIdentity: function() {
1334
+ this._compareByIdentity = true;
1335
+ },
1336
+
1337
+ comparesByIdentity: function() {
1338
+ return !!this._compareByIdentity;
1339
+ },
1340
+
1341
+ setDefault: function(value) {
1342
+ this._default = value;
1343
+ return this;
1344
+ },
1345
+
1346
+ getDefault: function(key) {
1347
+ return JS.isFn(this._default)
1348
+ ? this._default(this, key)
1349
+ : (this._default || null);
1350
+ },
1351
+
1352
+ equals: function(other) {
1353
+ if (!JS.isType(other, JS.Hash) || this.length !== other.length)
1354
+ return false;
1355
+ var result = true;
1356
+ this.forEach(function(pair) {
1357
+ if (!result) return;
1358
+ var otherPair = other.assoc(pair.key);
1359
+ if (otherPair === null || !otherPair.hasValue(pair.value)) result = false;
1360
+ });
1361
+ return result;
1362
+ },
1363
+
1364
+ hash: function() {
1365
+ var hashes = [];
1366
+ this.forEach(function(pair) { hashes.push(pair.hash()) });
1367
+ return hashes.sort().join('');
1368
+ },
1369
+
1370
+ fetch: function(key, defaultValue) {
1371
+ var pair = this.assoc(key);
1372
+ if (pair) return pair.value;
1373
+
1374
+ if (defaultValue === undefined) throw new Error('key not found');
1375
+ if (JS.isFn(defaultValue)) return defaultValue(key);
1376
+ return defaultValue;
1377
+ },
1378
+
1379
+ forEachKey: function(block, context) {
1380
+ if (!block) return this.enumFor('forEachKey');
1381
+ block = JS.Enumerable.toFn(block);
1382
+
1383
+ this.forEach(function(pair) {
1384
+ block.call(context || null, pair.key);
1385
+ });
1386
+ return this;
1387
+ },
1388
+
1389
+ forEachPair: function(block, context) {
1390
+ if (!block) return this.enumFor('forEachPair');
1391
+ block = JS.Enumerable.toFn(block);
1392
+
1393
+ this.forEach(function(pair) {
1394
+ block.call(context || null, pair.key, pair.value);
1395
+ });
1396
+ return this;
1397
+ },
1398
+
1399
+ forEachValue: function(block, context) {
1400
+ if (!block) return this.enumFor('forEachValue');
1401
+ block = JS.Enumerable.toFn(block);
1402
+
1403
+ this.forEach(function(pair) {
1404
+ block.call(context || null, pair.value);
1405
+ });
1406
+ return this;
1407
+ },
1408
+
1409
+ get: function(key) {
1410
+ var pair = this.assoc(key);
1411
+ return pair ? pair.value : this.getDefault(key);
1412
+ },
1413
+
1414
+ hasKey: function(key) {
1415
+ return !!this.assoc(key);
1416
+ },
1417
+
1418
+ hasValue: function(value) {
1419
+ var has = false, ident = !!this._compareByIdentity;
1420
+ this.forEach(function(pair) {
1421
+ if ((value.equals && !ident) ? value.equals(pair.value) : value === pair.value)
1422
+ has = true;
1423
+ });
1424
+ return has;
1425
+ },
1426
+
1427
+ invert: function() {
1428
+ var hash = new this.klass;
1429
+ this.forEach(function(pair) {
1430
+ hash.store(pair.value, pair.key);
1431
+ });
1432
+ return hash;
1433
+ },
1434
+
1435
+ isEmpty: function() {
1436
+ for (var hash in this._buckets) {
1437
+ if (this._buckets.hasOwnProperty(hash) && this._buckets[hash].length > 0)
1438
+ return false;
1439
+ }
1440
+ return true;
1441
+ },
1442
+
1443
+ key: function(value) {
1444
+ var result = null;
1445
+ this.forEach(function(pair) {
1446
+ if (value.equals ? value.equals(pair.value) : (value === pair.value))
1447
+ result = pair.key;
1448
+ });
1449
+ return result;
1450
+ },
1451
+
1452
+ keys: function() {
1453
+ var keys = [];
1454
+ this.forEach(function(pair) { keys.push(pair.key) });
1455
+ return keys;
1456
+ },
1457
+
1458
+ merge: function(hash, block, context) {
1459
+ var newHash = new this.klass;
1460
+ newHash.update(this);
1461
+ newHash.update(hash, block, context);
1462
+ return newHash;
1463
+ },
1464
+
1465
+ rehash: function() {
1466
+ var temp = new this.klass;
1467
+ temp._buckets = this._buckets;
1468
+ this.clear();
1469
+ this.update(temp);
1470
+ },
1471
+
1472
+ remove: function(key, block) {
1473
+ if (block === undefined) block = null;
1474
+ var bucket, index, result;
1475
+
1476
+ bucket = this._bucketForKey(key);
1477
+ if (!bucket) return JS.isFn(block) ? this.fetch(key, block) : this.getDefault(key);
1478
+
1479
+ index = this._indexInBucket(bucket, key);
1480
+ if (index < 0) return JS.isFn(block) ? this.fetch(key, block) : this.getDefault(key);
1481
+
1482
+ result = bucket[index].value;
1483
+ bucket.splice(index, 1);
1484
+ this.size -= 1;
1485
+ this.length -= 1;
1486
+
1487
+ if (bucket.length === 0)
1488
+ delete this._buckets[this.klass.codeFor(key)];
1489
+
1490
+ return result;
1491
+ },
1492
+
1493
+ removeIf: function(block, context) {
1494
+ if (!block) return this.enumFor('removeIf');
1495
+ block = JS.Enumerable.toFn(block);
1496
+
1497
+ this.forEach(function(pair) {
1498
+ if (block.call(context || null, pair))
1499
+ this.remove(pair.key);
1500
+ }, this);
1501
+ return this;
1502
+ },
1503
+
1504
+ replace: function(hash) {
1505
+ this.clear();
1506
+ this.update(hash);
1507
+ },
1508
+
1509
+ shift: function() {
1510
+ var keys = this.keys();
1511
+ if (keys.length === 0) return this.getDefault();
1512
+ var pair = this.assoc(keys[0]);
1513
+ this.remove(pair.key);
1514
+ return pair;
1515
+ },
1516
+
1517
+ store: function(key, value) {
1518
+ this.assoc(key, true).setValue(value);
1519
+ return value;
1520
+ },
1521
+
1522
+ update: function(hash, block, context) {
1523
+ var blockGiven = JS.isFn(block);
1524
+ hash.forEach(function(pair) {
1525
+ var key = pair.key, value = pair.value;
1526
+ if (blockGiven && this.hasKey(key))
1527
+ value = block.call(context || null, key, this.get(key), value);
1528
+ this.store(key, value);
1529
+ }, this);
1530
+ },
1531
+
1532
+ values: function() {
1533
+ var values = [];
1534
+ this.forEach(function(pair) { values.push(pair.value) });
1535
+ return values;
1536
+ },
1537
+
1538
+ valuesAt: function() {
1539
+ var i = arguments.length, results = [];
1540
+ while (i--) results.push(this.get(arguments[i]));
1541
+ return results;
1542
+ }
1543
+ });
1544
+
1545
+ JS.Hash.include({
1546
+ includes: JS.Hash.instanceMethod('hasKey'),
1547
+ index: JS.Hash.instanceMethod('key'),
1548
+ put: JS.Hash.instanceMethod('store')
1549
+ }, true);
1550
+
1551
+
1552
+ JS.Set = new JS.Class('Set', {
1553
+ extend: {
1554
+ forEach: function(list, block, context) {
1555
+ if (!list || !block) return;
1556
+ if (list.forEach) return list.forEach(block, context);
1557
+ for (var i = 0, n = list.length; i < n; i++) {
1558
+ if (list[i] !== undefined)
1559
+ block.call(context || null, list[i], i);
1560
+ }
1561
+ }
1562
+ },
1563
+
1564
+ include: JS.Enumerable || {},
1565
+
1566
+ initialize: function(list, block, context) {
1567
+ this.clear();
1568
+ if (block) this.klass.forEach(list, function(item) {
1569
+ this.add(block.call(context || null, item));
1570
+ }, this);
1571
+ else this.merge(list);
1572
+ },
1573
+
1574
+ forEach: function(block, context) {
1575
+ if (!block) return this.enumFor('forEach');
1576
+ block = JS.Enumerable.toFn(block);
1577
+
1578
+ this.klass.forEach(this._members, block, context);
1579
+ return this;
1580
+ },
1581
+
1582
+ add: function(item) {
1583
+ if (this.contains(item)) return false;
1584
+ this._members.push(item);
1585
+ this.length = this.size = this._members.length;
1586
+ return true;
1587
+ },
1588
+
1589
+ classify: function(block, context) {
1590
+ if (!block) return this.enumFor('classify');
1591
+ block = JS.Enumerable.toFn(block);
1592
+
1593
+ var classes = new JS.Hash();
1594
+ this.forEach(function(item) {
1595
+ var value = block.call(context || null, item);
1596
+ if (!classes.hasKey(value)) classes.store(value, new this.klass);
1597
+ classes.get(value).add(item);
1598
+ }, this);
1599
+ return classes;
1600
+ },
1601
+
1602
+ clear: function() {
1603
+ this._members = [];
1604
+ this.length = this.size = 0;
1605
+ },
1606
+
1607
+ complement: function(other) {
1608
+ var set = new this.klass;
1609
+ this.klass.forEach(other, function(item) {
1610
+ if (!this.contains(item)) set.add(item);
1611
+ }, this);
1612
+ return set;
1613
+ },
1614
+
1615
+ contains: function(item) {
1616
+ return this._indexOf(item) !== -1;
1617
+ },
1618
+
1619
+ difference: function(other) {
1620
+ other = JS.isType(other, JS.Set) ? other : new JS.Set(other);
1621
+ var set = new this.klass;
1622
+ this.forEach(function(item) {
1623
+ if (!other.contains(item)) set.add(item);
1624
+ });
1625
+ return set;
1626
+ },
1627
+
1628
+ divide: function(block, context) {
1629
+ if (!block) return this.enumFor('divide');
1630
+ block = JS.Enumerable.toFn(block);
1631
+
1632
+ var classes = this.classify(block, context),
1633
+ sets = new this.klass;
1634
+
1635
+ classes.forEachValue(sets.method('add'));
1636
+ return sets;
1637
+ },
1638
+
1639
+ equals: function(other) {
1640
+ if (this.length !== other.length || !JS.isType(other, JS.Set)) return false;
1641
+ var result = true;
1642
+ this.forEach(function(item) {
1643
+ if (!result) return;
1644
+ if (!other.contains(item)) result = false;
1645
+ });
1646
+ return result;
1647
+ },
1648
+
1649
+ hash: function() {
1650
+ var hashes = [];
1651
+ this.forEach(function(object) { hashes.push(JS.Hash.codeFor(object)) });
1652
+ return hashes.sort().join('');
1653
+ },
1654
+
1655
+ flatten: function(set) {
1656
+ var copy = new this.klass;
1657
+ copy._members = this._members;
1658
+ if (!set) { set = this; set.clear(); }
1659
+ copy.forEach(function(item) {
1660
+ if (JS.isType(item, JS.Set)) item.flatten(set);
1661
+ else set.add(item);
1662
+ });
1663
+ return set;
1664
+ },
1665
+
1666
+ intersection: function(other) {
1667
+ var set = new this.klass;
1668
+ this.klass.forEach(other, function(item) {
1669
+ if (this.contains(item)) set.add(item);
1670
+ }, this);
1671
+ return set;
1672
+ },
1673
+
1674
+ isEmpty: function() {
1675
+ return this._members.length === 0;
1676
+ },
1677
+
1678
+ isProperSubset: function(other) {
1679
+ return this._members.length < other._members.length && this.isSubset(other);
1680
+ },
1681
+
1682
+ isProperSuperset: function(other) {
1683
+ return this._members.length > other._members.length && this.isSuperset(other);
1684
+ },
1685
+
1686
+ isSubset: function(other) {
1687
+ var result = true;
1688
+ this.forEach(function(item) {
1689
+ if (!result) return;
1690
+ if (!other.contains(item)) result = false;
1691
+ });
1692
+ return result;
1693
+ },
1694
+
1695
+ isSuperset: function(other) {
1696
+ return other.isSubset(this);
1697
+ },
1698
+
1699
+ merge: function(list) {
1700
+ this.klass.forEach(list, function(item) { this.add(item) }, this);
1701
+ },
1702
+
1703
+ product: function(other) {
1704
+ var pairs = new JS.Set;
1705
+ this.forEach(function(item) {
1706
+ this.klass.forEach(other, function(partner) {
1707
+ pairs.add([item, partner]);
1708
+ });
1709
+ }, this);
1710
+ return pairs;
1711
+ },
1712
+
1713
+ rebuild: function() {
1714
+ var members = this._members;
1715
+ this.clear();
1716
+ this.merge(members);
1717
+ },
1718
+
1719
+ remove: function(item) {
1720
+ var index = this._indexOf(item);
1721
+ if (index === -1) return;
1722
+ this._members.splice(index, 1);
1723
+ this.length = this.size = this._members.length;
1724
+ },
1725
+
1726
+ removeIf: function(block, context) {
1727
+ if (!block) return this.enumFor('removeIf');
1728
+ block = JS.Enumerable.toFn(block);
1729
+
1730
+ var members = this._members,
1731
+ i = members.length;
1732
+
1733
+ while (i--) {
1734
+ if (block.call(context || null, members[i]))
1735
+ this.remove(members[i]);
1736
+ }
1737
+ return this;
1738
+ },
1739
+
1740
+ replace: function(other) {
1741
+ this.clear();
1742
+ this.merge(other);
1743
+ },
1744
+
1745
+ subtract: function(list) {
1746
+ this.klass.forEach(list, function(item) {
1747
+ this.remove(item);
1748
+ }, this);
1749
+ },
1750
+
1751
+ union: function(other) {
1752
+ var set = new this.klass;
1753
+ set.merge(this);
1754
+ set.merge(other);
1755
+ return set;
1756
+ },
1757
+
1758
+ xor: function(other) {
1759
+ var set = new JS.Set(other);
1760
+ this.forEach(function(item) {
1761
+ set[set.contains(item) ? 'remove' : 'add'](item);
1762
+ });
1763
+ return set;
1764
+ },
1765
+
1766
+ _indexOf: function(item) {
1767
+ var i = this._members.length,
1768
+ equal = JS.Enumerable.areEqual;
1769
+
1770
+ while (i--) {
1771
+ if (equal(item, this._members[i])) return i;
1772
+ }
1773
+ return -1;
1774
+ }
1775
+ });
1776
+
1777
+ JS.Set.include({
1778
+ n: JS.Set.instanceMethod('intersection'),
1779
+ u: JS.Set.instanceMethod('union'),
1780
+ x: JS.Set.instanceMethod('product')
1781
+ }, false);
1782
+
1783
+ JS.SortedSet = new JS.Class('SortedSet', JS.Set, {
1784
+ extend: {
1785
+ compare: function(one, another) {
1786
+ return JS.isType(one, Object)
1787
+ ? one.compareTo(another)
1788
+ : (one < another ? -1 : (one > another ? 1 : 0));
1789
+ }
1790
+ },
1791
+
1792
+ add: function(item) {
1793
+ var point = this._indexOf(item, true);
1794
+ if (point === null) return;
1795
+ this._members.splice(point, 0, item);
1796
+ this.length = this.size = this._members.length;
1797
+ },
1798
+
1799
+ _indexOf: function(item, insertionPoint) {
1800
+ var items = this._members,
1801
+ n = items.length,
1802
+ i = 0,
1803
+ d = n,
1804
+ compare = this.klass.compare,
1805
+ equal = JS.Enumerable.areEqual,
1806
+ found;
1807
+
1808
+ if (n === 0) return insertionPoint ? 0 : -1;
1809
+
1810
+ if (compare(item, items[0]) < 1) { d = 0; i = 0; }
1811
+ if (compare(item, items[n-1]) > 0) { d = 0; i = n; }
1812
+
1813
+ while (!equal(item, items[i]) && d > 0.5) {
1814
+ d = d / 2;
1815
+ i += (compare(item, items[i]) > 0 ? 1 : -1) * Math.round(d);
1816
+ if (i > 0 && compare(item, items[i-1]) > 0 && compare(item, items[i]) < 1) d = 0;
1817
+ }
1818
+
1819
+ // The pointer will end up at the start of any homogenous section. Step
1820
+ // through the section until we find the needle or until the section ends.
1821
+ while (items[i] && !equal(item, items[i]) &&
1822
+ compare(item, items[i]) === 0) i += 1;
1823
+
1824
+ found = equal(item, items[i]);
1825
+ return insertionPoint
1826
+ ? (found ? null : i)
1827
+ : (found ? i : -1);
1828
+ }
1829
+ });
1830
+
1831
+ JS.HashSet = new JS.Class('HashSet', JS.Set, {
1832
+ forEach: function(block, context) {
1833
+ if (!block) return this.enumFor('forEach');
1834
+ block = JS.Enumerable.toFn(block);
1835
+
1836
+ this._members.forEachKey(block, context);
1837
+ return this;
1838
+ },
1839
+
1840
+ add: function(item) {
1841
+ if (this.contains(item)) return false;
1842
+ this._members.store(item, true);
1843
+ this.length = this.size = this._members.length;
1844
+ return true;
1845
+ },
1846
+
1847
+ clear: function() {
1848
+ this._members = new JS.Hash();
1849
+ this.size = this.length = 0;
1850
+ },
1851
+
1852
+ contains: function(item) {
1853
+ return this._members.hasKey(item);
1854
+ },
1855
+
1856
+ rebuild: function() {
1857
+ this._members.rehash();
1858
+ this.length = this.size = this._members.length;
1859
+ },
1860
+
1861
+ remove: function(item) {
1862
+ this._members.remove(item);
1863
+ this.length = this.size = this._members.length;
1864
+ },
1865
+
1866
+ removeIf: function(block, context) {
1867
+ if (!block) return this.enumFor('removeIf');
1868
+ block = JS.Enumerable.toFn(block);
1869
+
1870
+ this._members.removeIf(function(pair) {
1871
+ return block.call(context || null, pair.key);
1872
+ });
1873
+ this.length = this.size = this._members.length;
1874
+ return this;
1875
+ }
1876
+ });
1877
+
1878
+ JS.Enumerable.include({
1879
+ toSet: function(klass, block, context) {
1880
+ klass = klass || JS.Set;
1881
+ return new klass(this, block, context);
1882
+ }
1883
+ }, true);
1884
+
1885
+
1886
+ JS.Observable = new JS.Module('Observable', {
1887
+ extend: {
1888
+ DEFAULT_METHOD: 'update'
1889
+ },
1890
+
1891
+ addObserver: function(observer, context) {
1892
+ (this.__observers__ = this.__observers__ || []).push({_block: observer, _context: context || null});
1893
+ },
1894
+
1895
+ removeObserver: function(observer, context) {
1896
+ this.__observers__ = this.__observers__ || [];
1897
+ context = context || null;
1898
+ var i = this.countObservers();
1899
+ while (i--) {
1900
+ if (this.__observers__[i]._block === observer && this.__observers__[i]._context === context) {
1901
+ this.__observers__.splice(i,1);
1902
+ return;
1903
+ }
1904
+ }
1905
+ },
1906
+
1907
+ removeObservers: function() {
1908
+ this.__observers__ = [];
1909
+ },
1910
+
1911
+ countObservers: function() {
1912
+ return (this.__observers__ = this.__observers__ || []).length;
1913
+ },
1914
+
1915
+ notifyObservers: function() {
1916
+ if (!this.isChanged()) return;
1917
+ var i = this.countObservers(), observer, block, context;
1918
+ while (i--) {
1919
+ observer = this.__observers__[i];
1920
+ block = observer._block;
1921
+ context = observer._context;
1922
+ if (JS.isFn(block)) block.apply(context || null, arguments);
1923
+ else block[context || JS.Observable.DEFAULT_METHOD].apply(block, arguments);
1924
+ }
1925
+ },
1926
+
1927
+ setChanged: function(state) {
1928
+ this.__changed__ = !(state === false);
1929
+ },
1930
+
1931
+ isChanged: function() {
1932
+ if (this.__changed__ === undefined) this.__changed__ = true;
1933
+ return !!this.__changed__;
1934
+ }
1935
+ });
1936
+
1937
+ JS.Observable.include({
1938
+ subscribe: JS.Observable.instanceMethod('addObserver'),
1939
+ unsubscribe: JS.Observable.instanceMethod('removeObserver')
1940
+ }, true);
1941
+
1942
+
1943
+ JS.Forwardable = new JS.Module('Forwardable', {
1944
+ defineDelegator: function(subject, method, alias, resolve) {
1945
+ alias = alias || method;
1946
+ this.define(alias, function() {
1947
+ var object = this[subject],
1948
+ property = object[method];
1949
+
1950
+ return JS.isFn(property)
1951
+ ? property.apply(object, arguments)
1952
+ : property;
1953
+ }, resolve !== false);
1954
+ },
1955
+
1956
+ defineDelegators: function() {
1957
+ var methods = JS.array(arguments),
1958
+ subject = methods.shift(),
1959
+ i = methods.length;
1960
+
1961
+ while (i--) this.defineDelegator(subject, methods[i], methods[i], false);
1962
+ this.resolve();
1963
+ }
1964
+ });
1965
+
1966
+
1967
+ JS.ConstantScope = new JS.Module('ConstantScope', {
1968
+ extend: {
1969
+ included: function(base) {
1970
+ base.__consts__ = new JS.Module();
1971
+ base.extend(this.ClassMethods);
1972
+
1973
+ base.include(base.__consts__);
1974
+ base.extend(base.__consts__);
1975
+
1976
+ base.include(base.__mod__.__fns__);
1977
+ base.extend(base.__eigen__().__fns__);
1978
+ },
1979
+
1980
+ ClassMethods: new JS.Module({
1981
+ extend: function() {
1982
+ var constants = JS.ConstantScope.extract(arguments[0], this);
1983
+ this.__consts__.include(constants);
1984
+ this.callSuper();
1985
+ },
1986
+
1987
+ include: function() {
1988
+ var constants = JS.ConstantScope.extract(arguments[0], this);
1989
+ this.__consts__.include(constants);
1990
+ this.callSuper();
1991
+ }
1992
+ }),
1993
+
1994
+ extract: function(inclusions, base) {
1995
+ if (!inclusions) return null;
1996
+ if (JS.isType(inclusions, JS.Module)) return null;
1997
+ var constants = {}, key, object;
1998
+ for (key in inclusions) {
1999
+
2000
+ if (!/^[A-Z]/.test(key)) continue;
2001
+
2002
+ object = inclusions[key];
2003
+ constants[key] = object;
2004
+ delete inclusions[key];
2005
+
2006
+ if (JS.isType(object, JS.Module)) {
2007
+ object.include(this);
2008
+ object.__consts__.include(base.__consts__);
2009
+ }
2010
+ }
2011
+ return constants;
2012
+ }
2013
+ }
2014
+ });
2015
+
2016
+
2017
+ JS.Decorator = new JS.Class('Decorator', {
2018
+ initialize: function(decoree, methods) {
2019
+ var decorator = new JS.Class(),
2020
+ delegators = {},
2021
+ method, func;
2022
+
2023
+ for (method in decoree.prototype) {
2024
+ func = decoree.prototype[method];
2025
+ if (JS.isFn(func) && func !== decoree) func = this.klass.delegate(method);
2026
+ delegators[method] = func;
2027
+ }
2028
+
2029
+ decorator.include(new JS.Module(delegators), false);
2030
+ decorator.include(this.klass.InstanceMethods, false);
2031
+ decorator.include(methods, true);
2032
+ return decorator;
2033
+ },
2034
+
2035
+ extend: {
2036
+ delegate: function(name) {
2037
+ return function() {
2038
+ return this.component[name].apply(this.component, arguments);
2039
+ };
2040
+ },
2041
+
2042
+ InstanceMethods: new JS.Module({
2043
+ initialize: function(component) {
2044
+ this.component = component;
2045
+ this.klass = this.constructor = component.klass;
2046
+ var method, func;
2047
+ for (method in component) {
2048
+ if (this[method]) continue;
2049
+ func = component[method];
2050
+ if (JS.isFn(func)) func = JS.Decorator.delegate(method);
2051
+ this[method] = func;
2052
+ }
2053
+ },
2054
+
2055
+ extend: function(source) {
2056
+ this.component.extend(source);
2057
+ var method, func;
2058
+ for (method in source) {
2059
+ func = source[method];
2060
+ if (JS.isFn(func)) func = JS.Decorator.delegate(method);
2061
+ this[method] = func;
2062
+ }
2063
+ }
2064
+ })
2065
+ }
2066
+ });
2067
+
2068
+
2069
+ if (JS.Proxy === undefined) JS.Proxy = {};
2070
+
2071
+ JS.Proxy.Virtual = new JS.Class('Proxy.Virtual', {
2072
+ initialize: function(klass) {
2073
+ var bridge = function() {},
2074
+ proxy = new JS.Class(),
2075
+ delegators = {},
2076
+ method, func;
2077
+
2078
+ bridge.prototype = klass.prototype;
2079
+
2080
+ for (method in klass.prototype) {
2081
+ func = klass.prototype[method];
2082
+ if (JS.isFn(func) && func !== klass) func = this.klass.forward(method);
2083
+ delegators[method] = func;
2084
+ }
2085
+
2086
+ proxy.include({
2087
+ initialize: function() {
2088
+ var args = arguments,
2089
+ subject = null;
2090
+
2091
+ this.__getSubject__ = function() {
2092
+ subject = new bridge;
2093
+ klass.apply(subject, args);
2094
+ return (this.__getSubject__ = function() { return subject; })();
2095
+ };
2096
+ },
2097
+ klass: klass,
2098
+ constructor: klass
2099
+ }, false);
2100
+
2101
+ proxy.include(new JS.Module(delegators), false);
2102
+ proxy.include(this.klass.InstanceMethods, true);
2103
+ return proxy;
2104
+ },
2105
+
2106
+ extend: {
2107
+ forward: function(name) {
2108
+ return function() {
2109
+ var subject = this.__getSubject__();
2110
+ return subject[name].apply(subject, arguments);
2111
+ };
2112
+ },
2113
+
2114
+ InstanceMethods: new JS.Module({
2115
+ extend: function(source) {
2116
+ this.__getSubject__().extend(source);
2117
+ var method, func;
2118
+ for (method in source) {
2119
+ func = source[method];
2120
+ if (JS.isFn(func)) func = JS.Proxy.Virtual.forward(method);
2121
+ this[method] = func;
2122
+ }
2123
+ }
2124
+ })
2125
+ }
2126
+ });
2127
+
2128
+
2129
+ JS.Command = new JS.Class('Command', {
2130
+ initialize: function(functions) {
2131
+ if (JS.isFn(functions))
2132
+ functions = {execute: functions};
2133
+ this._functions = functions;
2134
+ this._stack = this._functions.stack || null;
2135
+ },
2136
+
2137
+ execute: function(push) {
2138
+ if (this._stack) this._stack._restart();
2139
+ var exec = this._functions.execute;
2140
+ if (exec) exec.apply(this);
2141
+ if (this._stack && push !== false) this._stack.push(this);
2142
+ },
2143
+
2144
+ undo: function() {
2145
+ var exec = this._functions.undo;
2146
+ if (exec) exec.apply(this);
2147
+ },
2148
+
2149
+ extend: {
2150
+ Stack: new JS.Class({
2151
+ include: [JS.Observable || {}, JS.Enumerable || {}],
2152
+
2153
+ initialize: function(options) {
2154
+ options = options || {};
2155
+ this._redo = options.redo || null;
2156
+ this.clear();
2157
+ },
2158
+
2159
+ forEach: function(block, context) {
2160
+ if (!block) return this.enumFor('forEach');
2161
+ block = JS.Enumerable.toFn(block);
2162
+
2163
+ for (var i = 0, n = this._stack.length; i < n; i++) {
2164
+ if (this._stack[i] !== undefined)
2165
+ block.call(context || null, this._stack[i], i);
2166
+ }
2167
+ return this;
2168
+ },
2169
+
2170
+ clear: function() {
2171
+ this._stack = [];
2172
+ this.length = this.pointer = 0;
2173
+ },
2174
+
2175
+ _restart: function() {
2176
+ if (this.pointer === 0 && this._redo && this._redo.execute)
2177
+ this._redo.execute();
2178
+ },
2179
+
2180
+ push: function(command) {
2181
+ this._stack.splice(this.pointer, this.length);
2182
+ this._stack.push(command);
2183
+ this.length = this.pointer = this._stack.length;
2184
+ if (this.notifyObservers) this.notifyObservers(this);
2185
+ },
2186
+
2187
+ stepTo: function(position) {
2188
+ if (position < 0 || position > this.length) return;
2189
+ var i, n;
2190
+
2191
+ switch (true) {
2192
+ case position > this.pointer :
2193
+ for (i = this.pointer, n = position; i < n; i++)
2194
+ this._stack[i].execute(false);
2195
+ break;
2196
+
2197
+ case position < this.pointer :
2198
+ if (this._redo && this._redo.execute) {
2199
+ this._redo.execute();
2200
+ for (i = 0, n = position; i < n; i++)
2201
+ this._stack[i].execute(false);
2202
+ } else {
2203
+ for (i = 0, n = this.pointer - position; i < n; i++)
2204
+ this._stack[this.pointer - i - 1].undo();
2205
+ }
2206
+ break;
2207
+ }
2208
+ this.pointer = position;
2209
+ if (this.notifyObservers) this.notifyObservers(this);
2210
+ },
2211
+
2212
+ undo: function() {
2213
+ this.stepTo(this.pointer - 1);
2214
+ },
2215
+
2216
+ redo: function() {
2217
+ this.stepTo(this.pointer + 1);
2218
+ }
2219
+ })
2220
+ }
2221
+ });
2222
+
2223
+
2224
+ JS.State = new JS.Module('State', {
2225
+ __getState__: function(state) {
2226
+ return (typeof state === 'object' && state) ||
2227
+ (typeof state === 'string' && ((this.states || {})[state] || {})) ||
2228
+ {};
2229
+ },
2230
+
2231
+ setState: function(state) {
2232
+ this.__state__ = this.__getState__(state);
2233
+ JS.State.addMethods(this.__state__, this.klass);
2234
+ },
2235
+
2236
+ inState: function() {
2237
+ var i = arguments.length;
2238
+ while (i--) {
2239
+ if (this.__state__ === this.__getState__(arguments[i])) return true;
2240
+ }
2241
+ return false;
2242
+ },
2243
+
2244
+ extend: {
2245
+ stub: function() { return this; },
2246
+
2247
+ buildStubs: function(stubs, collection, states) {
2248
+ var state, method;
2249
+ for (state in states) {
2250
+ collection[state] = {};
2251
+ for (method in states[state]) stubs[method] = this.stub;
2252
+ } },
2253
+
2254
+ findStates: function(collections, name) {
2255
+ var i = collections.length, results = [];
2256
+ while (i--) {
2257
+ if (collections[i].hasOwnProperty(name))
2258
+ results.push(collections[i][name]);
2259
+ }
2260
+ return results;
2261
+ },
2262
+
2263
+ buildCollection: function(module, states) {
2264
+ var stubs = {},
2265
+ collection = {},
2266
+ superstates = module.lookup('states'),
2267
+ state, klass, methods, name, mixins, i, n;
2268
+
2269
+ this.buildStubs(stubs, collection, states);
2270
+
2271
+ for (i = 0, n = superstates.length; i < n; i++)
2272
+ this.buildStubs(stubs, collection, superstates[i]);
2273
+
2274
+ for (state in collection) {
2275
+ klass = new JS.Class(states[state]);
2276
+ mixins = this.findStates(superstates, state);
2277
+
2278
+ i = mixins.length;
2279
+ while (i--) klass.include(mixins[i].klass);
2280
+
2281
+ methods = {};
2282
+ for (name in stubs) { if (!klass.prototype[name]) methods[name] = stubs[name]; }
2283
+ klass.include(methods);
2284
+ collection[state] = new klass;
2285
+ }
2286
+ if (module.__res__) this.addMethods(stubs, module.__res__.klass);
2287
+ return collection;
2288
+ },
2289
+
2290
+ addMethods: function(state, klass) {
2291
+ if (!klass) return;
2292
+
2293
+ var methods = {},
2294
+ p = klass.prototype,
2295
+ method;
2296
+
2297
+ for (method in state) {
2298
+ if (p[method]) continue;
2299
+ p[method] = klass.__mod__.__fns__[method] = this.wrapped(method);
2300
+ }
2301
+ },
2302
+
2303
+ wrapped: function(method) {
2304
+ return function() {
2305
+ var func = (this.__state__ || {})[method];
2306
+ return func ? func.apply(this, arguments): this;
2307
+ };
2308
+ }
2309
+ }
2310
+ });
2311
+
2312
+ JS.Module.include({define: (function(wrapped) {
2313
+ return function(name, block) {
2314
+ if (name === 'states' && typeof block === 'object')
2315
+ arguments[1] = JS.State.buildCollection(this, block);
2316
+ return wrapped.apply(this, arguments);
2317
+ };
2318
+ })(JS.Module.prototype.define)}, true);
2319
+
2320
+
2321
+ JS.StackTrace = new JS.Module('StackTrace', {
2322
+ extend: {
2323
+ included: function(base) {
2324
+ var module = base.__mod__ || base,
2325
+ self = this,
2326
+ method;
2327
+
2328
+ module.extend({define: function(name, func) {
2329
+ if (!JS.isFn(func)) return this.callSuper();
2330
+ var wrapper = self.wrap(func, module, name);
2331
+ return this.callSuper(name, wrapper);
2332
+ } });
2333
+
2334
+ for (method in module.__fns__)
2335
+ module.define(method, module.__fns__[method], false);
2336
+ module.resolve();
2337
+
2338
+ if (!module.__nom__) setTimeout(function() {
2339
+ module.__nom__ = self.nameOf(base);
2340
+ }, 1);
2341
+ },
2342
+
2343
+ nameOf: function(object, root) {
2344
+ var results = [], i, n, field, l;
2345
+
2346
+ if (JS.isType(object, Array)) {
2347
+ for (i = 0, n = object.length; i < n; i++)
2348
+ results.push(this.nameOf(object[i]));
2349
+ return results;
2350
+ }
2351
+
2352
+ if (object.__nom__) return object.__nom__;
2353
+
2354
+ field = [{name: null, o: root || this.root}];
2355
+ l = 0;
2356
+ while (typeof field === 'object' && l < this.maxDepth) {
2357
+ l += 1;
2358
+ field = this.descend(field, object);
2359
+ }
2360
+ if (typeof field == 'string') {
2361
+ field = field.replace(/\.prototype\./g, '#');
2362
+ object.__nom__ = field;
2363
+ if (object.__meta__) object.__meta__.__nom__ = field + '.__meta__';
2364
+ }
2365
+ return object.__nom__;
2366
+ },
2367
+
2368
+ descend: function(list, needle) {
2369
+ var results = [],
2370
+ n = list.length,
2371
+ i = n,
2372
+ key, item, name;
2373
+
2374
+ while (i--) {
2375
+ item = list[i];
2376
+ if (n > 1 && JS.indexOf(this.excluded, item.o) !== -1) continue;
2377
+ if (JS.isType(item.o, Array)) continue;
2378
+ name = item.name ? item.name + '.' : '';
2379
+ for (key in item.o) {
2380
+ if (needle && item.o[key] === needle) return name + key;
2381
+ results.push({name: name + key, o: item.o[key]});
2382
+ }
2383
+ }
2384
+ return results;
2385
+ },
2386
+
2387
+ root: this,
2388
+ excluded: [],
2389
+ maxDepth: 8,
2390
+ logLevel: 'full',
2391
+
2392
+ stack: new JS.Singleton({
2393
+ _list: [],
2394
+
2395
+ indent: function() {
2396
+ var indent = '',
2397
+ n = this._list.length;
2398
+
2399
+ while (n--) indent += '| ';
2400
+ return indent;
2401
+ },
2402
+
2403
+ push: function(name, object, args) {
2404
+ if (JS.StackTrace.logLevel === 'full') window.console &&
2405
+ console.log(this.indent() + name + '(', args, ')');
2406
+ this._list.push({name: name, object: object, args: args});
2407
+ },
2408
+
2409
+ pop: function(result) {
2410
+ var name = this._list.pop().name;
2411
+ if (JS.StackTrace.logLevel === 'full') window.console &&
2412
+ console.log(this.indent() + name + '() --> ', result);
2413
+ return name;
2414
+ },
2415
+
2416
+ top: function() {
2417
+ return this._list[this._list.length - 1] || {};
2418
+ },
2419
+
2420
+ backtrace: function() {
2421
+ var i = this._list.length, item;
2422
+ while (i--) {
2423
+ item = this._list[i];
2424
+ window.console && console.log(item.name, 'in', item.object, '(', item.args, ')');
2425
+ }
2426
+ }
2427
+ }),
2428
+
2429
+ flush: function() {
2430
+ this.stack._list = [];
2431
+ },
2432
+
2433
+ print: function() {
2434
+ this.stack.backtrace();
2435
+ },
2436
+
2437
+ wrap: function(func, module, name) {
2438
+ var self = JS.StackTrace;
2439
+ var wrapper = function() {
2440
+ var result, fullName = self.nameOf(module) + '#' + name;
2441
+ self.stack.push(fullName, this, arguments);
2442
+
2443
+ if (self.logLevel === 'errors') {
2444
+ try { result = func.apply(this, arguments); }
2445
+ catch (e) {
2446
+ if (e.logged) throw e;
2447
+ e.logged = true;
2448
+ window.console && console.error(e, 'thrown by', self.stack.top().name + '. Backtrace:');
2449
+ self.print();
2450
+ self.flush();
2451
+ throw e;
2452
+ }
2453
+ } else {
2454
+ result = func.apply(this, arguments);
2455
+ }
2456
+
2457
+ self.stack.pop(result);
2458
+ return result;
2459
+ };
2460
+ wrapper.toString = function() { return func.toString() };
2461
+ return wrapper;
2462
+ }
2463
+ }
2464
+ });
2465
+
2466
+ (function() {
2467
+ var module = JS.StackTrace, key;
2468
+ for (key in module.root) {
2469
+ if (key !== 'JS') module.excluded.push(module.root[key]);
2470
+ }
2471
+ })();
2472
+
2473
+
2474
+ JS.Ruby = function(klass, define) {
2475
+ define.call(new JS.Ruby.ClassBuilder(klass));
2476
+ };
2477
+
2478
+ JS.extend(JS.Ruby, {
2479
+ extendDSL: function(builder, source) {
2480
+ for (var method in source) {
2481
+ if (builder[method] || !JS.isFn(source[method])) continue;
2482
+ this.addMethod(builder, source, method);
2483
+ }
2484
+ },
2485
+
2486
+ addMethod: function(builder, source, method) {
2487
+ builder[method] = function() {
2488
+ var result = source[method].apply(source, arguments);
2489
+ JS.Ruby.extendDSL(builder, source);
2490
+ return result;
2491
+ };
2492
+ },
2493
+
2494
+ alias: function(object, builder) {
2495
+ return function(newName, oldName) {
2496
+ var old = object[oldName];
2497
+ if (old !== undefined) this.def(newName, old);
2498
+ if (builder) JS.Ruby.extendDSL(builder, object);
2499
+ };
2500
+ },
2501
+
2502
+ ClassBuilder: function(klass) {
2503
+ this.def = klass.method('define');
2504
+ this.alias = JS.Ruby.alias(klass.prototype);
2505
+
2506
+ this.self = {
2507
+ def: JS.bind(function(name, method) {
2508
+ var def = {}; def[name] = method;
2509
+ klass.extend(def);
2510
+ JS.Ruby.extendDSL(this, klass);
2511
+ }, this),
2512
+ alias: JS.Ruby.alias(klass, this)
2513
+ };
2514
+
2515
+ JS.Ruby.extendDSL(this, klass);
2516
+ }
2517
+ });