├── .gitignore ├── src ├── widgets.coffee ├── vendor │ ├── LICENSE.txt │ └── moof.js └── calendar.coffee ├── doc └── calendar.png ├── test ├── assets │ ├── css │ │ └── index.styl │ └── js │ │ └── jquery.js ├── views │ ├── layout.jade │ └── index.jade └── server.coffee ├── package.json ├── README.md ├── Cakefile └── LICENSE-MIT.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | lib 4 | -------------------------------------------------------------------------------- /src/widgets.coffee: -------------------------------------------------------------------------------- 1 | 2 | window.Calendar = Calendar 3 | -------------------------------------------------------------------------------- /doc/calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loule/js-chart-widgets/HEAD/doc/calendar.png -------------------------------------------------------------------------------- /test/assets/css/index.styl: -------------------------------------------------------------------------------- 1 | 2 | body 3 | padding-top 80px 4 | 5 | h2 6 | font 26px Georgia 7 | 8 | -------------------------------------------------------------------------------- /test/views/layout.jade: -------------------------------------------------------------------------------- 1 | html 2 | head 3 | != js('jquery') 4 | script(type="text/javascript", src="/widgets.js") 5 | != css('index') 6 | body!= body 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"js-chart-widgets", 3 | "version":"0.0.0", 4 | "devDependencies": { 5 | "jade": "0.20.3", 6 | "stylus": "0.22.2", 7 | "express": "2.5.8", 8 | "coffeesurgeon": "0.0.3", 9 | "coffee-script": "1.1.0", 10 | "closure-compiler": "0.1.1", 11 | "moof": "0.0.12", 12 | "connect-assets": "2.1.8" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/views/index.jade: -------------------------------------------------------------------------------- 1 | 2 | script(type="text/javascript") 3 | $(function() { 4 | new Calendar({ 5 | append_to: 'calendar', 6 | num_weeks: 51, 7 | day_size: 11, 8 | data: [ 9 | ['2012-03-01', 123], 10 | ['2012-03-02', 456.7], 11 | ['2012-03-04', 234] 12 | ] 13 | }); 14 | }); 15 | 16 | center 17 | h2 Calendar 18 | #calendar 19 | 20 | -------------------------------------------------------------------------------- /test/server.coffee: -------------------------------------------------------------------------------- 1 | 2 | fs = require 'fs' 3 | express = require 'express' 4 | 5 | app = express.createServer express.logger() 6 | app.set 'views', "#{__dirname}/views" 7 | app.set 'view engine', 'jade' 8 | app.use app.router 9 | app.use express.errorHandler {dumpExceptions:true} 10 | app.use require('connect-assets') src:"#{__dirname}/assets" 11 | 12 | 13 | app.get '/widgets.js', (req, res, next) -> 14 | res.writeHead 200, {'Content-Type': 'text/javascript'} 15 | res.end fs.readFileSync "#{__dirname}/../lib/js-chart-widgets.min.js" 16 | 17 | 18 | app.get '/', (req, res, next) -> 19 | res.render 'index' 20 | 21 | app.listen process.env.PORT or 3000 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | npm install 3 | cake build 4 | 5 | #--> lib/js-chart-widgets.min.js 6 |7 | 8 | ## Calendar 9 | 10 | new Calendar({ 11 | append_to: 'some_id', 12 | num_weeks: 51, 13 | day_size: 11, 14 | data: [ 15 | ['2012-03-01', 123], 16 | ['2012-03-02', 456.7], 17 | // gaps are fine 18 | ['2012-03-04', 234] 19 | ], 20 | color: '#005500' 21 | }); 22 | 23 |  24 | 25 | ## The Means 26 | 27 | - Wrap or borrow from other open-source widgets when it makes sense 28 | - Get our NIH on when it doesn't 29 | 30 | ## The End 31 | 32 | - Make a sensible abstraction with nice defaults for each of the world's widget types 33 | 34 |  35 | -------------------------------------------------------------------------------- /Cakefile: -------------------------------------------------------------------------------- 1 | fs = require 'fs' 2 | {exec} = require 'child_process' 3 | closure_compiler = require 'closure-compiler' 4 | coffee_script = require 'coffee-script' 5 | 6 | 7 | read = (path) -> 8 | fs.readFileSync("#{__dirname}/#{path}").toString() 9 | 10 | 11 | task 'build', () -> 12 | exec 'mkdir -p lib', (e, out, err) -> 13 | js = [ 14 | read "src/vendor/moof.js" 15 | coffee_script.compile read("src/calendar.coffee"), bare:true 16 | coffee_script.compile read("src/widgets.coffee"), bare:true 17 | ].join "\n\n" 18 | js = "(function(){\n#{js}\n})();" 19 | opt = {compilation_level: 'SIMPLE_OPTIMIZATIONS'} 20 | closure_compiler.compile js, opt, (e, js) -> 21 | throw e if e 22 | fs.writeFileSync "#{__dirname}/lib/js-chart-widgets.min.js", js 23 | 24 | 25 | task 'test', () -> 26 | throw new Error "TODO" 27 | -------------------------------------------------------------------------------- /LICENSE-MIT.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012+ js-chart-widgets contributors 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/vendor/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2011+ moof contributors 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /src/calendar.coffee: -------------------------------------------------------------------------------- 1 | 2 | make_colorizer = (c1, c2, v1, v2) -> 3 | (v) -> 4 | interpolateColors c1, c2, (if v1 == v2 then 0.5 else ((v - v1) / (v2 - v1))) 5 | 6 | 7 | rjust_2_0 = (s) -> 8 | if s.length == 1 9 | "0#{s}" 10 | else 11 | s 12 | 13 | strftime_Ymd = (date) -> 14 | Y = 1900 + date.getYear() 15 | m = rjust_2_0("" + (date.getMonth() + 1)) 16 | d = rjust_2_0("" + date.getDate()) 17 | "#{Y}-#{m}-#{d}" 18 | 19 | 20 | class Calendar extends Element 21 | constructor: ({color, data, day_size, num_weeks, append_to}) -> 22 | super 'div', 'Calendar' 23 | if append_to 24 | document.getElementById(append_to).appendChild @_ 25 | max_value = 0 26 | for [k, v] in data 27 | if v > max_value 28 | max_value = v 29 | colorizer = make_colorizer '#FFFFFF', color, 0, max_value 30 | w = (day_size * num_weeks) + (1 * (num_weeks + 1)) 31 | h = (day_size * 7) + (1 * (7 + 1)) 32 | dayHolder = D() 33 | dayHolder.setStyles { 34 | width: w + 'px' 35 | height: h + 'px' 36 | position: 'relative' 37 | background: '#999999' 38 | } 39 | @appendChild dayHolder 40 | 41 | datestr_coord_map = {} 42 | MS_IN_DAY = 1000 * 3600 * 24 43 | t = new Date() 44 | day = t.getDay() # [Sun..Sat] <-> [0..6] 45 | day = (7 + day - 1) % 7 # [Mon..Sun] <-> [0..6] 46 | days_until_next_sunday = 6 - day 47 | t = new Date(t.getTime() + (MS_IN_DAY * days_until_next_sunday)) 48 | for x in [(num_weeks - 1)..0] 49 | for y in [(7 - 1)..0] 50 | datestr_coord_map[strftime_Ymd(t)] = "#{x}:#{y}" 51 | t = new Date(t.getTime() - MS_IN_DAY) 52 | 53 | days = {} 54 | for x in [0...num_weeks] 55 | for y in [0...7] 56 | day = D() 57 | day.setStyles { 58 | width: day_size + 'px' 59 | height: day_size + 'px' 60 | background: '#FFFFFF' 61 | position: 'absolute' 62 | left: (1 + (day_size + 1) * x) + 'px' 63 | top: (1 + (day_size + 1) * y) + 'px' 64 | zIndex: 2 65 | } 66 | days["#{x}:#{y}"] = day 67 | dayHolder.appendChild day 68 | for [datestr, v] in data 69 | coord = datestr_coord_map[datestr] 70 | if coord 71 | days[coord].setStyles background: colorizer(v) 72 | 73 | -------------------------------------------------------------------------------- /src/vendor/moof.js: -------------------------------------------------------------------------------- 1 | 2 | /* /node_modules/moof/src/geom.coffee 3 | */ 4 | 5 | var ALPHABET58, BASE64_ALPHABET, BUTTON_STYLUS, Button, D, E, Element, Event, KEYCODE_0, KEYCODE_1, KEYCODE_2, KEYCODE_3, KEYCODE_4, KEYCODE_5, KEYCODE_6, KEYCODE_7, KEYCODE_8, KEYCODE_9, KEYCODE_A, KEYCODE_B, KEYCODE_C, KEYCODE_D, KEYCODE_DELETE, KEYCODE_DOWN, KEYCODE_E, KEYCODE_ESCAPE, KEYCODE_F, KEYCODE_G, KEYCODE_H, KEYCODE_I, KEYCODE_J, KEYCODE_K, KEYCODE_KEYPAD_0, KEYCODE_KEYPAD_1, KEYCODE_KEYPAD_2, KEYCODE_KEYPAD_3, KEYCODE_KEYPAD_4, KEYCODE_KEYPAD_5, KEYCODE_KEYPAD_6, KEYCODE_KEYPAD_7, KEYCODE_KEYPAD_8, KEYCODE_KEYPAD_9, KEYCODE_L, KEYCODE_LEFT, KEYCODE_M, KEYCODE_N, KEYCODE_O, KEYCODE_P, KEYCODE_Q, KEYCODE_R, KEYCODE_RETURN, KEYCODE_RIGHT, KEYCODE_S, KEYCODE_SPACE, KEYCODE_T, KEYCODE_TAB, KEYCODE_U, KEYCODE_UP, KEYCODE_V, KEYCODE_W, KEYCODE_X, KEYCODE_Y, KEYCODE_Z, Morph, Point, Rect, Tween, addCss, b64decode, b64encode, bodyOn, decimal_gt, distanceBetweenPoints, endswith, interpolateColors, interpolatePoints, interpolateRects, intervalSet, invertedDict, json_decode_via_eval, json_encode, keysOf, linear, lstrip, matrix_centerOfGravity, matrix_create, matrix_rotated, max, min, mixInEventEmitter, moof_color_hex2, random, randomInteger, randomToken, re_escape, rgbFromWeb, rjust, rstrip, startswith, strip, timeoutSet, valuesOf, webFromRgb; 6 | var __slice = Array.prototype.slice, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }; 7 | 8 | Point = (function() { 9 | 10 | function Point(x, y) { 11 | this.x = x; 12 | this.y = y; 13 | } 14 | 15 | return Point; 16 | 17 | })(); 18 | 19 | Rect = (function() { 20 | 21 | function Rect(x, y, w, h) { 22 | this.x = x; 23 | this.y = y; 24 | this.w = w; 25 | this.h = h; 26 | } 27 | 28 | Rect.prototype.translated = function(r) { 29 | return new Rect(this.x + r.x, this.y + r.y, this.w, this.h); 30 | }; 31 | 32 | Rect.prototype.scaled = function(scaledBy) { 33 | return new Rect(this.x, this.y, this.w * scaledBy, this.h * scaledBy); 34 | }; 35 | 36 | Rect.prototype.center = function() { 37 | return new Point(this.x + (this.w / 2), this.y + (this.h / 2)); 38 | }; 39 | 40 | Rect.prototype.centeredAt = function(r) { 41 | return new Rect(r.x - (this.w / 2), r.y - (this.h / 2), this.w, this.h); 42 | }; 43 | 44 | Rect.prototype.centeredIn = function(r) { 45 | return this.centeredAt(r.center()); 46 | }; 47 | 48 | return Rect; 49 | 50 | })(); 51 | 52 | interpolateRects = function(r1, r2, t) { 53 | return new Rect(r1.x + (r2.x - r1.x) * t, r1.y + (r2.y - r1.y) * t, r1.w + (r2.w - r1.w) * t, r1.h + (r2.h - r1.h) * t); 54 | }; 55 | 56 | interpolatePoints = function(r1, r2, t) { 57 | return new Point(r1.x + (r2.x - r1.x) * t, r1.y + (r2.y - r1.y) * t); 58 | }; 59 | 60 | distanceBetweenPoints = function(p, p2) { 61 | var dx, dy; 62 | dx = p.x - p2.x; 63 | dy = p.y - p2.y; 64 | return Math.sqrt((dx * dx) + (dy * dy)); 65 | }; 66 | 67 | /* /node_modules/moof/src/event.coffee 68 | */ 69 | 70 | KEYCODE_DELETE = 8; 71 | 72 | KEYCODE_TAB = 9; 73 | 74 | KEYCODE_RETURN = 13; 75 | 76 | KEYCODE_ESCAPE = 27; 77 | 78 | KEYCODE_SPACE = 32; 79 | 80 | KEYCODE_LEFT = 37; 81 | 82 | KEYCODE_UP = 38; 83 | 84 | KEYCODE_RIGHT = 39; 85 | 86 | KEYCODE_DOWN = 40; 87 | 88 | KEYCODE_0 = 48; 89 | 90 | KEYCODE_1 = 49; 91 | 92 | KEYCODE_2 = 50; 93 | 94 | KEYCODE_3 = 51; 95 | 96 | KEYCODE_4 = 52; 97 | 98 | KEYCODE_5 = 53; 99 | 100 | KEYCODE_6 = 54; 101 | 102 | KEYCODE_7 = 55; 103 | 104 | KEYCODE_8 = 56; 105 | 106 | KEYCODE_9 = 57; 107 | 108 | KEYCODE_KEYPAD_0 = 96; 109 | 110 | KEYCODE_KEYPAD_1 = 97; 111 | 112 | KEYCODE_KEYPAD_2 = 98; 113 | 114 | KEYCODE_KEYPAD_3 = 99; 115 | 116 | KEYCODE_KEYPAD_4 = 100; 117 | 118 | KEYCODE_KEYPAD_5 = 101; 119 | 120 | KEYCODE_KEYPAD_6 = 102; 121 | 122 | KEYCODE_KEYPAD_7 = 103; 123 | 124 | KEYCODE_KEYPAD_8 = 104; 125 | 126 | KEYCODE_KEYPAD_9 = 105; 127 | 128 | KEYCODE_A = 65; 129 | 130 | KEYCODE_B = 66; 131 | 132 | KEYCODE_C = 67; 133 | 134 | KEYCODE_D = 68; 135 | 136 | KEYCODE_E = 69; 137 | 138 | KEYCODE_F = 70; 139 | 140 | KEYCODE_G = 71; 141 | 142 | KEYCODE_H = 72; 143 | 144 | KEYCODE_I = 73; 145 | 146 | KEYCODE_J = 74; 147 | 148 | KEYCODE_K = 75; 149 | 150 | KEYCODE_L = 76; 151 | 152 | KEYCODE_M = 77; 153 | 154 | KEYCODE_N = 78; 155 | 156 | KEYCODE_O = 79; 157 | 158 | KEYCODE_P = 80; 159 | 160 | KEYCODE_Q = 81; 161 | 162 | KEYCODE_R = 82; 163 | 164 | KEYCODE_S = 83; 165 | 166 | KEYCODE_T = 84; 167 | 168 | KEYCODE_U = 85; 169 | 170 | KEYCODE_V = 86; 171 | 172 | KEYCODE_W = 87; 173 | 174 | KEYCODE_X = 88; 175 | 176 | KEYCODE_Y = 89; 177 | 178 | KEYCODE_Z = 90; 179 | 180 | Event = (function() { 181 | 182 | function Event(e) { 183 | this.e = e; 184 | } 185 | 186 | Event.prototype.getKeycode = function() { 187 | return this.e.charCode || this.e.keyCode; 188 | }; 189 | 190 | Event.prototype.isRightButton = function() { 191 | if (this.e.which) { 192 | return this.e.which === 3; 193 | } else if (e.button) { 194 | return this.e.button === 2; 195 | } 196 | }; 197 | 198 | Event.prototype.getPos = function() { 199 | if (this.e.pageX || this.e.pageY) { 200 | return new Point(this.e.pageX, this.e.pageY); 201 | } else if (this.e.clientX || this.e.clientY) { 202 | return new Point(this.e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft, this.e.clientY + document.body.scrollTop + document.documentElement.scrollTop); 203 | } 204 | }; 205 | 206 | Event.prototype.controlDown = function() { 207 | return this.e.ctrlKey; 208 | }; 209 | 210 | Event.prototype.altDown = function() { 211 | return this.e.altKey; 212 | }; 213 | 214 | Event.prototype.shiftDown = function() { 215 | return this.e.shiftKey; 216 | }; 217 | 218 | Event.prototype.metaDown = function() { 219 | return this.e.metaKey; 220 | }; 221 | 222 | Event.prototype.stop = function() { 223 | if (this.e.stopPropagation) { 224 | this.e.stopPropagation(); 225 | } else { 226 | this.e.cancelBubble = true; 227 | } 228 | if (this.e.preventDefault) { 229 | return this.e.preventDefault(); 230 | } else { 231 | return this.e.returnValue = false; 232 | } 233 | }; 234 | 235 | return Event; 236 | 237 | })(); 238 | 239 | /* /node_modules/moof/src/page.coffee 240 | */ 241 | 242 | bodyOn = function(k, f) { 243 | return document.body['on' + k] = function(e) { 244 | return f(new Event(e)); 245 | }; 246 | }; 247 | 248 | /* /node_modules/moof/src/element.coffee 249 | */ 250 | 251 | Element = (function() { 252 | 253 | function Element() { 254 | var arg, args, k, kid, node, nodeType, _i, _j, _len, _len2; 255 | nodeType = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; 256 | this._ = node = document.createElement(nodeType); 257 | for (_i = 0, _len = args.length; _i < _len; _i++) { 258 | arg = args[_i]; 259 | if ((typeof arg) === 'string') { 260 | node.className = arg; 261 | } else if (arg instanceof Array) { 262 | for (_j = 0, _len2 = arg.length; _j < _len2; _j++) { 263 | kid = arg[_j]; 264 | if ((typeof kid) === 'string') { 265 | node.appendChild(document.createTextNode(kid)); 266 | } else { 267 | node.appendChild(kid._); 268 | } 269 | } 270 | } else { 271 | for (k in arg) { 272 | if (!__hasProp.call(arg, k)) continue; 273 | node[k] = "" + arg[k]; 274 | } 275 | } 276 | } 277 | } 278 | 279 | Element.prototype.appendChildren = function(arr) { 280 | var x, _i, _len, _results; 281 | _results = []; 282 | for (_i = 0, _len = arr.length; _i < _len; _i++) { 283 | x = arr[_i]; 284 | _results.push(this.appendChild(x)); 285 | } 286 | return _results; 287 | }; 288 | 289 | Element.prototype.appendChild = function(x) { 290 | return this._.appendChild(x._); 291 | }; 292 | 293 | Element.prototype.removeChildren = function() { 294 | var x, _results; 295 | x = this._.lastChild; 296 | _results = []; 297 | while (x) { 298 | this._.removeChild(x); 299 | _results.push(x = this._.lastChild); 300 | } 301 | return _results; 302 | }; 303 | 304 | Element.prototype.setChildren = function(arr) { 305 | var x, _i, _len, _results; 306 | this.removeChildren(); 307 | _results = []; 308 | for (_i = 0, _len = arr.length; _i < _len; _i++) { 309 | x = arr[_i]; 310 | _results.push(this.appendChild(x)); 311 | } 312 | return _results; 313 | }; 314 | 315 | Element.prototype.setChild = function(x) { 316 | return this.setChildren([x]); 317 | }; 318 | 319 | Element.prototype.prependChild = function(x) { 320 | if (this._.childNodes.length === 0) { 321 | this._.appendChild(x._); 322 | } else { 323 | 324 | } 325 | return this._.insertBefore(x._, this._.firstChild); 326 | }; 327 | 328 | Element.prototype.insertBefore = function(kid, existingKid) { 329 | return this._.insertBefore(kid._, existingKid._); 330 | }; 331 | 332 | Element.prototype.appendToBody = function() { 333 | return document.body.appendChild(this._); 334 | }; 335 | 336 | Element.prototype.appendToHead = function() { 337 | return document.getElementsByTagName("head")[0].appendChild(this._); 338 | }; 339 | 340 | Element.prototype.appendTo = function(x) { 341 | return x._.appendChild(this._); 342 | }; 343 | 344 | Element.prototype.prependTo = function(x) { 345 | return x.prependChild(this); 346 | }; 347 | 348 | Element.prototype.remove = function() { 349 | var _ref; 350 | return (_ref = this._.parentNode) != null ? _ref.removeChild(this._) : void 0; 351 | }; 352 | 353 | Element.prototype.setTextChild = function(text) { 354 | this.removeChildren(); 355 | return this._.appendChild(document.createTextNode(text)); 356 | }; 357 | 358 | Element.prototype.setOpacity = function(fraction) { 359 | var percent; 360 | percent = Math.round(100 * fraction); 361 | return this.setStyles({ 362 | opacity: fraction, 363 | filter: "alpha(opacity=" + percent + ")", 364 | '-ms-filter': "progid:DXImageTransform.Microsoft.Alpha(opacity=" + percent + ")" 365 | }); 366 | }; 367 | 368 | Element.prototype.setStyles = function(d) { 369 | var k, v, _results; 370 | _results = []; 371 | for (k in d) { 372 | if (!__hasProp.call(d, k)) continue; 373 | v = d[k]; 374 | _results.push(this._.style[k] = v); 375 | } 376 | return _results; 377 | }; 378 | 379 | Element.prototype.setPos = function(r) { 380 | return this.setStyles({ 381 | left: Math.round(r.x), 382 | top: Math.round(r.y) 383 | }); 384 | }; 385 | 386 | Element.prototype.setRect = function(r) { 387 | return this.setStyles({ 388 | left: Math.round(r.x) + 'px', 389 | top: Math.round(r.y) + 'px', 390 | width: Math.round(r.w) + 'px', 391 | height: Math.round(r.h) + 'px' 392 | }); 393 | }; 394 | 395 | Element.prototype.on = function(k, f) { 396 | return this._['on' + k] = function(event) { 397 | return f(new Event(event)); 398 | }; 399 | }; 400 | 401 | Element.prototype.setClasses = function(classes) { 402 | return this._.className = classes.join(' '); 403 | }; 404 | 405 | Element.prototype.getClasses = function() { 406 | if (this._.className) { 407 | return this._.className.split(' '); 408 | } else { 409 | return []; 410 | } 411 | }; 412 | 413 | Element.prototype.addClass = function(className) { 414 | var arr; 415 | arr = this.getClasses(); 416 | if (arr.indexOf(className) === -1) { 417 | arr.push(className); 418 | return this.setClasses(arr); 419 | } 420 | }; 421 | 422 | Element.prototype.removeClass = function(className) { 423 | var arr, i; 424 | arr = this.getClasses(); 425 | i = arr.indexOf(className); 426 | if (i !== -1) { 427 | arr.splice(i, 1); 428 | return this.setClasses(arr); 429 | } 430 | }; 431 | 432 | Element.prototype.getValue = function() { 433 | return this._.value; 434 | }; 435 | 436 | Element.prototype.setValue = function(x) { 437 | return this._.value = x; 438 | }; 439 | 440 | Element.prototype.scrollToBottom = function() { 441 | return this._.scrollTop = this._.scrollHeight - this._.clientHeight; 442 | }; 443 | 444 | return Element; 445 | 446 | })(); 447 | 448 | E = function() { 449 | var args; 450 | args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 451 | return (function(func, args, ctor) { 452 | ctor.prototype = func.prototype; 453 | var child = new ctor, result = func.apply(child, args); 454 | return typeof result === "object" ? result : child; 455 | })(Element, args, function() {}); 456 | }; 457 | 458 | D = function() { 459 | var args; 460 | args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 461 | return (function(func, args, ctor) { 462 | ctor.prototype = func.prototype; 463 | var child = new ctor, result = func.apply(child, args); 464 | return typeof result === "object" ? result : child; 465 | })(Element, ['div'].concat(__slice.call(args)), function() {}); 466 | }; 467 | 468 | /* /node_modules/moof/src/widgets.coffee 469 | */ 470 | 471 | BUTTON_STYLUS = "\n.Button\n display block\n cursor pointer\n text-align center\n color white\n position relative\n\n.Button *\n cursor pointer\n\n.Button table\n border-spacing 0\n width 100%\n height 100%\n\n.Button .Boverlay\n z-index 50\n abs(0, 0)\n dim(100%, 100%)\n text-align center\n\n.Button .BL\n padding 0\n\n.Button .BR\n padding 0\n"; 472 | 473 | Button = (function() { 474 | 475 | __extends(Button, Element); 476 | 477 | function Button() { 478 | var args, classes, opt, t, text, type, x, _i, _len; 479 | var _this = this; 480 | x = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; 481 | if (typeof x === 'string') { 482 | type = 'whole'; 483 | classes = "Button " + x; 484 | } else if (x.lmr) { 485 | type = 'lmr'; 486 | classes = "Button " + x.lmr; 487 | } 488 | Button.__super__.constructor.call(this, 'a', classes, [this.overlay = E('div', 'Boverlay')]); 489 | if (type === 'lmr') { 490 | this.appendChildren([E('table', [E('tr', [E('td', "BLR BL"), E('td', "BM", [' ']), E('td', "BLR BR")])])]); 491 | } 492 | this.on('click', (function(e) { 493 | return _this.click(e); 494 | })); 495 | text = null; 496 | opt = {}; 497 | for (_i = 0, _len = args.length; _i < _len; _i++) { 498 | x = args[_i]; 499 | t = typeof x; 500 | if (t === 'string') { 501 | text = x; 502 | } else if (t === 'function') { 503 | this.onclick = x; 504 | } else { 505 | _.extend(opt, x); 506 | } 507 | } 508 | if (opt.id) this._.id = opt.id; 509 | if (text) this.overlay.appendChild(this.label = D('Blabel', [text])); 510 | } 511 | 512 | Button.prototype.setText = function(text) { 513 | return this.label.setTextChild(text); 514 | }; 515 | 516 | Button.prototype.click = function(e) { 517 | if (e) e.stop(); 518 | if (this.onclick) return this.onclick(e); 519 | }; 520 | 521 | Button.prototype.showLoader = function(className) {}; 522 | 523 | Button.prototype.hideLoader = function() {}; 524 | 525 | return Button; 526 | 527 | })(); 528 | 529 | /* /node_modules/moof/src/color.coffee 530 | */ 531 | 532 | moof_color_hex2 = function(n) { 533 | if (n < 16) { 534 | return "0" + n.toString(16); 535 | } else { 536 | return n.toString(16); 537 | } 538 | }; 539 | 540 | rgbFromWeb = function(web) { 541 | return [parseInt(web.substr(1, 2), 16), parseInt(web.substr(3, 2), 16), parseInt(web.substr(5, 2), 16)]; 542 | }; 543 | 544 | webFromRgb = function(r, g, b) { 545 | return "#" + moof_color_hex2(r) + moof_color_hex2(g) + moof_color_hex2(b); 546 | }; 547 | 548 | interpolateColors = function(c1, c2, t) { 549 | var b1, b2, g1, g2, r1, r2, _ref, _ref2; 550 | _ref = rgbFromWeb(c1), r1 = _ref[0], g1 = _ref[1], b1 = _ref[2]; 551 | _ref2 = rgbFromWeb(c2), r2 = _ref2[0], g2 = _ref2[1], b2 = _ref2[2]; 552 | return webFromRgb(Math.round(r1 + (r2 - r1) * t), Math.round(g1 + (g2 - g1) * t), Math.round(b1 + (b2 - b1) * t)); 553 | }; 554 | 555 | /* /node_modules/moof/src/animation.coffee 556 | */ 557 | 558 | Tween = (function() { 559 | 560 | function Tween(duration, transition, f) { 561 | var _this = this; 562 | this.duration = duration; 563 | this.transition = transition; 564 | this.f = f; 565 | this.start = new Date().getTime(); 566 | this.f(0); 567 | setTimeout((function() { 568 | return _this.step(); 569 | }), 0); 570 | } 571 | 572 | Tween.prototype.step = function() { 573 | var t; 574 | var _this = this; 575 | t = (new Date().getTime() - this.start) / this.duration; 576 | if (t > 1) t = 1; 577 | this.f(this.transition(t)); 578 | if (t < 1) { 579 | return setTimeout((function() { 580 | return _this.step(); 581 | }), 0); 582 | } 583 | }; 584 | 585 | return Tween; 586 | 587 | })(); 588 | 589 | Morph = (function() { 590 | 591 | function Morph(elements, info) { 592 | var background, duration, numFrames, oncomplete, opacity, pos, rect, transition; 593 | duration = info.duration, transition = info.transition, oncomplete = info.oncomplete, opacity = info.opacity, rect = info.rect, pos = info.pos, background = info.background; 594 | if (!(elements instanceof Array)) elements = [elements]; 595 | numFrames = 0; 596 | new Tween(duration, transition, function(t) { 597 | var element, _i, _len; 598 | numFrames++; 599 | for (_i = 0, _len = elements.length; _i < _len; _i++) { 600 | element = elements[_i]; 601 | if (opacity) { 602 | element.setOpacity(opacity[0] + (opacity[1] - opacity[0]) * t); 603 | } 604 | if (rect) element.setRect(interpolateRects(rect[0], rect[1], t)); 605 | if (pos) element.setPos(interpolatePoints(pos[0], pos[1], t)); 606 | if (background) { 607 | element._.style.background = interpolateColors(background[0], background[1], t); 608 | } 609 | } 610 | if (t === 1 && oncomplete) { 611 | return oncomplete({ 612 | numFrames: numFrames, 613 | info: info 614 | }); 615 | } 616 | }); 617 | } 618 | 619 | return Morph; 620 | 621 | })(); 622 | 623 | linear = function(t) { 624 | return t; 625 | }; 626 | 627 | /* /node_modules/moof/src/base64.coffee 628 | */ 629 | 630 | BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; 631 | 632 | b64encode = function(octets) { 633 | var combined, i, numOctets, paddingLength, s, strings; 634 | strings = []; 635 | numOctets = octets.length; 636 | i = 0; 637 | while (i < numOctets) { 638 | combined = ((octets[i] || 0) << 16) | ((octets[i + 1] || 0) << 8) | (octets[i + 2] || 0); 639 | i += 3; 640 | strings.push(BASE64_ALPHABET.charAt((combined >> 18) & 0x3F) + BASE64_ALPHABET.charAt((combined >> 12) & 0x3F) + BASE64_ALPHABET.charAt((combined >> 6) & 0x3F) + BASE64_ALPHABET.charAt(combined & 0x3F)); 641 | } 642 | paddingLength = [0, 2, 1][numOctets % 3]; 643 | s = strings.join(''); 644 | return s.substr(0, s.length - paddingLength) + ['', '=', '=='][paddingLength]; 645 | }; 646 | 647 | b64decode = function(s) { 648 | var combined, i, numChars, octets; 649 | octets = []; 650 | numChars = s.length - (s.match(/[=]+/) || [''])[0].length; 651 | i = 0; 652 | while (i < numChars) { 653 | combined = ((BASE64_ALPHABET.indexOf(s[i]) % 64) << 18) | ((BASE64_ALPHABET.indexOf(s[i + 1]) % 64) << 12) | ((BASE64_ALPHABET.indexOf(s[i + 2]) % 64) << 6) | (BASE64_ALPHABET.indexOf(s[i + 3]) % 64); 654 | i += 4; 655 | octets.push((combined >> 16) & 0xFF); 656 | if ((i - 1) <= numChars) { 657 | octets.push((combined >> 8) & 0xFF); 658 | if ((i - 1) < numChars) octets.push(combined & 0xFF); 659 | } 660 | } 661 | return octets; 662 | }; 663 | 664 | /* /node_modules/moof/src/decimal.coffee 665 | */ 666 | 667 | decimal_gt = function(x, y) { 668 | return (1 * x) > (1 * y); 669 | }; 670 | 671 | /* /node_modules/moof/src/dom.coffee 672 | */ 673 | 674 | addCss = function(css) { 675 | var node; 676 | node = document.createElement('style'); 677 | node.type = 'text/css'; 678 | node.appendChild(document.createTextNode(css)); 679 | return document.head.appendChild(node); 680 | }; 681 | 682 | /* /node_modules/moof/src/eventemitter.coffee 683 | */ 684 | 685 | mixInEventEmitter = function(x) { 686 | x.EventEmitter_listeners = {}; 687 | x.emit = function() { 688 | var args, arr, f, k, _i, _len, _results; 689 | k = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; 690 | arr = this.EventEmitter_listeners[k] = this.EventEmitter_listeners[k] || []; 691 | _results = []; 692 | for (_i = 0, _len = arr.length; _i < _len; _i++) { 693 | f = arr[_i]; 694 | _results.push(f.apply(null, args)); 695 | } 696 | return _results; 697 | }; 698 | x.on = function(k, f) { 699 | var arr; 700 | arr = this.EventEmitter_listeners[k] = this.EventEmitter_listeners[k] || []; 701 | return arr.push(f); 702 | }; 703 | return x.listeners = function(k) { 704 | if (!this.EventEmitter_listeners[k]) this.EventEmitter_listeners[k] = []; 705 | return this.EventEmitter_listeners[k]; 706 | }; 707 | }; 708 | 709 | /* /node_modules/moof/src/json.coffee 710 | */ 711 | 712 | json_encode = function(x) { 713 | var arr, k, t, v, y, _i, _len; 714 | t = typeof x; 715 | if (x === null || t === 'undefined') { 716 | return 'null'; 717 | } else if (t === 'boolean' || t === 'number') { 718 | return x.valueOf(); 719 | } else if (t === 'string') { 720 | return '"' + (x.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/, '\\n')) + '"'; 721 | } else if (x instanceof Array) { 722 | arr = []; 723 | for (_i = 0, _len = x.length; _i < _len; _i++) { 724 | y = x[_i]; 725 | arr.push(json_encode(y)); 726 | } 727 | return "[" + arr.join(',') + "]"; 728 | } else { 729 | arr = []; 730 | for (k in x) { 731 | if (!__hasProp.call(x, k)) continue; 732 | v = x[k]; 733 | arr.push(json_encode(k) + ":" + json_encode(v)); 734 | } 735 | return "{" + arr.join(',') + "}"; 736 | } 737 | }; 738 | 739 | json_decode_via_eval = function(s) { 740 | return eval("(" + s + ")"); 741 | }; 742 | 743 | /* /node_modules/moof/src/util.coffee 744 | */ 745 | 746 | timeoutSet = function(ms, f) { 747 | return setTimeout(f, ms); 748 | }; 749 | 750 | intervalSet = function(ms, f) { 751 | return setInterval(f, ms); 752 | }; 753 | 754 | min = function(x, y) { 755 | if (x < y) { 756 | return x; 757 | } else { 758 | return y; 759 | } 760 | }; 761 | 762 | max = function(x, y) { 763 | if (x > y) { 764 | return x; 765 | } else { 766 | return y; 767 | } 768 | }; 769 | 770 | keysOf = function(d) { 771 | var k, _results; 772 | _results = []; 773 | for (k in d) { 774 | if (!__hasProp.call(d, k)) continue; 775 | _results.push(k); 776 | } 777 | return _results; 778 | }; 779 | 780 | valuesOf = function(d) { 781 | var k, v, _results; 782 | _results = []; 783 | for (k in d) { 784 | if (!__hasProp.call(d, k)) continue; 785 | v = d[k]; 786 | _results.push(v); 787 | } 788 | return _results; 789 | }; 790 | 791 | invertedDict = function(d) { 792 | var d2, k, v; 793 | d2 = {}; 794 | for (k in d) { 795 | if (!__hasProp.call(d, k)) continue; 796 | v = d[k]; 797 | d2[v] = k; 798 | } 799 | return d2; 800 | }; 801 | 802 | startswith = function(s, s2) { 803 | return (s.length >= s2.length) && (s.substr(0, s2.length) === s2); 804 | }; 805 | 806 | endswith = function(s, s2) { 807 | return (s.length >= s2.length) && (s.substr(s.length - s2.length) === s2); 808 | }; 809 | 810 | rstrip = function(s, chars) { 811 | var m; 812 | if (chars == null) chars = "\t\n\v\f\r "; 813 | m = s.match(new RegExp("[" + (re_escape(chars)) + "]+$")); 814 | if (m) { 815 | return s.substr(0, s.length - m[0].length); 816 | } else { 817 | return s; 818 | } 819 | }; 820 | 821 | lstrip = function(s, chars) { 822 | var m; 823 | if (chars == null) chars = "\t\n\v\f\r "; 824 | m = s.match(new RegExp("^[" + (re_escape(chars)) + "]+")); 825 | if (m) { 826 | return s.substr(m[0].length); 827 | } else { 828 | return s; 829 | } 830 | }; 831 | 832 | strip = function(s, chars) { 833 | if (chars == null) chars = "\t\n\v\f\r "; 834 | return lstrip(rstrip(s, chars), chars); 835 | }; 836 | 837 | rjust = function(s, width, fillchar) { 838 | var arr, i, n; 839 | if (fillchar == null) fillchar = ' '; 840 | n = width - s.length; 841 | if (n <= 0) { 842 | return s; 843 | } else { 844 | arr = []; 845 | for (i = 0; 0 <= n ? i < n : i > n; 0 <= n ? i++ : i--) { 846 | arr.push(fillchar); 847 | } 848 | arr.push(s); 849 | return arr.join(''); 850 | } 851 | }; 852 | 853 | re_escape = function(s) { 854 | return s.replace(/[-\[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 855 | }; 856 | 857 | ALPHABET58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; 858 | 859 | random = function() { 860 | var x; 861 | x = Math.random(); 862 | if (x === 1) { 863 | return 0; 864 | } else { 865 | return x; 866 | } 867 | }; 868 | 869 | randomInteger = function(a, b) { 870 | return Math.floor(random() * (b - a + 1)) + a; 871 | }; 872 | 873 | randomToken = function(n, alphabet) { 874 | var i, lte; 875 | if (n == null) n = 8; 876 | if (alphabet == null) alphabet = ALPHABET58; 877 | lte = alphabet.length - 1; 878 | return ((function() { 879 | var _results; 880 | _results = []; 881 | for (i = 0; 0 <= n ? i < n : i > n; 0 <= n ? i++ : i--) { 882 | _results.push(alphabet.charAt(randomInteger(0, lte))); 883 | } 884 | return _results; 885 | })()).join(''); 886 | }; 887 | 888 | /* /node_modules/moof/src/matrix.coffee 889 | */ 890 | 891 | matrix_create = function(w, h, v) { 892 | var m, row, vIsAFunction, x, y; 893 | if (v == null) v = 0; 894 | vIsAFunction = (typeof v) === 'function'; 895 | m = []; 896 | for (y = 0; 0 <= h ? y < h : y > h; 0 <= h ? y++ : y--) { 897 | row = []; 898 | for (x = 0; 0 <= w ? x < w : x > w; 0 <= w ? x++ : x--) { 899 | if (vIsAFunction) { 900 | row.push(v(x, y)); 901 | } else { 902 | row.push(v); 903 | } 904 | } 905 | m.push(row); 906 | } 907 | return m; 908 | }; 909 | 910 | matrix_rotated = function(m, rotation90s) { 911 | var m2, n, n_minus_one, x, y; 912 | rotation90s %= 4; 913 | n = m.length; 914 | n_minus_one = n - 1; 915 | m2 = matrix_create(n, n); 916 | for (y = 0; 0 <= n ? y < n : y > n; 0 <= n ? y++ : y--) { 917 | for (x = 0; 0 <= n ? x < n : x > n; 0 <= n ? x++ : x--) { 918 | if (rotation90s === 0) { 919 | m2[y][x] = m[y][x]; 920 | } else if (rotation90s === 1) { 921 | m2[y][x] = m[n_minus_one - x][y]; 922 | } else if (rotation90s === 2) { 923 | m2[y][x] = m[n_minus_one - y][n_minus_one - x]; 924 | } else if (rotation90s === 3) { 925 | m2[y][x] = m[x][n_minus_one - y]; 926 | } 927 | } 928 | } 929 | return m2; 930 | }; 931 | 932 | matrix_centerOfGravity = function(m) { 933 | var h, totalWeight, w, weight, x, xsum, y, ysum; 934 | h = m.length; 935 | w = m[0].length; 936 | totalWeight = 0; 937 | xsum = 0; 938 | ysum = 0; 939 | for (y = 0; 0 <= h ? y < h : y > h; 0 <= h ? y++ : y--) { 940 | for (x = 0; 0 <= w ? x < w : x > w; 0 <= w ? x++ : x--) { 941 | weight = m[y][x]; 942 | totalWeight += weight; 943 | xsum += weight * (x + 0.5); 944 | ysum += weight * (y + 0.5); 945 | } 946 | } 947 | return [xsum / totalWeight, ysum / totalWeight]; 948 | }; 949 | 950 | /* /node_modules/moof/src/moof_bodystitch_main.coffee 951 | */ 952 | -------------------------------------------------------------------------------- /test/assets/js/jquery.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery JavaScript Library v1.6.2 3 | * http://jquery.com/ 4 | * 5 | * Copyright 2011, John Resig 6 | * Dual licensed under the MIT or GPL Version 2 licenses. 7 | * http://jquery.org/license 8 | * 9 | * Includes Sizzle.js 10 | * http://sizzlejs.com/ 11 | * Copyright 2011, The Dojo Foundation 12 | * Released under the MIT, BSD, and GPL Licenses. 13 | * 14 | * Date: Thu Jun 30 14:16:56 2011 -0400 15 | */ 16 | (function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i
| t |