Final small fixes…
[raphael] / raphael.js
1 // ┌─────────────────────────────────────────────────────────────────────┐ \\
2 // │ Raphaël 2.0 - JavaScript Vector Library                             │ \\
3 // ├─────────────────────────────────────────────────────────────────────┤ \\
4 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
5 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
6 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
7 // └─────────────────────────────────────────────────────────────────────┘ \\
8
9 // ┌──────────────────────────────────────────────────────────────────────────────────────┐ \\
10 // │ Eve 0.3.2 - JavaScript Events Library                                                │ \\
11 // ├──────────────────────────────────────────────────────────────────────────────────────┤ \\
12 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://dmitry.baranovskiy.com/)          │ \\
13 // │ Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. │ \\
14 // └──────────────────────────────────────────────────────────────────────────────────────┘ \\
15
16 (function (glob) {
17     var version = "0.3.2",
18         has = "hasOwnProperty",
19         separator = /[\.\/]/,
20         wildcard = "*",
21         fun = function () {},
22         numsort = function (a, b) {
23             return a - b;
24         },
25         current_event,
26         stop,
27         events = {n: {}},
28     
29         eve = function (name, scope) {
30             var e = events,
31                 oldstop = stop,
32                 args = Array.prototype.slice.call(arguments, 2),
33                 listeners = eve.listeners(name),
34                 z = 0,
35                 f = false,
36                 l,
37                 indexed = [],
38                 queue = {},
39                 out = [],
40                 errors = [];
41             current_event = name;
42             stop = 0;
43             for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) {
44                 indexed.push(listeners[i].zIndex);
45                 if (listeners[i].zIndex < 0) {
46                     queue[listeners[i].zIndex] = listeners[i];
47                 }
48             }
49             indexed.sort(numsort);
50             while (indexed[z] < 0) {
51                 l = queue[indexed[z++]];
52                 out.push(l.apply(scope, args));
53                 if (stop) {
54                     stop = oldstop;
55                     return out;
56                 }
57             }
58             for (i = 0; i < ii; i++) {
59                 l = listeners[i];
60                 if ("zIndex" in l) {
61                     if (l.zIndex == indexed[z]) {
62                         out.push(l.apply(scope, args));
63                         if (stop) {
64                             stop = oldstop;
65                             return out;
66                         }
67                         do {
68                             z++;
69                             l = queue[indexed[z]];
70                             l && out.push(l.apply(scope, args));
71                             if (stop) {
72                                 stop = oldstop;
73                                 return out;
74                             }
75                         } while (l)
76                     } else {
77                         queue[l.zIndex] = l;
78                     }
79                 } else {
80                     out.push(l.apply(scope, args));
81                     if (stop) {
82                         stop = oldstop;
83                         return out;
84                     }
85                 }
86             }
87             stop = oldstop;
88             return out.length ? out : null;
89         };
90     
91     eve.listeners = function (name) {
92         var names = name.split(separator),
93             e = events,
94             item,
95             items,
96             k,
97             i,
98             ii,
99             j,
100             jj,
101             nes,
102             es = [e],
103             out = [];
104         for (i = 0, ii = names.length; i < ii; i++) {
105             nes = [];
106             for (j = 0, jj = es.length; j < jj; j++) {
107                 e = es[j].n;
108                 items = [e[names[i]], e[wildcard]];
109                 k = 2;
110                 while (k--) {
111                     item = items[k];
112                     if (item) {
113                         nes.push(item);
114                         out = out.concat(item.f || []);
115                     }
116                 }
117             }
118             es = nes;
119         }
120         return out;
121     };
122     
123     
124     eve.on = function (name, f) {
125         var names = name.split(separator),
126             e = events;
127         for (var i = 0, ii = names.length; i < ii; i++) {
128             e = e.n;
129             !e[names[i]] && (e[names[i]] = {n: {}});
130             e = e[names[i]];
131         }
132         e.f = e.f || [];
133         for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) {
134             return fun;
135         }
136         e.f.push(f);
137         return function (zIndex) {
138             if (+zIndex == +zIndex) {
139                 f.zIndex = +zIndex;
140             }
141         };
142     };
143     
144     eve.stop = function () {
145         stop = 1;
146     };
147     
148     eve.nt = function (subname) {
149         if (subname) {
150             return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event);
151         }
152         return current_event;
153     };
154     
155     eve.unbind = function (name, f) {
156         var names = name.split(separator),
157             e,
158             key,
159             splice,
160             cur = [events];
161         for (var i = 0, ii = names.length; i < ii; i++) {
162             for (var j = 0; j < cur.length; j += splice.length - 2) {
163                 splice = [j, 1];
164                 e = cur[j].n;
165                 if (names[i] != wildcard) {
166                     if (e[names[i]]) {
167                         splice.push(e[names[i]]);
168                     }
169                 } else {
170                     for (key in e) if (e[has](key)) {
171                         splice.push(e[key]);
172                     }
173                 }
174                 cur.splice.apply(cur, splice);
175             }
176         }
177         for (i = 0, ii = cur.length; i < ii; i++) {
178             e = cur[i];
179             while (e.n) {
180                 if (f) {
181                     if (e.f) {
182                         for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) {
183                             e.f.splice(j, 1);
184                             break;
185                         }
186                         !e.f.length && delete e.f;
187                     }
188                     for (key in e.n) if (e.n[has](key) && e.n[key].f) {
189                         var funcs = e.n[key].f;
190                         for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) {
191                             funcs.splice(j, 1);
192                             break;
193                         }
194                         !funcs.length && delete e.n[key].f;
195                     }
196                 } else {
197                     delete e.f;
198                     for (key in e.n) if (e.n[has](key) && e.n[key].f) {
199                         delete e.n[key].f;
200                     }
201                 }
202                 e = e.n;
203             }
204         }
205     };
206     
207     eve.version = version;
208     eve.toString = function () {
209         return "You are running Eve " + version;
210     };
211     (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (glob.eve = eve);
212 })(this);
213
214 // ┌─────────────────────────────────────────────────────────────────────┐ \\
215 // │ "Raphaël 2.0" - JavaScript Vector Library                           │ \\
216 // ├─────────────────────────────────────────────────────────────────────┤ \\
217 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
218 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
219 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
220 // └─────────────────────────────────────────────────────────────────────┘ \\
221 (function () {
222     
223     function R(first) {
224         if (R.is(first, "function")) {
225             return loaded ? first() : eve.on("DOMload", first);
226         } else if (R.is(first, array)) {
227             var a = first,
228                 cnv = R._engine.create[apply](R, a.splice(0, 3 + R.is(a[0], nu))),
229                 res = cnv.set(),
230                 i = 0,
231                 ii = a.length,
232                 j;
233             for (; i < ii; i++) {
234                 j = a[i] || {};
235                 elements[has](j.type) && res.push(cnv[j.type]().attr(j));
236             }
237             return res;
238         } else {
239             var args = Array.prototype.slice.call(arguments, 0);
240             if (R.is(args[args.length - 1], "function")) {
241                 var f = args.pop();
242                 return loaded ? f.call(R._engine.create[apply](R, args)) : eve.on("DOMload", function () {
243                     f.call(R._engine.create[apply](R, args));
244                 });
245             } else {
246                 return R._engine.create[apply](R, arguments);
247             }
248         }
249     }
250     R.version = "2.0.0";
251     R.eve = eve;
252     var loaded,
253         separator = /[, ]+/,
254         elements = {circle: 1, rect: 1, path: 1, ellipse: 1, text: 1, image: 1},
255         formatrg = /\{(\d+)\}/g,
256         proto = "prototype",
257         has = "hasOwnProperty",
258         g = {
259             doc: document,
260             win: window
261         },
262         oldRaphael = {
263             was: Object.prototype[has].call(g.win, "Raphael"),
264             is: g.win.Raphael
265         },
266         Paper = function () {
267             
268             
269             this.ca = this.customAttributes = {};
270         },
271         paperproto,
272         appendChild = "appendChild",
273         apply = "apply",
274         concat = "concat",
275         supportsTouch = "createTouch" in g.doc,
276         E = "",
277         S = " ",
278         Str = String,
279         split = "split",
280         events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S),
281         touchMap = {
282             mousedown: "touchstart",
283             mousemove: "touchmove",
284             mouseup: "touchend"
285         },
286         lowerCase = Str.prototype.toLowerCase,
287         math = Math,
288         mmax = math.max,
289         mmin = math.min,
290         abs = math.abs,
291         pow = math.pow,
292         PI = math.PI,
293         nu = "number",
294         string = "string",
295         array = "array",
296         toString = "toString",
297         fillString = "fill",
298         objectToString = Object.prototype.toString,
299         paper = {},
300         push = "push",
301         ISURL = R._ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i,
302         colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i,
303         isnan = {"NaN": 1, "Infinity": 1, "-Infinity": 1},
304         bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
305         round = math.round,
306         setAttribute = "setAttribute",
307         toFloat = parseFloat,
308         toInt = parseInt,
309         upperCase = Str.prototype.toUpperCase,
310         availableAttrs = R._availableAttrs = {
311             "arrow-end": "none",
312             "arrow-start": "none",
313             blur: 0,
314             "clip-rect": "0 0 1e9 1e9",
315             cursor: "default",
316             cx: 0,
317             cy: 0,
318             fill: "#fff",
319             "fill-opacity": 1,
320             font: '10px "Arial"',
321             "font-family": '"Arial"',
322             "font-size": "10",
323             "font-style": "normal",
324             "font-weight": 400,
325             gradient: 0,
326             height: 0,
327             href: "http://raphaeljs.com/",
328             opacity: 1,
329             path: "M0,0",
330             r: 0,
331             rx: 0,
332             ry: 0,
333             src: "",
334             stroke: "#000",
335             "stroke-dasharray": "",
336             "stroke-linecap": "butt",
337             "stroke-linejoin": "butt",
338             "stroke-miterlimit": 0,
339             "stroke-opacity": 1,
340             "stroke-width": 1,
341             target: "_blank",
342             "text-anchor": "middle",
343             title: "Raphael",
344             transform: "",
345             width: 0,
346             x: 0,
347             y: 0
348         },
349         availableAnimAttrs = R._availableAnimAttrs = {
350             blur: nu,
351             "clip-rect": "csv",
352             cx: nu,
353             cy: nu,
354             fill: "colour",
355             "fill-opacity": nu,
356             "font-size": nu,
357             height: nu,
358             opacity: nu,
359             path: "path",
360             r: nu,
361             rx: nu,
362             ry: nu,
363             stroke: "colour",
364             "stroke-opacity": nu,
365             "stroke-width": nu,
366             transform: "transform",
367             width: nu,
368             x: nu,
369             y: nu
370         },
371         commaSpaces = /\s*,\s*/,
372         hsrg = {hs: 1, rg: 1},
373         p2s = /,?([achlmqrstvxz]),?/gi,
374         pathCommand = /([achlmrqstvz])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?\s*,?\s*)+)/ig,
375         tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?\s*,?\s*)+)/ig,
376         pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)\s*,?\s*/ig,
377         radial_gradient = R._radial_gradient = /^r(?:\(([^,]+?)\s*,\s*([^\)]+?)\))?/,
378         eldata = {},
379         sortByKey = function (a, b) {
380             return a.key - b.key;
381         },
382         sortByNumber = function (a, b) {
383             return toFloat(a) - toFloat(b);
384         },
385         fun = function () {},
386         pipe = function (x) {
387             return x;
388         },
389         rectPath = R._rectPath = function (x, y, w, h, r) {
390             if (r) {
391                 return [["M", x + r, y], ["l", w - r * 2, 0], ["a", r, r, 0, 0, 1, r, r], ["l", 0, h - r * 2], ["a", r, r, 0, 0, 1, -r, r], ["l", r * 2 - w, 0], ["a", r, r, 0, 0, 1, -r, -r], ["l", 0, r * 2 - h], ["a", r, r, 0, 0, 1, r, -r], ["z"]];
392             }
393             return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]];
394         },
395         ellipsePath = function (x, y, rx, ry) {
396             if (ry == null) {
397                 ry = rx;
398             }
399             return [["M", x, y], ["m", 0, -ry], ["a", rx, ry, 0, 1, 1, 0, 2 * ry], ["a", rx, ry, 0, 1, 1, 0, -2 * ry], ["z"]];
400         },
401         getPath = R._getPath = {
402             path: function (el) {
403                 return el.attr("path");
404             },
405             circle: function (el) {
406                 var a = el.attrs;
407                 return ellipsePath(a.cx, a.cy, a.r);
408             },
409             ellipse: function (el) {
410                 var a = el.attrs;
411                 return ellipsePath(a.cx, a.cy, a.rx, a.ry);
412             },
413             rect: function (el) {
414                 var a = el.attrs;
415                 return rectPath(a.x, a.y, a.width, a.height, a.r);
416             },
417             image: function (el) {
418                 var a = el.attrs;
419                 return rectPath(a.x, a.y, a.width, a.height);
420             },
421             text: function (el) {
422                 var bbox = el._getBBox();
423                 return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
424             }
425         },
426         mapPath = R.mapPath = function (path, matrix) {
427             if (!matrix) {
428                 return path;
429             }
430             var x, y, i, j, pathi;
431             path = path2curve(path);
432             for (i = 0, ii = path.length; i < ii; i++) {
433                 pathi = path[i];
434                 for (j = 1, jj = pathi.length; j < jj; j += 2) {
435                     x = matrix.x(pathi[j], pathi[j + 1]);
436                     y = matrix.y(pathi[j], pathi[j + 1]);
437                     pathi[j] = x;
438                     pathi[j + 1] = y;
439                 }
440             }
441             return path;
442         };
443
444     R._g = g;
445     
446     R.type = (g.win.SVGAngle || g.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML");
447     if (R.type == "VML") {
448         var d = g.doc.createElement("div"),
449             b;
450         d.innerHTML = '<v:shape adj="1"/>';
451         b = d.firstChild;
452         b.style.behavior = "url(#default#VML)";
453         if (!(b && typeof b.adj == "object")) {
454             return (R.type = E);
455         }
456         d = null;
457     }
458     
459     
460     R.svg = !(R.vml = R.type == "VML");
461     R._Paper = Paper;
462     
463     R.fn = paperproto = Paper.prototype = R.prototype;
464     R._id = 0;
465     R._oid = 0;
466     
467     R.is = function (o, type) {
468         type = lowerCase.call(type);
469         if (type == "finite") {
470             return !isnan[has](+o);
471         }
472         if (type == "array") {
473             return o instanceof Array;
474         }
475         return  (type == "null" && o === null) ||
476                 (type == typeof o && o !== null) ||
477                 (type == "object" && o === Object(o)) ||
478                 (type == "array" && Array.isArray && Array.isArray(o)) ||
479                 objectToString.call(o).slice(8, -1).toLowerCase() == type;
480     };
481     
482     R.angle = function (x1, y1, x2, y2, x3, y3) {
483         if (x3 == null) {
484             var x = x1 - x2,
485                 y = y1 - y2;
486             if (!x && !y) {
487                 return 0;
488             }
489             return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360;
490         } else {
491             return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3);
492         }
493     };
494     
495     R.rad = function (deg) {
496         return deg % 360 * PI / 180;
497     };
498     
499     R.deg = function (rad) {
500         return rad * 180 / PI % 360;
501     };
502     
503     R.snapTo = function (values, value, tolerance) {
504         tolerance = R.is(tolerance, "finite") ? tolerance : 10;
505         if (R.is(values, array)) {
506             var i = values.length;
507             while (i--) if (abs(values[i] - value) <= tolerance) {
508                 return values[i];
509             }
510         } else {
511             values = +values;
512             var rem = value % values;
513             if (rem < tolerance) {
514                 return value - rem;
515             }
516             if (rem > values - tolerance) {
517                 return value - rem + values;
518             }
519         }
520         return value;
521     };
522     
523     
524     var createUUID = R.createUUID = (function (uuidRegEx, uuidReplacer) {
525         return function () {
526             return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase();
527         };
528     })(/[xy]/g, function (c) {
529         var r = math.random() * 16 | 0,
530             v = c == "x" ? r : (r & 3 | 8);
531         return v.toString(16);
532     });
533
534     
535     R.setWindow = function (newwin) {
536         eve("setWindow", R, g.win, newwin);
537         g.win = newwin;
538         g.doc = g.win.document;
539         if (initWin) {
540             initWin(g.win);
541         }
542     };
543     var toHex = function (color) {
544         if (R.vml) {
545             // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/
546             var trim = /^\s+|\s+$/g;
547             var bod;
548             try {
549                 var docum = new ActiveXObject("htmlfile");
550                 docum.write("<body>");
551                 docum.close();
552                 bod = docum.body;
553             } catch(e) {
554                 bod = createPopup().document.body;
555             }
556             var range = bod.createTextRange();
557             toHex = cacher(function (color) {
558                 try {
559                     bod.style.color = Str(color).replace(trim, E);
560                     var value = range.queryCommandValue("ForeColor");
561                     value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16);
562                     return "#" + ("000000" + value.toString(16)).slice(-6);
563                 } catch(e) {
564                     return "none";
565                 }
566             });
567         } else {
568             var i = g.doc.createElement("i");
569             i.title = "Rapha\xebl Colour Picker";
570             i.style.display = "none";
571             g.doc.body.appendChild(i);
572             toHex = cacher(function (color) {
573                 i.style.color = color;
574                 return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color");
575             });
576         }
577         return toHex(color);
578     },
579     hsbtoString = function () {
580         return "hsb(" + [this.h, this.s, this.b] + ")";
581     },
582     hsltoString = function () {
583         return "hsl(" + [this.h, this.s, this.l] + ")";
584     },
585     rgbtoString = function () {
586         return this.hex;
587     },
588     prepareRGB = function (r, g, b) {
589         if (g == null && R.is(r, "object") && "r" in r && "g" in r && "b" in r) {
590             b = r.b;
591             g = r.g;
592             r = r.r;
593         }
594         if (g == null && R.is(r, string)) {
595             var clr = R.getRGB(r);
596             r = clr.r;
597             g = clr.g;
598             b = clr.b;
599         }
600         if (r > 1 || g > 1 || b > 1) {
601             r /= 255;
602             g /= 255;
603             b /= 255;
604         }
605         
606         return [r, g, b];
607     },
608     packageRGB = function (r, g, b, o) {
609         r *= 255;
610         g *= 255;
611         b *= 255;
612         var rgb = {
613             r: r,
614             g: g,
615             b: b,
616             hex: R.rgb(r, g, b),
617             toString: rgbtoString
618         };
619         R.is(o, "finite") && (rgb.opacity = o);
620         return rgb;
621     };
622     
623     
624     R.color = function (clr) {
625         var rgb;
626         if (R.is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) {
627             rgb = R.hsb2rgb(clr);
628             clr.r = rgb.r;
629             clr.g = rgb.g;
630             clr.b = rgb.b;
631             clr.hex = rgb.hex;
632         } else if (R.is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) {
633             rgb = R.hsl2rgb(clr);
634             clr.r = rgb.r;
635             clr.g = rgb.g;
636             clr.b = rgb.b;
637             clr.hex = rgb.hex;
638         } else {
639             if (R.is(clr, "string")) {
640                 clr = R.getRGB(clr);
641             }
642             if (R.is(clr, "object") && "r" in clr && "g" in clr && "b" in clr) {
643                 rgb = R.rgb2hsl(clr);
644                 clr.h = rgb.h;
645                 clr.s = rgb.s;
646                 clr.l = rgb.l;
647                 rgb = R.rgb2hsb(clr);
648                 clr.v = rgb.b;
649             } else {
650                 clr = {hex: "none"};
651                 crl.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1;
652             }
653         }
654         clr.toString = rgbtoString;
655         return clr;
656     };
657     
658     R.hsb2rgb = function (h, s, v, o) {
659         if (this.is(h, "object") && "h" in h && "s" in h && "b" in h) {
660             v = h.b;
661             s = h.s;
662             h = h.h;
663             o = h.o;
664         }
665         h *= 360;
666         var R, G, B, X, C;
667         h = (h % 360) / 60;
668         C = v * s;
669         X = C * (1 - abs(h % 2 - 1));
670         R = G = B = v - C;
671
672         h = ~~h;
673         R += [C, X, 0, 0, X, C][h];
674         G += [X, C, C, X, 0, 0][h];
675         B += [0, 0, X, C, C, X][h];
676         return packageRGB(R, G, B, o);
677     };
678     
679     R.hsl2rgb = function (h, s, l, o) {
680         if (this.is(h, "object") && "h" in h && "s" in h && "l" in h) {
681             l = h.l;
682             s = h.s;
683             h = h.h;
684         }
685         if (h > 1 || s > 1 || l > 1) {
686             h /= 360;
687             s /= 100;
688             l /= 100;
689         }
690         h *= 360;
691         var R, G, B, X, C;
692         h = (h % 360) / 60;
693         C = 2 * s * (l < .5 ? l : 1 - l);
694         X = C * (1 - abs(h % 2 - 1));
695         R = G = B = l - C / 2;
696
697         h = ~~h;
698         R += [C, X, 0, 0, X, C][h];
699         G += [X, C, C, X, 0, 0][h];
700         B += [0, 0, X, C, C, X][h];
701         return packageRGB(R, G, B, o);
702     };
703     
704     R.rgb2hsb = function (r, g, b) {
705         b = prepareRGB(r, g, b);
706         r = b[0];
707         g = b[1];
708         b = b[2];
709
710         var H, S, V, C;
711         V = mmax(r, g, b);
712         C = V - mmin(r, g, b);
713         H = (C == 0 ? null :
714              V == r ? (g - b) / C :
715              V == g ? (b - r) / C + 2 :
716                       (r - g) / C + 4
717             );
718         H = ((H + 360) % 6) * 60 / 360;
719         S = C == 0 ? 0 : C / V;
720         return {h: H, s: S, b: V, toString: hsbtoString};
721     };
722     
723     R.rgb2hsl = function (r, g, b) {
724         b = prepareRGB(r, g, b);
725         r = b[0];
726         g = b[1];
727         b = b[2];
728
729         var H, S, L, M, m, C;
730         M = mmax(r, g, b);
731         m = mmin(r, g, b);
732         C = M - m;
733         H = (C == 0 ? null :
734              M == r ? (g - b) / C :
735              M == g ? (b - r) / C + 2 :
736                       (r - g) / C + 4);
737         H = ((H + 360) % 6) * 60 / 360;
738         L = (M + m) / 2;
739         S = (C == 0 ? 0 :
740              L < .5 ? C / (2 * L) :
741                       C / (2 - 2 * L));
742         return {h: H, s: S, l: L, toString: hsltoString};
743     };
744     R._path2string = function () {
745         return this.join(",").replace(p2s, "$1");
746     };
747     function repush(array, item) {
748         for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) {
749             return array.push(array.splice(i, 1)[0]);
750         }
751     }
752     function cacher(f, scope, postprocessor) {
753         function newf() {
754             var arg = Array.prototype.slice.call(arguments, 0),
755                 args = arg.join("\u2400"),
756                 cache = newf.cache = newf.cache || {},
757                 count = newf.count = newf.count || [];
758             if (cache[has](args)) {
759                 repush(count, args);
760                 return postprocessor ? postprocessor(cache[args]) : cache[args];
761             }
762             count.length >= 1e3 && delete cache[count.shift()];
763             count.push(args);
764             cache[args] = f[apply](scope, arg);
765             return postprocessor ? postprocessor(cache[args]) : cache[args];
766         }
767         return newf;
768     }
769
770     var preload = R._preload = function (src, f) {
771         var img = g.doc.createElement("img");
772         img.style.cssText = "position:absolute;left:-9999em;top-9999em";
773         img.onload = function () {
774             f.call(this);
775             this.onload = null;
776             g.doc.body.removeChild(this);
777         };
778         img.onerror = function () {
779             g.doc.body.removeChild(this);
780         };
781         g.doc.body.appendChild(img);
782         img.src = src;
783     };
784     
785     function clrToString() {
786         return this.hex;
787     }
788
789     
790     R.getRGB = cacher(function (colour) {
791         if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) {
792             return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString};
793         }
794         if (colour == "none") {
795             return {r: -1, g: -1, b: -1, hex: "none", toString: clrToString};
796         }
797         !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour));
798         var res,
799             red,
800             green,
801             blue,
802             opacity,
803             t,
804             values,
805             rgb = colour.match(colourRegExp);
806         if (rgb) {
807             if (rgb[2]) {
808                 blue = toInt(rgb[2].substring(5), 16);
809                 green = toInt(rgb[2].substring(3, 5), 16);
810                 red = toInt(rgb[2].substring(1, 3), 16);
811             }
812             if (rgb[3]) {
813                 blue = toInt((t = rgb[3].charAt(3)) + t, 16);
814                 green = toInt((t = rgb[3].charAt(2)) + t, 16);
815                 red = toInt((t = rgb[3].charAt(1)) + t, 16);
816             }
817             if (rgb[4]) {
818                 values = rgb[4][split](commaSpaces);
819                 red = toFloat(values[0]);
820                 values[0].slice(-1) == "%" && (red *= 2.55);
821                 green = toFloat(values[1]);
822                 values[1].slice(-1) == "%" && (green *= 2.55);
823                 blue = toFloat(values[2]);
824                 values[2].slice(-1) == "%" && (blue *= 2.55);
825                 rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3]));
826                 values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
827             }
828             if (rgb[5]) {
829                 values = rgb[5][split](commaSpaces);
830                 red = toFloat(values[0]);
831                 values[0].slice(-1) == "%" && (red *= 2.55);
832                 green = toFloat(values[1]);
833                 values[1].slice(-1) == "%" && (green *= 2.55);
834                 blue = toFloat(values[2]);
835                 values[2].slice(-1) == "%" && (blue *= 2.55);
836                 (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
837                 rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3]));
838                 values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
839                 return R.hsb2rgb(red, green, blue, opacity);
840             }
841             if (rgb[6]) {
842                 values = rgb[6][split](commaSpaces);
843                 red = toFloat(values[0]);
844                 values[0].slice(-1) == "%" && (red *= 2.55);
845                 green = toFloat(values[1]);
846                 values[1].slice(-1) == "%" && (green *= 2.55);
847                 blue = toFloat(values[2]);
848                 values[2].slice(-1) == "%" && (blue *= 2.55);
849                 (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
850                 rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3]));
851                 values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
852                 return R.hsl2rgb(red, green, blue, opacity);
853             }
854             rgb = {r: red, g: green, b: blue, toString: clrToString};
855             rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1);
856             R.is(opacity, "finite") && (rgb.opacity = opacity);
857             return rgb;
858         }
859         return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString};
860     }, R);
861     
862     R.hsb = cacher(function (h, s, b) {
863         return R.hsb2rgb(h, s, b).hex;
864     });
865     
866     R.hsl = cacher(function (h, s, l) {
867         return R.hsl2rgb(h, s, l).hex;
868     });
869     
870     R.rgb = cacher(function (r, g, b) {
871         return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1);
872     });
873     
874     R.getColor = function (value) {
875         var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75},
876             rgb = this.hsb2rgb(start.h, start.s, start.b);
877         start.h += .075;
878         if (start.h > 1) {
879             start.h = 0;
880             start.s -= .2;
881             start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b});
882         }
883         return rgb.hex;
884     };
885     
886     R.getColor.reset = function () {
887         delete this.start;
888     };
889
890     // http://schepers.cc/getting-to-the-point
891     function catmullRom2bezier(crp) {
892         var d = [];
893         for (var i = 0, iLen = crp.length; iLen - 2 > i; i += 2) {
894             var p = [{x: +crp[i],     y: +crp[i + 1]},
895                      {x: +crp[i],     y: +crp[i + 1]},
896                      {x: +crp[i + 2], y: +crp[i + 3]},
897                      {x: +crp[i + 4], y: +crp[i + 5]}];
898             if (iLen - 4 == i) {
899                 p[0] = {x: +crp[i - 2], y: +crp[i - 1]};
900                 p[3] = p[2];
901             } else if (i) {
902                 p[0] = {x: +crp[i - 2], y: +crp[i - 1]};
903             }
904             d.push(["C",
905                 (-p[0].x + 6 * p[1].x + p[2].x) / 6,
906                 (-p[0].y + 6 * p[1].y + p[2].y) / 6,
907                 (p[1].x + 6 * p[2].x - p[3].x) / 6,
908                 (p[1].y + 6*p[2].y - p[3].y) / 6,
909                 p[2].x,
910                 p[2].y
911             ]);
912         }
913
914         return d;
915     }
916     
917     R.parsePathString = cacher(function (pathString) {
918         if (!pathString) {
919             return null;
920         }
921         var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0},
922             data = [];
923         if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption
924             data = pathClone(pathString);
925         }
926         if (!data.length) {
927             Str(pathString).replace(pathCommand, function (a, b, c) {
928                 var params = [],
929                     name = b.toLowerCase();
930                 c.replace(pathValues, function (a, b) {
931                     b && params.push(+b);
932                 });
933                 if (name == "m" && params.length > 2) {
934                     data.push([b][concat](params.splice(0, 2)));
935                     name = "l";
936                     b = b == "m" ? "l" : "L";
937                 }
938                 if (name == "r") {
939                     data.push([b][concat](params));
940                 } else while (params.length >= paramCounts[name]) {
941                     data.push([b][concat](params.splice(0, paramCounts[name])));
942                     if (!paramCounts[name]) {
943                         break;
944                     }
945                 }
946             });
947         }
948         data.toString = R._path2string;
949         return data;
950     });
951     
952     R.parseTransformString = cacher(function (TString) {
953         if (!TString) {
954             return null;
955         }
956         var paramCounts = {r: 3, s: 4, t: 2, m: 6},
957             data = [];
958         if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption
959             data = pathClone(TString);
960         }
961         if (!data.length) {
962             Str(TString).replace(tCommand, function (a, b, c) {
963                 var params = [],
964                     name = lowerCase.call(b);
965                 c.replace(pathValues, function (a, b) {
966                     b && params.push(+b);
967                 });
968                 data.push([b][concat](params));
969             });
970         }
971         data.toString = R._path2string;
972         return data;
973     });
974     
975     R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
976         var t1 = 1 - t,
977             t13 = pow(t1, 3),
978             t12 = pow(t1, 2),
979             t2 = t * t,
980             t3 = t2 * t,
981             x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x,
982             y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y,
983             mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x),
984             my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y),
985             nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x),
986             ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y),
987             ax = t1 * p1x + t * c1x,
988             ay = t1 * p1y + t * c1y,
989             cx = t1 * c2x + t * p2x,
990             cy = t1 * c2y + t * p2y,
991             alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI);
992         (mx > nx || my < ny) && (alpha += 180);
993         return {
994             x: x,
995             y: y,
996             m: {x: mx, y: my},
997             n: {x: nx, y: ny},
998             start: {x: ax, y: ay},
999             end: {x: cx, y: cy},
1000             alpha: alpha
1001         };
1002     };
1003     var pathDimensions = cacher(function (path) {
1004         if (!path) {
1005             return {x: 0, y: 0, width: 0, height: 0};
1006         }
1007         path = path2curve(path);
1008         var x = 0, 
1009             y = 0,
1010             X = [],
1011             Y = [],
1012             p;
1013         for (var i = 0, ii = path.length; i < ii; i++) {
1014             p = path[i];
1015             if (p[0] == "M") {
1016                 x = p[1];
1017                 y = p[2];
1018                 X.push(x);
1019                 Y.push(y);
1020             } else {
1021                 var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
1022                 X = X[concat](dim.min.x, dim.max.x);
1023                 Y = Y[concat](dim.min.y, dim.max.y);
1024                 x = p[5];
1025                 y = p[6];
1026             }
1027         }
1028         var xmin = mmin[apply](0, X),
1029             ymin = mmin[apply](0, Y);
1030         return {
1031             x: xmin,
1032             y: ymin,
1033             width: mmax[apply](0, X) - xmin,
1034             height: mmax[apply](0, Y) - ymin
1035         };
1036     }, null, function (o) {
1037         return {
1038             x: o.x,
1039             y: o.y,
1040             width: o.width,
1041             height: o.height
1042         };
1043     }),
1044         pathClone = function (pathArray) {
1045             var res = [];
1046             if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
1047                 pathArray = R.parsePathString(pathArray);
1048             }
1049             for (var i = 0, ii = pathArray.length; i < ii; i++) {
1050                 res[i] = [];
1051                 for (var j = 0, jj = pathArray[i].length; j < jj; j++) {
1052                     res[i][j] = pathArray[i][j];
1053                 }
1054             }
1055             res.toString = R._path2string;
1056             return res;
1057         },
1058         pathToRelative = R._pathToRelative = cacher(function (pathArray) {
1059             if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
1060                 pathArray = R.parsePathString(pathArray);
1061             }
1062             var res = [],
1063                 x = 0,
1064                 y = 0,
1065                 mx = 0,
1066                 my = 0,
1067                 start = 0;
1068             if (pathArray[0][0] == "M") {
1069                 x = pathArray[0][1];
1070                 y = pathArray[0][2];
1071                 mx = x;
1072                 my = y;
1073                 start++;
1074                 res.push(["M", x, y]);
1075             }
1076             for (var i = start, ii = pathArray.length; i < ii; i++) {
1077                 var r = res[i] = [],
1078                     pa = pathArray[i];
1079                 if (pa[0] != lowerCase.call(pa[0])) {
1080                     r[0] = lowerCase.call(pa[0]);
1081                     switch (r[0]) {
1082                         case "a":
1083                             r[1] = pa[1];
1084                             r[2] = pa[2];
1085                             r[3] = pa[3];
1086                             r[4] = pa[4];
1087                             r[5] = pa[5];
1088                             r[6] = +(pa[6] - x).toFixed(3);
1089                             r[7] = +(pa[7] - y).toFixed(3);
1090                             break;
1091                         case "v":
1092                             r[1] = +(pa[1] - y).toFixed(3);
1093                             break;
1094                         case "m":
1095                             mx = pa[1];
1096                             my = pa[2];
1097                         default:
1098                             for (var j = 1, jj = pa.length; j < jj; j++) {
1099                                 r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
1100                             }
1101                     }
1102                 } else {
1103                     r = res[i] = [];
1104                     if (pa[0] == "m") {
1105                         mx = pa[1] + x;
1106                         my = pa[2] + y;
1107                     }
1108                     for (var k = 0, kk = pa.length; k < kk; k++) {
1109                         res[i][k] = pa[k];
1110                     }
1111                 }
1112                 var len = res[i].length;
1113                 switch (res[i][0]) {
1114                     case "z":
1115                         x = mx;
1116                         y = my;
1117                         break;
1118                     case "h":
1119                         x += +res[i][len - 1];
1120                         break;
1121                     case "v":
1122                         y += +res[i][len - 1];
1123                         break;
1124                     default:
1125                         x += +res[i][len - 2];
1126                         y += +res[i][len - 1];
1127                 }
1128             }
1129             res.toString = R._path2string;
1130             return res;
1131         }, 0, pathClone),
1132         pathToAbsolute = R._pathToAbsolute = cacher(function (pathArray) {
1133             if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
1134                 pathArray = R.parsePathString(pathArray);
1135             }
1136             if (!pathArray || !pathArray.length) {
1137                 return [["M", 0, 0]];
1138             }
1139             var res = [],
1140                 x = 0,
1141                 y = 0,
1142                 mx = 0,
1143                 my = 0,
1144                 start = 0;
1145             if (pathArray[0][0] == "M") {
1146                 x = +pathArray[0][1];
1147                 y = +pathArray[0][2];
1148                 mx = x;
1149                 my = y;
1150                 start++;
1151                 res[0] = ["M", x, y];
1152             }
1153             for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) {
1154                 res.push(r = []);
1155                 pa = pathArray[i];
1156                 if (pa[0] != upperCase.call(pa[0])) {
1157                     r[0] = upperCase.call(pa[0]);
1158                     switch (r[0]) {
1159                         case "A":
1160                             r[1] = pa[1];
1161                             r[2] = pa[2];
1162                             r[3] = pa[3];
1163                             r[4] = pa[4];
1164                             r[5] = pa[5];
1165                             r[6] = +(pa[6] + x);
1166                             r[7] = +(pa[7] + y);
1167                             break;
1168                         case "V":
1169                             r[1] = +pa[1] + y;
1170                             break;
1171                         case "H":
1172                             r[1] = +pa[1] + x;
1173                             break;
1174                         case "R":
1175                             var dots = [x, y][concat](pa.slice(1));
1176                             for (var j = 2, jj = dots.length; j < jj; j++) {
1177                                 dots[j] = +dots[j] + x;
1178                                 dots[++j] = +dots[j] + y;
1179                             }
1180                             res.pop();
1181                             res = res[concat](catmullRom2bezier(dots));
1182                             break;
1183                         case "M":
1184                             mx = +pa[1] + x;
1185                             my = +pa[2] + y;
1186                         default:
1187                             for (j = 1, jj = pa.length; j < jj; j++) {
1188                                 r[j] = +pa[j] + ((j % 2) ? x : y);
1189                             }
1190                     }
1191                 } else if (pa[0] == "R") {
1192                     dots = [x, y][concat](pa.slice(1));
1193                     res.pop();
1194                     res = res[concat](catmullRom2bezier(dots));
1195                     r = ["R"][concat](pa.slice(-2));
1196                 } else {
1197                     for (var k = 0, kk = pa.length; k < kk; k++) {
1198                         r[k] = pa[k];
1199                     }
1200                 }
1201                 switch (r[0]) {
1202                     case "Z":
1203                         x = mx;
1204                         y = my;
1205                         break;
1206                     case "H":
1207                         x = r[1];
1208                         break;
1209                     case "V":
1210                         y = r[1];
1211                         break;
1212                     case "M":
1213                         mx = r[r.length - 2];
1214                         my = r[r.length - 1];
1215                     default:
1216                         x = r[r.length - 2];
1217                         y = r[r.length - 1];
1218                 }
1219             }
1220             res.toString = R._path2string;
1221             return res;
1222         }, null, pathClone),
1223         l2c = function (x1, y1, x2, y2) {
1224             return [x1, y1, x2, y2, x2, y2];
1225         },
1226         q2c = function (x1, y1, ax, ay, x2, y2) {
1227             var _13 = 1 / 3,
1228                 _23 = 2 / 3;
1229             return [
1230                     _13 * x1 + _23 * ax,
1231                     _13 * y1 + _23 * ay,
1232                     _13 * x2 + _23 * ax,
1233                     _13 * y2 + _23 * ay,
1234                     x2,
1235                     y2
1236                 ];
1237         },
1238         a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
1239             // for more information of where this math came from visit:
1240             // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
1241             var _120 = PI * 120 / 180,
1242                 rad = PI / 180 * (+angle || 0),
1243                 res = [],
1244                 xy,
1245                 rotate = cacher(function (x, y, rad) {
1246                     var X = x * math.cos(rad) - y * math.sin(rad),
1247                         Y = x * math.sin(rad) + y * math.cos(rad);
1248                     return {x: X, y: Y};
1249                 });
1250             if (!recursive) {
1251                 xy = rotate(x1, y1, -rad);
1252                 x1 = xy.x;
1253                 y1 = xy.y;
1254                 xy = rotate(x2, y2, -rad);
1255                 x2 = xy.x;
1256                 y2 = xy.y;
1257                 var cos = math.cos(PI / 180 * angle),
1258                     sin = math.sin(PI / 180 * angle),
1259                     x = (x1 - x2) / 2,
1260                     y = (y1 - y2) / 2;
1261                 var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
1262                 if (h > 1) {
1263                     h = math.sqrt(h);
1264                     rx = h * rx;
1265                     ry = h * ry;
1266                 }
1267                 var rx2 = rx * rx,
1268                     ry2 = ry * ry,
1269                     k = (large_arc_flag == sweep_flag ? -1 : 1) *
1270                         math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
1271                     cx = k * rx * y / ry + (x1 + x2) / 2,
1272                     cy = k * -ry * x / rx + (y1 + y2) / 2,
1273                     f1 = math.asin(((y1 - cy) / ry).toFixed(9)),
1274                     f2 = math.asin(((y2 - cy) / ry).toFixed(9));
1275
1276                 f1 = x1 < cx ? PI - f1 : f1;
1277                 f2 = x2 < cx ? PI - f2 : f2;
1278                 f1 < 0 && (f1 = PI * 2 + f1);
1279                 f2 < 0 && (f2 = PI * 2 + f2);
1280                 if (sweep_flag && f1 > f2) {
1281                     f1 = f1 - PI * 2;
1282                 }
1283                 if (!sweep_flag && f2 > f1) {
1284                     f2 = f2 - PI * 2;
1285                 }
1286             } else {
1287                 f1 = recursive[0];
1288                 f2 = recursive[1];
1289                 cx = recursive[2];
1290                 cy = recursive[3];
1291             }
1292             var df = f2 - f1;
1293             if (abs(df) > _120) {
1294                 var f2old = f2,
1295                     x2old = x2,
1296                     y2old = y2;
1297                 f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
1298                 x2 = cx + rx * math.cos(f2);
1299                 y2 = cy + ry * math.sin(f2);
1300                 res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
1301             }
1302             df = f2 - f1;
1303             var c1 = math.cos(f1),
1304                 s1 = math.sin(f1),
1305                 c2 = math.cos(f2),
1306                 s2 = math.sin(f2),
1307                 t = math.tan(df / 4),
1308                 hx = 4 / 3 * rx * t,
1309                 hy = 4 / 3 * ry * t,
1310                 m1 = [x1, y1],
1311                 m2 = [x1 + hx * s1, y1 - hy * c1],
1312                 m3 = [x2 + hx * s2, y2 - hy * c2],
1313                 m4 = [x2, y2];
1314             m2[0] = 2 * m1[0] - m2[0];
1315             m2[1] = 2 * m1[1] - m2[1];
1316             if (recursive) {
1317                 return [m2, m3, m4][concat](res);
1318             } else {
1319                 res = [m2, m3, m4][concat](res).join()[split](",");
1320                 var newres = [];
1321                 for (var i = 0, ii = res.length; i < ii; i++) {
1322                     newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
1323                 }
1324                 return newres;
1325             }
1326         },
1327         findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
1328             var t1 = 1 - t;
1329             return {
1330                 x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,
1331                 y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
1332             };
1333         },
1334         curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
1335             var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
1336                 b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
1337                 c = p1x - c1x,
1338                 t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a,
1339                 t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a,
1340                 y = [p1y, p2y],
1341                 x = [p1x, p2x],
1342                 dot;
1343             abs(t1) > "1e12" && (t1 = .5);
1344             abs(t2) > "1e12" && (t2 = .5);
1345             if (t1 > 0 && t1 < 1) {
1346                 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
1347                 x.push(dot.x);
1348                 y.push(dot.y);
1349             }
1350             if (t2 > 0 && t2 < 1) {
1351                 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
1352                 x.push(dot.x);
1353                 y.push(dot.y);
1354             }
1355             a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
1356             b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
1357             c = p1y - c1y;
1358             t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a;
1359             t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a;
1360             abs(t1) > "1e12" && (t1 = .5);
1361             abs(t2) > "1e12" && (t2 = .5);
1362             if (t1 > 0 && t1 < 1) {
1363                 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
1364                 x.push(dot.x);
1365                 y.push(dot.y);
1366             }
1367             if (t2 > 0 && t2 < 1) {
1368                 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
1369                 x.push(dot.x);
1370                 y.push(dot.y);
1371             }
1372             return {
1373                 min: {x: mmin[apply](0, x), y: mmin[apply](0, y)},
1374                 max: {x: mmax[apply](0, x), y: mmax[apply](0, y)}
1375             };
1376         }),
1377         path2curve = R._path2curve = cacher(function (path, path2) {
1378             var p = pathToAbsolute(path),
1379                 p2 = path2 && pathToAbsolute(path2),
1380                 attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
1381                 attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
1382                 processPath = function (path, d) {
1383                     var nx, ny;
1384                     if (!path) {
1385                         return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
1386                     }
1387                     !(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null);
1388                     switch (path[0]) {
1389                         case "M":
1390                             d.X = path[1];
1391                             d.Y = path[2];
1392                             break;
1393                         case "A":
1394                             path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1))));
1395                             break;
1396                         case "S":
1397                             nx = d.x + (d.x - (d.bx || d.x));
1398                             ny = d.y + (d.y - (d.by || d.y));
1399                             path = ["C", nx, ny][concat](path.slice(1));
1400                             break;
1401                         case "T":
1402                             d.qx = d.x + (d.x - (d.qx || d.x));
1403                             d.qy = d.y + (d.y - (d.qy || d.y));
1404                             path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
1405                             break;
1406                         case "Q":
1407                             d.qx = path[1];
1408                             d.qy = path[2];
1409                             path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
1410                             break;
1411                         case "L":
1412                             path = ["C"][concat](l2c(d.x, d.y, path[1], path[2]));
1413                             break;
1414                         case "H":
1415                             path = ["C"][concat](l2c(d.x, d.y, path[1], d.y));
1416                             break;
1417                         case "V":
1418                             path = ["C"][concat](l2c(d.x, d.y, d.x, path[1]));
1419                             break;
1420                         case "Z":
1421                             path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y));
1422                             break;
1423                     }
1424                     return path;
1425                 },
1426                 fixArc = function (pp, i) {
1427                     if (pp[i].length > 7) {
1428                         pp[i].shift();
1429                         var pi = pp[i];
1430                         while (pi.length) {
1431                             pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6)));
1432                         }
1433                         pp.splice(i, 1);
1434                         ii = mmax(p.length, p2 && p2.length || 0);
1435                     }
1436                 },
1437                 fixM = function (path1, path2, a1, a2, i) {
1438                     if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
1439                         path2.splice(i, 0, ["M", a2.x, a2.y]);
1440                         a1.bx = 0;
1441                         a1.by = 0;
1442                         a1.x = path1[i][1];
1443                         a1.y = path1[i][2];
1444                         ii = mmax(p.length, p2 && p2.length || 0);
1445                     }
1446                 };
1447             for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) {
1448                 p[i] = processPath(p[i], attrs);
1449                 fixArc(p, i);
1450                 p2 && (p2[i] = processPath(p2[i], attrs2));
1451                 p2 && fixArc(p2, i);
1452                 fixM(p, p2, attrs, attrs2, i);
1453                 fixM(p2, p, attrs2, attrs, i);
1454                 var seg = p[i],
1455                     seg2 = p2 && p2[i],
1456                     seglen = seg.length,
1457                     seg2len = p2 && seg2.length;
1458                 attrs.x = seg[seglen - 2];
1459                 attrs.y = seg[seglen - 1];
1460                 attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;
1461                 attrs.by = toFloat(seg[seglen - 3]) || attrs.y;
1462                 attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x);
1463                 attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y);
1464                 attrs2.x = p2 && seg2[seg2len - 2];
1465                 attrs2.y = p2 && seg2[seg2len - 1];
1466             }
1467             return p2 ? [p, p2] : p;
1468         }, null, pathClone),
1469         parseDots = R._parseDots = cacher(function (gradient) {
1470             var dots = [];
1471             for (var i = 0, ii = gradient.length; i < ii; i++) {
1472                 var dot = {},
1473                     par = gradient[i].match(/^([^:]*):?([\d\.]*)/);
1474                 dot.color = R.getRGB(par[1]);
1475                 if (dot.color.error) {
1476                     return null;
1477                 }
1478                 dot.color = dot.color.hex;
1479                 par[2] && (dot.offset = par[2] + "%");
1480                 dots.push(dot);
1481             }
1482             for (i = 1, ii = dots.length - 1; i < ii; i++) {
1483                 if (!dots[i].offset) {
1484                     var start = toFloat(dots[i - 1].offset || 0),
1485                         end = 0;
1486                     for (var j = i + 1; j < ii; j++) {
1487                         if (dots[j].offset) {
1488                             end = dots[j].offset;
1489                             break;
1490                         }
1491                     }
1492                     if (!end) {
1493                         end = 100;
1494                         j = ii;
1495                     }
1496                     end = toFloat(end);
1497                     var d = (end - start) / (j - i + 1);
1498                     for (; i < j; i++) {
1499                         start += d;
1500                         dots[i].offset = start + "%";
1501                     }
1502                 }
1503             }
1504             return dots;
1505         }),
1506         tear = R._tear = function (el, paper) {
1507             el == paper.top && (paper.top = el.prev);
1508             el == paper.bottom && (paper.bottom = el.next);
1509             el.next && (el.next.prev = el.prev);
1510             el.prev && (el.prev.next = el.next);
1511         },
1512         tofront = R._tofront = function (el, paper) {
1513             if (paper.top === el) {
1514                 return;
1515             }
1516             tear(el, paper);
1517             el.next = null;
1518             el.prev = paper.top;
1519             paper.top.next = el;
1520             paper.top = el;
1521         },
1522         toback = R._toback = function (el, paper) {
1523             if (paper.bottom === el) {
1524                 return;
1525             }
1526             tear(el, paper);
1527             el.next = paper.bottom;
1528             el.prev = null;
1529             paper.bottom.prev = el;
1530             paper.bottom = el;
1531         },
1532         insertafter = R._insertafter = function (el, el2, paper) {
1533             tear(el, paper);
1534             el2 == paper.top && (paper.top = el);
1535             el2.next && (el2.next.prev = el);
1536             el.next = el2.next;
1537             el.prev = el2;
1538             el2.next = el;
1539         },
1540         insertbefore = R._insertbefore = function (el, el2, paper) {
1541             tear(el, paper);
1542             el2 == paper.bottom && (paper.bottom = el);
1543             el2.prev && (el2.prev.next = el);
1544             el.prev = el2.prev;
1545             el2.prev = el;
1546             el.next = el2;
1547         },
1548         removed = function (methodname) {
1549             return function () {
1550                 throw new Error("Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object");
1551             };
1552         },
1553         extractTransform = R._extractTransform = function (el, tstr) {
1554             if (tstr == null) {
1555                 return el._.transform;
1556             }
1557             tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E);
1558             var tdata = R.parseTransformString(tstr),
1559                 deg = 0,
1560                 dx = 0,
1561                 dy = 0,
1562                 sx = 1,
1563                 sy = 1,
1564                 _ = el._,
1565                 m = new Matrix;
1566             _.transform = tdata || [];
1567             if (tdata) {
1568                 for (var i = 0, ii = tdata.length; i < ii; i++) {
1569                     var t = tdata[i],
1570                         tlen = t.length,
1571                         command = Str(t[0]).toLowerCase(),
1572                         absolute = t[0] != command,
1573                         inver = absolute ? m.invert() : 0,
1574                         x1,
1575                         y1,
1576                         x2,
1577                         y2,
1578                         bb;
1579                     if (command == "t" && tlen == 3) {
1580                         if (absolute) {
1581                             x1 = inver.x(0, 0);
1582                             y1 = inver.y(0, 0);
1583                             x2 = inver.x(t[1], t[2]);
1584                             y2 = inver.y(t[1], t[2]);
1585                             m.translate(x2 - x1, y2 - y1);
1586                         } else {
1587                             m.translate(t[1], t[2]);
1588                         }
1589                     } else if (command == "r") {
1590                         if (tlen == 2) {
1591                             bb = bb || el.getBBox(1);
1592                             m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2);
1593                             deg += t[1];
1594                         } else if (tlen == 4) {
1595                             if (absolute) {
1596                                 x2 = inver.x(t[2], t[3]);
1597                                 y2 = inver.y(t[2], t[3]);
1598                                 m.rotate(t[1], x2, y2);
1599                             } else {
1600                                 m.rotate(t[1], t[2], t[3]);
1601                             }
1602                             deg += t[1];
1603                         }
1604                     } else if (command == "s") {
1605                         if (tlen == 2 || tlen == 3) {
1606                             bb = bb || el.getBBox(1);
1607                             m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2);
1608                             sx *= t[1];
1609                             sy *= t[tlen - 1];
1610                         } else if (tlen == 5) {
1611                             if (absolute) {
1612                                 x2 = inver.x(t[3], t[4]);
1613                                 y2 = inver.y(t[3], t[4]);
1614                                 m.scale(t[1], t[2], x2, y2);
1615                             } else {
1616                                 m.scale(t[1], t[2], t[3], t[4]);
1617                             }
1618                             sx *= t[1];
1619                             sy *= t[2];
1620                         }
1621                     } else if (command == "m" && tlen == 7) {
1622                         m.add(t[1], t[2], t[3], t[4], t[5], t[6]);
1623                     }
1624                     _.dirtyT = 1;
1625                     el.matrix = m;
1626                 }
1627             }
1628
1629             el.matrix = m;
1630
1631             _.sx = sx;
1632             _.sy = sy;
1633             _.deg = deg;
1634             _.dx = dx = m.e;
1635             _.dy = dy = m.f;
1636
1637             if (sx == 1 && sy == 1 && !deg && _.bbox) {
1638                 _.bbox.x += +dx;
1639                 _.bbox.y += +dy;
1640             } else {
1641                 _.dirtyT = 1;
1642             }
1643         },
1644         getEmpty = function (item) {
1645             var l = item[0];
1646             switch (l.toLowerCase()) {
1647                 case "t": return [l, 0, 0];
1648                 case "m": return [l, 1, 0, 0, 1, 0, 0];
1649                 case "r": if (item.length == 4) {
1650                     return [l, 0, item[2], item[3]];
1651                 } else {
1652                     return [l, 0];
1653                 }
1654                 case "s": if (item.length == 5) {
1655                     return [l, 1, 1, item[3], item[4]];
1656                 } else if (item.length == 3) {
1657                     return [l, 1, 1];
1658                 } else {
1659                     return [l, 1];
1660                 }
1661             }
1662         },
1663         equaliseTransform = R._equaliseTransform = function (t1, t2) {
1664             t2 = Str(t2).replace(/\.{3}|\u2026/g, t1);
1665             t1 = R.parseTransformString(t1) || [];
1666             t2 = R.parseTransformString(t2) || [];
1667             var maxlength = mmax(t1.length, t2.length),
1668                 from = [],
1669                 to = [],
1670                 i = 0, j, jj,
1671                 tt1, tt2;
1672             for (; i < maxlength; i++) {
1673                 tt1 = t1[i] || getEmpty(t2[i]);
1674                 tt2 = t2[i] || getEmpty(tt1);
1675                 if ((tt1[0] != tt2[0]) ||
1676                     (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) ||
1677                     (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4]))
1678                     ) {
1679                     return;
1680                 }
1681                 from[i] = [];
1682                 to[i] = [];
1683                 for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) {
1684                     j in tt1 && (from[i][j] = tt1[j]);
1685                     j in tt2 && (to[i][j] = tt2[j]);
1686                 }
1687             }
1688             return {
1689                 from: from,
1690                 to: to
1691             };
1692         };
1693     R._getContainer = function (x, y, w, h) {
1694         var container;
1695         container = h == null && !R.is(x, "object") ? g.doc.getElementById(x) : x;
1696         if (container == null) {
1697             return;
1698         }
1699         if (container.tagName) {
1700             if (y == null) {
1701                 return {
1702                     container: container,
1703                     width: container.style.pixelWidth || container.offsetWidth,
1704                     height: container.style.pixelHeight || container.offsetHeight
1705                 };
1706             } else {
1707                 return {
1708                     container: container,
1709                     width: y,
1710                     height: w
1711                 };
1712             }
1713         }
1714         return {
1715             container: 1,
1716             x: x,
1717             y: y,
1718             width: w,
1719             height: h
1720         };
1721     };
1722     
1723     R.pathToRelative = pathToRelative;
1724     R._engine = {};
1725     
1726     R.path2curve = path2curve;
1727     
1728     R.matrix = function (a, b, c, d, e, f) {
1729         return new Matrix(a, b, c, d, e, f);
1730     };
1731     function Matrix(a, b, c, d, e, f) {
1732         if (a != null) {
1733             this.a = +a;
1734             this.b = +b;
1735             this.c = +c;
1736             this.d = +d;
1737             this.e = +e;
1738             this.f = +f;
1739         } else {
1740             this.a = 1;
1741             this.b = 0;
1742             this.c = 0;
1743             this.d = 1;
1744             this.e = 0;
1745             this.f = 0;
1746         }
1747     }
1748     (function (matrixproto) {
1749         
1750         matrixproto.add = function (a, b, c, d, e, f) {
1751             var out = [[], [], []],
1752                 m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]],
1753                 matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
1754                 x, y, z, res;
1755
1756             if (a && a instanceof Matrix) {
1757                 matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]];
1758             }
1759
1760             for (x = 0; x < 3; x++) {
1761                 for (y = 0; y < 3; y++) {
1762                     res = 0;
1763                     for (z = 0; z < 3; z++) {
1764                         res += m[x][z] * matrix[z][y];
1765                     }
1766                     out[x][y] = res;
1767                 }
1768             }
1769             this.a = out[0][0];
1770             this.b = out[1][0];
1771             this.c = out[0][1];
1772             this.d = out[1][1];
1773             this.e = out[0][2];
1774             this.f = out[1][2];
1775         };
1776         
1777         matrixproto.invert = function () {
1778             var me = this,
1779                 x = me.a * me.d - me.b * me.c;
1780             return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x);
1781         };
1782         
1783         matrixproto.clone = function () {
1784             return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
1785         };
1786         
1787         matrixproto.translate = function (x, y) {
1788             this.add(1, 0, 0, 1, x, y);
1789         };
1790         
1791         matrixproto.scale = function (x, y, cx, cy) {
1792             y == null && (y = x);
1793             (cx || cy) && this.add(1, 0, 0, 1, cx, cy);
1794             this.add(x, 0, 0, y, 0, 0);
1795             (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy);
1796         };
1797         
1798         matrixproto.rotate = function (a, x, y) {
1799             a = R.rad(a);
1800             x = x || 0;
1801             y = y || 0;
1802             var cos = +math.cos(a).toFixed(9),
1803                 sin = +math.sin(a).toFixed(9);
1804             this.add(cos, sin, -sin, cos, x, y);
1805             this.add(1, 0, 0, 1, -x, -y);
1806         };
1807         
1808         matrixproto.x = function (x, y) {
1809             return x * this.a + y * this.c + this.e;
1810         };
1811         
1812         matrixproto.y = function (x, y) {
1813             return x * this.b + y * this.d + this.f;
1814         };
1815         matrixproto.get = function (i) {
1816             return +this[Str.fromCharCode(97 + i)].toFixed(4);
1817         };
1818         matrixproto.toString = function () {
1819             return R.svg ?
1820                 "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" :
1821                 [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join();
1822         };
1823         matrixproto.toFilter = function () {
1824             return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) +
1825                 ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) +
1826                 ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')";
1827         };
1828         matrixproto.offset = function () {
1829             return [this.e.toFixed(4), this.f.toFixed(4)];
1830         };
1831         function norm(a) {
1832             return a[0] * a[0] + a[1] * a[1];
1833         }
1834         function normalize(a) {
1835             var mag = math.sqrt(norm(a));
1836             a[0] && (a[0] /= mag);
1837             a[1] && (a[1] /= mag);
1838         }
1839         
1840         matrixproto.split = function () {
1841             var out = {};
1842             // translation
1843             out.dx = this.e;
1844             out.dy = this.f;
1845
1846             // scale and shear
1847             var row = [[this.a, this.c], [this.b, this.d]];
1848             out.scalex = math.sqrt(norm(row[0]));
1849             normalize(row[0]);
1850
1851             out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
1852             row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
1853
1854             out.scaley = math.sqrt(norm(row[1]));
1855             normalize(row[1]);
1856             out.shear /= out.scaley;
1857
1858             // rotation
1859             var sin = -row[0][1],
1860                 cos = row[1][1];
1861             if (cos < 0) {
1862                 out.rotate = R.deg(math.acos(cos));
1863                 if (sin < 0) {
1864                     out.rotate = 360 - out.rotate;
1865                 }
1866             } else {
1867                 out.rotate = R.deg(math.asin(sin));
1868             }
1869
1870             out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
1871             out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate;
1872             out.noRotation = !+out.shear.toFixed(9) && !out.rotate;
1873             return out;
1874         };
1875         
1876         matrixproto.toTransformString = function (shorter) {
1877             var s = shorter || this[split]();
1878             if (s.isSimple) {
1879                 return "t" + [s.dx, s.dy] + "s" + [s.scalex, s.scaley, 0, 0] + "r" + [s.rotate, 0, 0];
1880             } else {
1881                 return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
1882             }
1883         };
1884     })(Matrix.prototype);
1885
1886     // WebKit rendering bug workaround method
1887     var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/);
1888     if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") ||
1889         (navigator.vendor == "Google Inc." && version && version[1] < 8)) {
1890         
1891         paperproto.safari = function () {
1892             var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"});
1893             setTimeout(function () {rect.remove();});
1894         };
1895     } else {
1896         paperproto.safari = fun;
1897     }
1898  
1899     var preventDefault = function () {
1900         this.returnValue = false;
1901     },
1902     preventTouch = function () {
1903         return this.originalEvent.preventDefault();
1904     },
1905     stopPropagation = function () {
1906         this.cancelBubble = true;
1907     },
1908     stopTouch = function () {
1909         return this.originalEvent.stopPropagation();
1910     },
1911     addEvent = (function () {
1912         if (g.doc.addEventListener) {
1913             return function (obj, type, fn, element) {
1914                 var realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
1915                     f = function (e) {
1916                         var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
1917                             scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
1918                             x = e.clientX + scrollX,
1919                             y = e.clientY + scrollY;
1920                     if (supportsTouch && touchMap[has](type)) {
1921                         for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
1922                             if (e.targetTouches[i].target == obj) {
1923                                 var olde = e;
1924                                 e = e.targetTouches[i];
1925                                 e.originalEvent = olde;
1926                                 e.preventDefault = preventTouch;
1927                                 e.stopPropagation = stopTouch;
1928                                 break;
1929                             }
1930                         }
1931                     }
1932                     return fn.call(element, e, x, y);
1933                 };
1934                 obj.addEventListener(realName, f, false);
1935                 return function () {
1936                     obj.removeEventListener(realName, f, false);
1937                     return true;
1938                 };
1939             };
1940         } else if (g.doc.attachEvent) {
1941             return function (obj, type, fn, element) {
1942                 var f = function (e) {
1943                     e = e || g.win.event;
1944                     var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
1945                         scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
1946                         x = e.clientX + scrollX,
1947                         y = e.clientY + scrollY;
1948                     e.preventDefault = e.preventDefault || preventDefault;
1949                     e.stopPropagation = e.stopPropagation || stopPropagation;
1950                     return fn.call(element, e, x, y);
1951                 };
1952                 obj.attachEvent("on" + type, f);
1953                 var detacher = function () {
1954                     obj.detachEvent("on" + type, f);
1955                     return true;
1956                 };
1957                 return detacher;
1958             };
1959         }
1960     })(),
1961     drag = [],
1962     dragMove = function (e) {
1963         var x = e.clientX,
1964             y = e.clientY,
1965             scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
1966             scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
1967             dragi,
1968             j = drag.length;
1969         while (j--) {
1970             dragi = drag[j];
1971             if (supportsTouch) {
1972                 var i = e.touches.length,
1973                     touch;
1974                 while (i--) {
1975                     touch = e.touches[i];
1976                     if (touch.identifier == dragi.el._drag.id) {
1977                         x = touch.clientX;
1978                         y = touch.clientY;
1979                         (e.originalEvent ? e.originalEvent : e).preventDefault();
1980                         break;
1981                     }
1982                 }
1983             } else {
1984                 e.preventDefault();
1985             }
1986             var node = dragi.el.node,
1987                 o,
1988                 next = node.nextSibling,
1989                 parent = node.parentNode,
1990                 display = node.style.display;
1991             g.win.opera && parent.removeChild(node);
1992             node.style.display = "none";
1993             o = dragi.el.paper.getElementByPoint(x, y);
1994             node.style.display = display;
1995             g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
1996             o && eve("drag.over." + dragi.el.id, dragi.el, o);
1997             x += scrollX;
1998             y += scrollY;
1999             eve("drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
2000         }
2001     },
2002     dragUp = function (e) {
2003         R.unmousemove(dragMove).unmouseup(dragUp);
2004         var i = drag.length,
2005             dragi;
2006         while (i--) {
2007             dragi = drag[i];
2008             dragi.el._drag = {};
2009             eve("drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
2010         }
2011         drag = [];
2012     },
2013     
2014     elproto = R.el = {};
2015     
2016     
2017     
2018     
2019     
2020     
2021     
2022     
2023     
2024     
2025     
2026     
2027     
2028     
2029     
2030     
2031     
2032     
2033     
2034     
2035     
2036     
2037     
2038     
2039     
2040     
2041     
2042     
2043     
2044     
2045     
2046     
2047     for (var i = events.length; i--;) {
2048         (function (eventName) {
2049             R[eventName] = elproto[eventName] = function (fn, scope) {
2050                 if (R.is(fn, "function")) {
2051                     this.events = this.events || [];
2052                     this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)});
2053                 }
2054                 return this;
2055             };
2056             R["un" + eventName] = elproto["un" + eventName] = function (fn) {
2057                 var events = this.events,
2058                     l = events.length;
2059                 while (l--) if (events[l].name == eventName && events[l].f == fn) {
2060                     events[l].unbind();
2061                     events.splice(l, 1);
2062                     !events.length && delete this.events;
2063                     return this;
2064                 }
2065                 return this;
2066             };
2067         })(events[i]);
2068     }
2069     
2070     
2071     elproto.data = function (key, value) {
2072         var data = eldata[this.id] = eldata[this.id] || {};
2073         if (arguments.length == 1) {
2074             if (R.is(key, "object")) {
2075                 for (var i in key) if (key[has](i)) {
2076                     this.data(i, key[i]);
2077                 }
2078                 return this;
2079             }
2080             eve("data.get." + this.id, this, data[key], key);
2081             return data[key];
2082         }
2083         data[key] = value;
2084         eve("data.set." + this.id, this, value, key);
2085         return this;
2086     };
2087     
2088     elproto.removeData = function (key) {
2089         if (key == null) {
2090             eldata[this.id] = {};
2091         } else {
2092             eldata[this.id] && delete eldata[this.id][key];
2093         }
2094         return this;
2095     };
2096     
2097     elproto.hover = function (f_in, f_out, scope_in, scope_out) {
2098         return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
2099     };
2100     
2101     elproto.unhover = function (f_in, f_out) {
2102         return this.unmouseover(f_in).unmouseout(f_out);
2103     };
2104     
2105     elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
2106         function start(e) {
2107             (e.originalEvent || e).preventDefault();
2108             var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
2109                 scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
2110             this._drag.x = e.clientX + scrollX;
2111             this._drag.y = e.clientY + scrollY;
2112             this._drag.id = e.identifier;
2113             !drag.length && R.mousemove(dragMove).mouseup(dragUp);
2114             drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope});
2115             onstart && eve.on("drag.start." + this.id, onstart);
2116             onmove && eve.on("drag.move." + this.id, onmove);
2117             onend && eve.on("drag.end." + this.id, onend);
2118             eve("drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e);
2119         }
2120         this._drag = {};
2121         this.mousedown(start);
2122         return this;
2123     };
2124     
2125     elproto.onDragOver = function (f) {
2126         f ? eve.on("drag.over." + this.id, f) : eve.unbind("drag.over." + this.id);
2127     };
2128     
2129     elproto.undrag = function () {
2130         var i = drag.length;
2131         while (i--) if (drag[i].el == this) {
2132             R.unmousedown(drag[i].start);
2133             drag.splice(i++, 1);
2134             eve.unbind("drag.*." + this.id);
2135         }
2136         !drag.length && R.unmousemove(dragMove).unmouseup(dragUp);
2137     };
2138     
2139     paperproto.circle = function (x, y, r) {
2140         var out = R._engine.circle(this, x || 0, y || 0, r || 0);
2141         this.__set__ && this.__set__.push(out);
2142         return out;
2143     };
2144     
2145     paperproto.rect = function (x, y, w, h, r) {
2146         var out = R._engine.rect(this, x || 0, y || 0, w || 0, h || 0, r || 0);
2147         this.__set__ && this.__set__.push(out);
2148         return out;
2149     };
2150     
2151     paperproto.ellipse = function (x, y, rx, ry) {
2152         var out = R._engine.ellipse(this, x || 0, y || 0, rx || 0, ry || 0);
2153         this.__set__ && this.__set__.push(out);
2154         return out;
2155     };
2156     
2157     paperproto.path = function (pathString) {
2158         pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E);
2159         var out = R._engine.path(R.format[apply](R, arguments), this);
2160         this.__set__ && this.__set__.push(out);
2161         return out;
2162     };
2163     
2164     paperproto.image = function (src, x, y, w, h) {
2165         var out = R._engine.image(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0);
2166         this.__set__ && this.__set__.push(out);
2167         return out;
2168     };
2169     
2170     paperproto.text = function (x, y, text) {
2171         var out = R._engine.text(this, x || 0, y || 0, Str(text));
2172         this.__set__ && this.__set__.push(out);
2173         return out;
2174     };
2175     
2176     paperproto.set = function (itemsArray) {
2177         !R.is(itemsArray, "array") && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length));
2178         var out = new Set(itemsArray);
2179         this.__set__ && this.__set__.push(out);
2180         return out;
2181     };
2182     
2183     paperproto.setStart = function (set) {
2184         this.__set__ = set || this.set();
2185     };
2186     
2187     paperproto.setFinish = function (set) {
2188         var out = this.__set__;
2189         delete this.__set__;
2190         return out;
2191     };
2192     
2193     paperproto.setSize = function (width, height) {
2194         return R._engine.setSize.call(this, width, height);
2195     };
2196     
2197     paperproto.setViewBox = function (x, y, w, h, fit) {
2198         return R._engine.setViewBox.call(this, x, y, w, h, fit);
2199     };
2200     
2201     
2202     paperproto.top = paperproto.bottom = null;
2203     
2204     paperproto.raphael = R;
2205     var getOffset = function (elem) {
2206         var box = elem.getBoundingClientRect(),
2207             doc = elem.ownerDocument,
2208             body = doc.body,
2209             docElem = doc.documentElement,
2210             clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
2211             top  = box.top  + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop,
2212             left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
2213         return {
2214             y: top,
2215             x: left
2216         };
2217     };
2218     
2219     paperproto.getElementByPoint = function (x, y) {
2220         var paper = this,
2221             svg = paper.canvas,
2222             target = g.doc.elementFromPoint(x, y);
2223         if (g.win.opera && target.tagName == "svg") {
2224             var so = getOffset(svg),
2225                 sr = svg.createSVGRect();
2226             sr.x = x - so.x;
2227             sr.y = y - so.y;
2228             sr.width = sr.height = 1;
2229             var hits = svg.getIntersectionList(sr, null);
2230             if (hits.length) {
2231                 target = hits[hits.length - 1];
2232             }
2233         }
2234         if (!target) {
2235             return null;
2236         }
2237         while (target.parentNode && target != svg.parentNode && !target.raphael) {
2238             target = target.parentNode;
2239         }
2240         target == paper.canvas.parentNode && (target = svg);
2241         target = target && target.raphael ? paper.getById(target.raphaelid) : null;
2242         return target;
2243     };
2244     
2245     paperproto.getById = function (id) {
2246         var bot = this.bottom;
2247         while (bot) {
2248             if (bot.id == id) {
2249                 return bot;
2250             }
2251             bot = bot.next;
2252         }
2253         return null;
2254     };
2255     
2256     paperproto.forEach = function (callback, thisArg) {
2257         var bot = this.bottom;
2258         while (bot) {
2259             if (callback.call(thisArg, bot) === false) {
2260                 return this;
2261             }
2262             bot = bot.next;
2263         }
2264         return this;
2265     };
2266     function x_y() {
2267         return this.x + S + this.y;
2268     }
2269     function x_y_w_h() {
2270         return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
2271     }
2272     
2273     elproto.getBBox = function (isWithoutTransform) {
2274         if (this.removed) {
2275             return {};
2276         }
2277         var _ = this._;
2278         if (isWithoutTransform) {
2279             if (_.dirty || !_.bboxwt) {
2280                 this.realPath = getPath[this.type](this);
2281                 _.bboxwt = pathDimensions(this.realPath);
2282                 _.bboxwt.toString = x_y_w_h;
2283                 _.dirty = 0;
2284             }
2285             return _.bboxwt;
2286         }
2287         if (_.dirty || _.dirtyT || !_.bbox) {
2288             if (_.dirty || !this.realPath) {
2289                 _.bboxwt = 0;
2290                 this.realPath = getPath[this.type](this);
2291             }
2292             _.bbox = pathDimensions(mapPath(this.realPath, this.matrix));
2293             _.bbox.toString = x_y_w_h;
2294             _.dirty = _.dirtyT = 0;
2295         }
2296         return _.bbox;
2297     };
2298     
2299     elproto.clone = function () {
2300         if (this.removed) {
2301             return null;
2302         }
2303         var out = this.paper[this.type]().attr(this.attr());
2304         this.__set__ && this.__set__.push(out);
2305         return out;
2306     };
2307     
2308     elproto.glow = function (glow) {
2309         if (this.type == "text") {
2310             return null;
2311         }
2312         glow = glow || {};
2313         var s = {
2314             width: (glow.width || 10) + (+this.attr("stroke-width") || 1),
2315             fill: glow.fill || false,
2316             opacity: glow.opacity || .5,
2317             offsetx: glow.offsetx || 0,
2318             offsety: glow.offsety || 0,
2319             color: glow.color || "#000"
2320         },
2321             c = s.width / 2,
2322             r = this.paper,
2323             out = r.set(),
2324             path = this.realPath || getPath[this.type](this);
2325         path = this.matrix ? mapPath(path, this.matrix) : path;
2326         for (var i = 1; i < c + 1; i++) {
2327             out.push(r.path(path).attr({
2328                 stroke: s.color,
2329                 fill: s.fill ? s.color : "none",
2330                 "stroke-linejoin": "round",
2331                 "stroke-linecap": "round",
2332                 "stroke-width": +(s.width / c * i).toFixed(3),
2333                 opacity: +(s.opacity / c).toFixed(3)
2334             }));
2335         }
2336         return out.insertBefore(this).translate(s.offsetx, s.offsety);
2337     };
2338     var curveslengths = {},
2339     getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {
2340         var len = 0,
2341             precision = 100,
2342             name = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y].join(),
2343             cache = curveslengths[name],
2344             old, dot;
2345         !cache && (curveslengths[name] = cache = {data: []});
2346         cache.timer && clearTimeout(cache.timer);
2347         cache.timer = setTimeout(function () {delete curveslengths[name];}, 2e3);
2348         if (length != null && !cache.precision) {
2349             var total = getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
2350             cache.precision = ~~total * 10;
2351             cache.data = [];
2352         }
2353         precision = cache.precision || precision;
2354         for (var i = 0; i < precision + 1; i++) {
2355             if (cache.data[i * precision]) {
2356                 dot = cache.data[i * precision];
2357             } else {
2358                 dot = R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i / precision);
2359                 cache.data[i * precision] = dot;
2360             }
2361             i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5));
2362             if (length != null && len >= length) {
2363                 return dot;
2364             }
2365             old = dot;
2366         }
2367         if (length == null) {
2368             return len;
2369         }
2370     },
2371     getLengthFactory = function (istotal, subpath) {
2372         return function (path, length, onlystart) {
2373             path = path2curve(path);
2374             var x, y, p, l, sp = "", subpaths = {}, point,
2375                 len = 0;
2376             for (var i = 0, ii = path.length; i < ii; i++) {
2377                 p = path[i];
2378                 if (p[0] == "M") {
2379                     x = +p[1];
2380                     y = +p[2];
2381                 } else {
2382                     l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
2383                     if (len + l > length) {
2384                         if (subpath && !subpaths.start) {
2385                             point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
2386                             sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y];
2387                             if (onlystart) {return sp;}
2388                             subpaths.start = sp;
2389                             sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join();
2390                             len += l;
2391                             x = +p[5];
2392                             y = +p[6];
2393                             continue;
2394                         }
2395                         if (!istotal && !subpath) {
2396                             point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
2397                             return {x: point.x, y: point.y, alpha: point.alpha};
2398                         }
2399                     }
2400                     len += l;
2401                     x = +p[5];
2402                     y = +p[6];
2403                 }
2404                 sp += p.shift() + p;
2405             }
2406             subpaths.end = sp;
2407             point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
2408             point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha});
2409             return point;
2410         };
2411     };
2412     var getTotalLength = getLengthFactory(1),
2413         getPointAtLength = getLengthFactory(),
2414         getSubpathsAtLength = getLengthFactory(0, 1);
2415     
2416     R.getTotalLength = getTotalLength;
2417     
2418     R.getPointAtLength = getPointAtLength;
2419     
2420     R.getSubpath = function (path, from, to) {
2421         if (this.getTotalLength(path) - to < 1e-6) {
2422             return getSubpathsAtLength(path, from).end;
2423         }
2424         var a = getSubpathsAtLength(path, to, 1);
2425         return from ? getSubpathsAtLength(a, from).end : a;
2426     };
2427     
2428     elproto.getTotalLength = function () {
2429         if (this.type != "path") {return;}
2430         if (this.node.getTotalLength) {
2431             return this.node.getTotalLength();
2432         }
2433         return getTotalLength(this.attrs.path);
2434     };
2435     
2436     elproto.getPointAtLength = function (length) {
2437         if (this.type != "path") {return;}
2438         return getPointAtLength(this.attrs.path, length);
2439     };
2440     
2441     elproto.getSubpath = function (from, to) {
2442         if (this.type != "path") {return;}
2443         return R.getSubpath(this.attrs.path, from, to);
2444     };
2445     
2446     var ef = R.easing_formulas = {
2447         linear: function (n) {
2448             return n;
2449         },
2450         "<": function (n) {
2451             return pow(n, 1.7);
2452         },
2453         ">": function (n) {
2454             return pow(n, .48);
2455         },
2456         "<>": function (n) {
2457             var q = .48 - n / 1.04,
2458                 Q = math.sqrt(.1734 + q * q),
2459                 x = Q - q,
2460                 X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1),
2461                 y = -Q - q,
2462                 Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1),
2463                 t = X + Y + .5;
2464             return (1 - t) * 3 * t * t + t * t * t;
2465         },
2466         backIn: function (n) {
2467             var s = 1.70158;
2468             return n * n * ((s + 1) * n - s);
2469         },
2470         backOut: function (n) {
2471             n = n - 1;
2472             var s = 1.70158;
2473             return n * n * ((s + 1) * n + s) + 1;
2474         },
2475         elastic: function (n) {
2476             if (n == !!n) {
2477                 return n;
2478             }
2479             return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1;
2480         },
2481         bounce: function (n) {
2482             var s = 7.5625,
2483                 p = 2.75,
2484                 l;
2485             if (n < (1 / p)) {
2486                 l = s * n * n;
2487             } else {
2488                 if (n < (2 / p)) {
2489                     n -= (1.5 / p);
2490                     l = s * n * n + .75;
2491                 } else {
2492                     if (n < (2.5 / p)) {
2493                         n -= (2.25 / p);
2494                         l = s * n * n + .9375;
2495                     } else {
2496                         n -= (2.625 / p);
2497                         l = s * n * n + .984375;
2498                     }
2499                 }
2500             }
2501             return l;
2502         }
2503     };
2504     ef.easeIn = ef["ease-in"] = ef["<"];
2505     ef.easeOut = ef["ease-out"] = ef[">"];
2506     ef.easeInOut = ef["ease-in-out"] = ef["<>"];
2507     ef["back-in"] = ef.backIn;
2508     ef["back-out"] = ef.backOut;
2509
2510     var animationElements = [],
2511         requestAnimFrame = window.requestAnimationFrame       ||
2512                            window.webkitRequestAnimationFrame ||
2513                            window.mozRequestAnimationFrame    ||
2514                            window.oRequestAnimationFrame      ||
2515                            window.msRequestAnimationFrame     ||
2516                            function (callback) {
2517                                setTimeout(callback, 16);
2518                            },
2519         animation = function () {
2520             var Now = +new Date,
2521                 l = 0;
2522             for (; l < animationElements.length; l++) {
2523                 var e = animationElements[l];
2524                 if (e.el.removed || e.paused) {
2525                     continue;
2526                 }
2527                 var time = Now - e.start,
2528                     ms = e.ms,
2529                     easing = e.easing,
2530                     from = e.from,
2531                     diff = e.diff,
2532                     to = e.to,
2533                     t = e.t,
2534                     that = e.el,
2535                     set = {},
2536                     now,
2537                     init = {},
2538                     key;
2539                 if (e.initstatus) {
2540                     time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms;
2541                     e.status = e.initstatus;
2542                     delete e.initstatus;
2543                     e.stop && animationElements.splice(l--, 1);
2544                 } else {
2545                     e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top;
2546                 }
2547                 if (time < 0) {
2548                     continue;
2549                 }
2550                 if (time < ms) {
2551                     var pos = easing(time / ms);
2552                     for (var attr in from) if (from[has](attr)) {
2553                         switch (availableAnimAttrs[attr]) {
2554                             case nu:
2555                                 now = +from[attr] + pos * ms * diff[attr];
2556                                 break;
2557                             case "colour":
2558                                 now = "rgb(" + [
2559                                     upto255(round(from[attr].r + pos * ms * diff[attr].r)),
2560                                     upto255(round(from[attr].g + pos * ms * diff[attr].g)),
2561                                     upto255(round(from[attr].b + pos * ms * diff[attr].b))
2562                                 ].join(",") + ")";
2563                                 break;
2564                             case "path":
2565                                 now = [];
2566                                 for (var i = 0, ii = from[attr].length; i < ii; i++) {
2567                                     now[i] = [from[attr][i][0]];
2568                                     for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
2569                                         now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j];
2570                                     }
2571                                     now[i] = now[i].join(S);
2572                                 }
2573                                 now = now.join(S);
2574                                 break;
2575                             case "transform":
2576                                 if (diff[attr].real) {
2577                                     now = [];
2578                                     for (i = 0, ii = from[attr].length; i < ii; i++) {
2579                                         now[i] = [from[attr][i][0]];
2580                                         for (j = 1, jj = from[attr][i].length; j < jj; j++) {
2581                                             now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j];
2582                                         }
2583                                     }
2584                                 } else {
2585                                     var get = function (i) {
2586                                         return +from[attr][i] + pos * ms * diff[attr][i];
2587                                     };
2588                                     // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]];
2589                                     now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]];
2590                                 }
2591                                 break;
2592                             case "csv":
2593                                 if (attr == "clip-rect") {
2594                                     now = [];
2595                                     i = 4;
2596                                     while (i--) {
2597                                         now[i] = +from[attr][i] + pos * ms * diff[attr][i];
2598                                     }
2599                                 }
2600                                 break;
2601                             default:
2602                                 var from2 = [][concat](from[attr]);
2603                                 now = [];
2604                                 i = that.paper.customAttributes[attr].length;
2605                                 while (i--) {
2606                                     now[i] = +from2[i] + pos * ms * diff[attr][i];
2607                                 }
2608                                 break;
2609                         }
2610                         set[attr] = now;
2611                     }
2612                     that.attr(set);
2613                     (function (id, that, anim) {
2614                         setTimeout(function () {
2615                             eve("anim.frame." + id, that, anim);
2616                         });
2617                     })(that.id, that, e.anim);
2618                 } else {
2619                     (function(f, el, a) {
2620                         setTimeout(function() {
2621                             eve("anim.frame." + el.id, el, a);
2622                             eve("anim.finish." + el.id, el, a);
2623                             R.is(f, "function") && f.call(el);
2624                         });
2625                     })(e.callback, that, e.anim);
2626                     that.attr(to);
2627                     animationElements.splice(l--, 1);
2628                     if (e.repeat > 1 && !e.next) {
2629                         for (key in to) if (to[has](key)) {
2630                             init[key] = e.totalOrigin[key];
2631                         }
2632                         e.el.attr(init);
2633                         runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1);
2634                     }
2635                     if (e.next && !e.stop) {
2636                         runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat);
2637                     }
2638                 }
2639             }
2640             R.svg && that && that.paper && that.paper.safari();
2641             animationElements.length && requestAnimFrame(animation);
2642         },
2643         upto255 = function (color) {
2644             return color > 255 ? 255 : color < 0 ? 0 : color;
2645         };
2646     
2647     elproto.animateWith = function (element, anim, params, ms, easing, callback) {
2648         var a = params ? R.animation(params, ms, easing, callback) : anim;
2649             status = element.status(anim);
2650         return this.animate(a).status(a, status * anim.ms / a.ms);
2651     };
2652     function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) {
2653         var cx = 3 * p1x,
2654             bx = 3 * (p2x - p1x) - cx,
2655             ax = 1 - cx - bx,
2656             cy = 3 * p1y,
2657             by = 3 * (p2y - p1y) - cy,
2658             ay = 1 - cy - by;
2659         function sampleCurveX(t) {
2660             return ((ax * t + bx) * t + cx) * t;
2661         }
2662         function solve(x, epsilon) {
2663             var t = solveCurveX(x, epsilon);
2664             return ((ay * t + by) * t + cy) * t;
2665         }
2666         function solveCurveX(x, epsilon) {
2667             var t0, t1, t2, x2, d2, i;
2668             for(t2 = x, i = 0; i < 8; i++) {
2669                 x2 = sampleCurveX(t2) - x;
2670                 if (abs(x2) < epsilon) {
2671                     return t2;
2672                 }
2673                 d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
2674                 if (abs(d2) < 1e-6) {
2675                     break;
2676                 }
2677                 t2 = t2 - x2 / d2;
2678             }
2679             t0 = 0;
2680             t1 = 1;
2681             t2 = x;
2682             if (t2 < t0) {
2683                 return t0;
2684             }
2685             if (t2 > t1) {
2686                 return t1;
2687             }
2688             while (t0 < t1) {
2689                 x2 = sampleCurveX(t2);
2690                 if (abs(x2 - x) < epsilon) {
2691                     return t2;
2692                 }
2693                 if (x > x2) {
2694                     t0 = t2;
2695                 } else {
2696                     t1 = t2;
2697                 }
2698                 t2 = (t1 - t0) / 2 + t0;
2699             }
2700             return t2;
2701         }
2702         return solve(t, 1 / (200 * duration));
2703     }
2704     elproto.onAnimation = function (f) {
2705         f ? eve.on("anim.frame." + this.id, f) : eve.unbind("anim.frame." + this.id);
2706         return this;
2707     };
2708     function Animation(anim, ms) {
2709         var percents = [],
2710             newAnim = {};
2711         this.ms = ms;
2712         this.times = 1;
2713         if (anim) {
2714             for (var attr in anim) if (anim[has](attr)) {
2715                 newAnim[toFloat(attr)] = anim[attr];
2716                 percents.push(toFloat(attr));
2717             }
2718             percents.sort(sortByNumber);
2719         }
2720         this.anim = newAnim;
2721         this.top = percents[percents.length - 1];
2722         this.percents = percents;
2723     }
2724     
2725     Animation.prototype.delay = function (delay) {
2726         var a = new Animation(this.anim, this.ms);
2727         a.times = this.times;
2728         a.del = +delay || 0;
2729         return a;
2730     };
2731     
2732     Animation.prototype.repeat = function (times) { 
2733         var a = new Animation(this.anim, this.ms);
2734         a.del = this.del;
2735         a.times = math.floor(mmax(times, 0)) || 1;
2736         return a;
2737     };
2738     function runAnimation(anim, element, percent, status, totalOrigin, times) {
2739         percent = toFloat(percent);
2740         var params,
2741             isInAnim,
2742             isInAnimSet,
2743             percents = [],
2744             next,
2745             prev,
2746             timestamp,
2747             ms = anim.ms,
2748             from = {},
2749             to = {},
2750             diff = {};
2751         if (status) {
2752             for (i = 0, ii = animationElements.length; i < ii; i++) {
2753                 var e = animationElements[i];
2754                 if (e.el.id == element.id && e.anim == anim) {
2755                     if (e.percent != percent) {
2756                         animationElements.splice(i, 1);
2757                         isInAnimSet = 1;
2758                     } else {
2759                         isInAnim = e;
2760                     }
2761                     element.attr(e.totalOrigin);
2762                     break;
2763                 }
2764             }
2765         } else {
2766             status = +to; // NaN
2767         }
2768         for (var i = 0, ii = anim.percents.length; i < ii; i++) {
2769             if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) {
2770                 percent = anim.percents[i];
2771                 prev = anim.percents[i - 1] || 0;
2772                 ms = ms / anim.top * (percent - prev);
2773                 next = anim.percents[i + 1];
2774                 params = anim.anim[percent];
2775                 break;
2776             } else if (status) {
2777                 element.attr(anim.anim[anim.percents[i]]);
2778             }
2779         }
2780         if (!params) {
2781             return;
2782         }
2783         if (!isInAnim) {
2784             for (attr in params) if (params[has](attr)) {
2785                 if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) {
2786                     from[attr] = element.attr(attr);
2787                     (from[attr] == null) && (from[attr] = availableAttrs[attr]);
2788                     to[attr] = params[attr];
2789                     switch (availableAnimAttrs[attr]) {
2790                         case nu:
2791                             diff[attr] = (to[attr] - from[attr]) / ms;
2792                             break;
2793                         case "colour":
2794                             from[attr] = R.getRGB(from[attr]);
2795                             var toColour = R.getRGB(to[attr]);
2796                             diff[attr] = {
2797                                 r: (toColour.r - from[attr].r) / ms,
2798                                 g: (toColour.g - from[attr].g) / ms,
2799                                 b: (toColour.b - from[attr].b) / ms
2800                             };
2801                             break;
2802                         case "path":
2803                             var pathes = path2curve(from[attr], to[attr]),
2804                                 toPath = pathes[1];
2805                             from[attr] = pathes[0];
2806                             diff[attr] = [];
2807                             for (i = 0, ii = from[attr].length; i < ii; i++) {
2808                                 diff[attr][i] = [0];
2809                                 for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
2810                                     diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms;
2811                                 }
2812                             }
2813                             break;
2814                         case "transform":
2815                             var _ = element._,
2816                                 eq = equaliseTransform(_[attr], to[attr]);
2817                             if (eq) {
2818                                 from[attr] = eq.from;
2819                                 to[attr] = eq.to;
2820                                 diff[attr] = [];
2821                                 diff[attr].real = true;
2822                                 for (i = 0, ii = from[attr].length; i < ii; i++) {
2823                                     diff[attr][i] = [from[attr][i][0]];
2824                                     for (j = 1, jj = from[attr][i].length; j < jj; j++) {
2825                                         diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms;
2826                                     }
2827                                 }
2828                             } else {
2829                                 var m = (element.matrix || new Matrix),
2830                                     to2 = {
2831                                         _: {transform: _.transform},
2832                                         getBBox: function () {
2833                                             return element.getBBox(1);
2834                                         }
2835                                     };
2836                                 from[attr] = [
2837                                     m.a,
2838                                     m.b,
2839                                     m.c,
2840                                     m.d,
2841                                     m.e,
2842                                     m.f
2843                                 ];
2844                                 extractTransform(to2, to[attr]);
2845                                 to[attr] = to2._.transform;
2846                                 diff[attr] = [
2847                                     (to2.matrix.a - m.a) / ms,
2848                                     (to2.matrix.b - m.b) / ms,
2849                                     (to2.matrix.c - m.c) / ms,
2850                                     (to2.matrix.d - m.d) / ms,
2851                                     (to2.matrix.e - m.e) / ms,
2852                                     (to2.matrix.e - m.f) / ms
2853                                 ];
2854                                 // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy];
2855                                 // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }};
2856                                 // extractTransform(to2, to[attr]);
2857                                 // diff[attr] = [
2858                                 //     (to2._.sx - _.sx) / ms,
2859                                 //     (to2._.sy - _.sy) / ms,
2860                                 //     (to2._.deg - _.deg) / ms,
2861                                 //     (to2._.dx - _.dx) / ms,
2862                                 //     (to2._.dy - _.dy) / ms
2863                                 // ];
2864                             }
2865                             break;
2866                         case "csv":
2867                             var values = Str(params[attr])[split](separator),
2868                                 from2 = Str(from[attr])[split](separator);
2869                             if (attr == "clip-rect") {
2870                                 from[attr] = from2;
2871                                 diff[attr] = [];
2872                                 i = from2.length;
2873                                 while (i--) {
2874                                     diff[attr][i] = (values[i] - from[attr][i]) / ms;
2875                                 }
2876                             }
2877                             to[attr] = values;
2878                             break;
2879                         default:
2880                             values = [][concat](params[attr]);
2881                             from2 = [][concat](from[attr]);
2882                             diff[attr] = [];
2883                             i = element.paper.customAttributes[attr].length;
2884                             while (i--) {
2885                                 diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms;
2886                             }
2887                             break;
2888                     }
2889                 }
2890             }
2891             var easing = params.easing,
2892                 easyeasy = R.easing_formulas[easing];
2893             if (!easyeasy) {
2894                 easyeasy = Str(easing).match(bezierrg);
2895                 if (easyeasy && easyeasy.length == 5) {
2896                     var curve = easyeasy;
2897                     easyeasy = function (t) {
2898                         return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms);
2899                     };
2900                 } else {
2901                     easyeasy = pipe;
2902                 }
2903             }
2904             timestamp = params.start || anim.start || +new Date;
2905             e = {
2906                 anim: anim,
2907                 percent: percent,
2908                 timestamp: timestamp,
2909                 start: timestamp + (anim.del || 0),
2910                 status: 0,
2911                 initstatus: status || 0,
2912                 stop: false,
2913                 ms: ms,
2914                 easing: easyeasy,
2915                 from: from,
2916                 diff: diff,
2917                 to: to,
2918                 el: element,
2919                 callback: params.callback,
2920                 prev: prev,
2921                 next: next,
2922                 repeat: times || anim.times,
2923                 origin: element.attr(),
2924                 totalOrigin: totalOrigin
2925             };
2926             animationElements.push(e);
2927             if (status && !isInAnim && !isInAnimSet) {
2928                 e.stop = true;
2929                 e.start = new Date - ms * status;
2930                 if (animationElements.length == 1) {
2931                     return animation();
2932                 }
2933             }
2934             if (isInAnimSet) {
2935                 e.start = new Date - e.ms * status;
2936             }
2937             animationElements.length == 1 && requestAnimFrame(animation);
2938         } else {
2939             isInAnim.initstatus = status;
2940             isInAnim.start = new Date - isInAnim.ms * status;
2941         }
2942         eve("anim.start." + element.id, element, anim);
2943     }
2944     
2945     R.animation = function (params, ms, easing, callback) {
2946         if (params instanceof Animation) {
2947             return params;
2948         }
2949         if (R.is(easing, "function") || !easing) {
2950             callback = callback || easing || null;
2951             easing = null;
2952         }
2953         params = Object(params);
2954         ms = +ms || 0;
2955         var p = {},
2956             json,
2957             attr;
2958         for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) {
2959             json = true;
2960             p[attr] = params[attr];
2961         }
2962         if (!json) {
2963             return new Animation(params, ms);
2964         } else {
2965             easing && (p.easing = easing);
2966             callback && (p.callback = callback);
2967             return new Animation({100: p}, ms);
2968         }
2969     };
2970     
2971     elproto.animate = function (params, ms, easing, callback) {
2972         var element = this;
2973         if (element.removed) {
2974             callback && callback.call(element);
2975             return element;
2976         }
2977         var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback);
2978         runAnimation(anim, element, anim.percents[0], null, element.attr());
2979         return element;
2980     };
2981     
2982     elproto.setTime = function (anim, value) {
2983         if (anim && value != null) {
2984             this.status(anim, mmin(value, anim.ms) / anim.ms);
2985         }
2986         return this;
2987     };
2988     
2989     elproto.status = function (anim, value) {
2990         var out = [],
2991             i = 0,
2992             len,
2993             e;
2994         if (value != null) {
2995             runAnimation(anim, this, -1, mmin(value, 1));
2996             return this;
2997         } else {
2998             len = animationElements.length;
2999             for (; i < len; i++) {
3000                 e = animationElements[i];
3001                 if (e.el.id == this.id && (!anim || e.anim == anim)) {
3002                     if (anim) {
3003                         return e.status;
3004                     }
3005                     out.push({
3006                         anim: e.anim,
3007                         status: e.status
3008                     });
3009                 }
3010             }
3011             if (anim) {
3012                 return 0;
3013             }
3014             return out;
3015         }
3016     };
3017     
3018     elproto.pause = function (anim) {
3019         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
3020             if (eve("anim.pause." + this.id, this, animationElements[i].anim) !== false) {
3021                 animationElements[i].paused = true;
3022             }
3023         }
3024         return this;
3025     };
3026     
3027     elproto.resume = function (anim) {
3028         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
3029             var e = animationElements[i];
3030             if (eve("anim.resume." + this.id, this, e.anim) !== false) {
3031                 delete e.paused;
3032                 this.status(e.anim, e.status);
3033             }
3034         }
3035         return this;
3036     };
3037     
3038     elproto.stop = function (anim) {
3039         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
3040             if (eve("anim.stop." + this.id, this, animationElements[i].anim) !== false) {
3041                 animationElements.splice(i--, 1);
3042             }
3043         }
3044         return this;
3045     };
3046     elproto.toString = function () {
3047         return "Rapha\xebl\u2019s object";
3048     };
3049
3050     // Set
3051     var Set = function (items) {
3052         this.items = [];
3053         this.length = 0;
3054         this.type = "set";
3055         if (items) {
3056             for (var i = 0, ii = items.length; i < ii; i++) {
3057                 if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) {
3058                     this[this.items.length] = this.items[this.items.length] = items[i];
3059                     this.length++;
3060                 }
3061             }
3062         }
3063     },
3064     setproto = Set.prototype;
3065     
3066     setproto.push = function () {
3067         var item,
3068             len;
3069         for (var i = 0, ii = arguments.length; i < ii; i++) {
3070             item = arguments[i];
3071             if (item && (item.constructor == elproto.constructor || item.constructor == Set)) {
3072                 len = this.items.length;
3073                 this[len] = this.items[len] = item;
3074                 this.length++;
3075             }
3076         }
3077         return this;
3078     };
3079     
3080     setproto.pop = function () {
3081         this.length && delete this[this.length--];
3082         return this.items.pop();
3083     };
3084     
3085     setproto.forEach = function (callback, thisArg) {
3086         for (var i = 0, ii = this.items.length; i < ii; i++) {
3087             if (callback.call(thisArg, this.items[i], i) === false) {
3088                 return this;
3089             }
3090         }
3091         return this;
3092     };
3093     for (var method in elproto) if (elproto[has](method)) {
3094         setproto[method] = (function (methodname) {
3095             return function () {
3096                 var arg = arguments;
3097                 return this.forEach(function (el) {
3098                     el[methodname][apply](el, arg);
3099                 });
3100             };
3101         })(method);
3102     }
3103     setproto.attr = function (name, value) {
3104         if (name && R.is(name, array) && R.is(name[0], "object")) {
3105             for (var j = 0, jj = name.length; j < jj; j++) {
3106                 this.items[j].attr(name[j]);
3107             }
3108         } else {
3109             for (var i = 0, ii = this.items.length; i < ii; i++) {
3110                 this.items[i].attr(name, value);
3111             }
3112         }
3113         return this;
3114     };
3115     
3116     setproto.clear = function () {
3117         while (this.length) {
3118             this.pop();
3119         }
3120     };
3121     
3122     setproto.splice = function (index, count, insertion) {
3123         index = index < 0 ? mmax(this.length + index, 0) : index;
3124         count = mmax(0, mmin(this.length - index, count));
3125         var tail = [],
3126             todel = [],
3127             args = [],
3128             i;
3129         for (i = 2; i < arguments.length; i++) {
3130             args.push(arguments[i]);
3131         }
3132         for (i = 0; i < count; i++) {
3133             todel.push(this[index + i]);
3134         }
3135         for (; i < this.length - index; i++) {
3136             tail.push(this[index + i]);
3137         }
3138         var arglen = args.length;
3139         for (i = 0; i < arglen + tail.length; i++) {
3140             this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen];
3141         }
3142         i = this.items.length = this.length -= count - arglen;
3143         while (this[i]) {
3144             delete this[i++];
3145         }
3146         return new Set(todel);
3147     };
3148     
3149     setproto.exclude = function (el) {
3150         for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) {
3151             this.splice(i, 1);
3152             return true;
3153         }
3154     };
3155     setproto.animate = function (params, ms, easing, callback) {
3156         (R.is(easing, "function") || !easing) && (callback = easing || null);
3157         var len = this.items.length,
3158             i = len,
3159             item,
3160             set = this,
3161             collector;
3162         if (!len) {
3163             return this;
3164         }
3165         callback && (collector = function () {
3166             !--len && callback.call(set);
3167         });
3168         easing = R.is(easing, string) ? easing : collector;
3169         var anim = R.animation(params, ms, easing, collector);
3170         item = this.items[--i].animate(anim);
3171         while (i--) {
3172             this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim);
3173         }
3174         return this;
3175     };
3176     setproto.insertAfter = function (el) {
3177         var i = this.items.length;
3178         while (i--) {
3179             this.items[i].insertAfter(el);
3180         }
3181         return this;
3182     };
3183     setproto.getBBox = function () {
3184         var x = [],
3185             y = [],
3186             w = [],
3187             h = [];
3188         for (var i = this.items.length; i--;) if (!this.items[i].removed) {
3189             var box = this.items[i].getBBox();
3190             x.push(box.x);
3191             y.push(box.y);
3192             w.push(box.x + box.width);
3193             h.push(box.y + box.height);
3194         }
3195         x = mmin[apply](0, x);
3196         y = mmin[apply](0, y);
3197         return {
3198             x: x,
3199             y: y,
3200             width: mmax[apply](0, w) - x,
3201             height: mmax[apply](0, h) - y
3202         };
3203     };
3204     setproto.clone = function (s) {
3205         s = new Set;
3206         for (var i = 0, ii = this.items.length; i < ii; i++) {
3207             s.push(this.items[i].clone());
3208         }
3209         return s;
3210     };
3211     setproto.toString = function () {
3212         return "Rapha\xebl\u2018s set";
3213     };
3214
3215     
3216     R.registerFont = function (font) {
3217         if (!font.face) {
3218             return font;
3219         }
3220         this.fonts = this.fonts || {};
3221         var fontcopy = {
3222                 w: font.w,
3223                 face: {},
3224                 glyphs: {}
3225             },
3226             family = font.face["font-family"];
3227         for (var prop in font.face) if (font.face[has](prop)) {
3228             fontcopy.face[prop] = font.face[prop];
3229         }
3230         if (this.fonts[family]) {
3231             this.fonts[family].push(fontcopy);
3232         } else {
3233             this.fonts[family] = [fontcopy];
3234         }
3235         if (!font.svg) {
3236             fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10);
3237             for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) {
3238                 var path = font.glyphs[glyph];
3239                 fontcopy.glyphs[glyph] = {
3240                     w: path.w,
3241                     k: {},
3242                     d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) {
3243                             return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M";
3244                         }) + "z"
3245                 };
3246                 if (path.k) {
3247                     for (var k in path.k) if (path[has](k)) {
3248                         fontcopy.glyphs[glyph].k[k] = path.k[k];
3249                     }
3250                 }
3251             }
3252         }
3253         return font;
3254     };
3255     
3256     paperproto.getFont = function (family, weight, style, stretch) {
3257         stretch = stretch || "normal";
3258         style = style || "normal";
3259         weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400;
3260         if (!R.fonts) {
3261             return;
3262         }
3263         var font = R.fonts[family];
3264         if (!font) {
3265             var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i");
3266             for (var fontName in R.fonts) if (R.fonts[has](fontName)) {
3267                 if (name.test(fontName)) {
3268                     font = R.fonts[fontName];
3269                     break;
3270                 }
3271             }
3272         }
3273         var thefont;
3274         if (font) {
3275             for (var i = 0, ii = font.length; i < ii; i++) {
3276                 thefont = font[i];
3277                 if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) {
3278                     break;
3279                 }
3280             }
3281         }
3282         return thefont;
3283     };
3284     
3285     paperproto.print = function (x, y, string, font, size, origin, letter_spacing) {
3286         origin = origin || "middle"; // baseline|middle
3287         letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1);
3288         var out = this.set(),
3289             letters = Str(string)[split](E),
3290             shift = 0,
3291             path = E,
3292             scale;
3293         R.is(font, string) && (font = this.getFont(font));
3294         if (font) {
3295             scale = (size || 16) / font.face["units-per-em"];
3296             var bb = font.face.bbox[split](separator),
3297                 top = +bb[0],
3298                 height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2);
3299             for (var i = 0, ii = letters.length; i < ii; i++) {
3300                 var prev = i && font.glyphs[letters[i - 1]] || {},
3301                     curr = font.glyphs[letters[i]];
3302                 shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0;
3303                 curr && curr.d && out.push(this.path(curr.d).attr({
3304                     fill: "#000",
3305                     stroke: "none",
3306                     transform: [["t", shift * scale, 0]]
3307                 }));
3308             }
3309             out.transform(["...s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]);
3310         }
3311         return out;
3312     };
3313
3314     
3315     R.format = function (token, params) {
3316         var args = R.is(params, array) ? [0][concat](params) : arguments;
3317         token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) {
3318             return args[++i] == null ? E : args[i];
3319         }));
3320         return token || E;
3321     };
3322     
3323     R.fullfill = (function () {
3324         var tokenRegex = /\{([^\}]+)\}/g,
3325             objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
3326             replacer = function (all, key, obj) {
3327                 var res = obj;
3328                 key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
3329                     name = name || quotedName;
3330                     if (res) {
3331                         if (name in res) {
3332                             res = res[name];
3333                         }
3334                         typeof res == "function" && isFunc && (res = res());
3335                     }
3336                 });
3337                 res = (res == null || res == obj ? all : res) + "";
3338                 return res;
3339             };
3340         return function (str, obj) {
3341             return String(str).replace(tokenRegex, function (all, key) {
3342                 return replacer(all, key, obj);
3343             });
3344         };
3345     })();
3346     
3347     R.ninja = function () {
3348         oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael;
3349         return R;
3350     };
3351     
3352     R.st = setproto;
3353     // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
3354     (function (doc, loaded, f) {
3355         if (doc.readyState == null && doc.addEventListener){
3356             doc.addEventListener(loaded, f = function () {
3357                 doc.removeEventListener(loaded, f, false);
3358                 doc.readyState = "complete";
3359             }, false);
3360             doc.readyState = "loading";
3361         }
3362         function isLoaded() {
3363             (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("DOMload");
3364         }
3365         isLoaded();
3366     })(document, "DOMContentLoaded");
3367
3368     oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R);
3369     
3370     eve.on("DOMload", function () {
3371         loaded = true;
3372     });
3373 })();
3374
3375 // ┌─────────────────────────────────────────────────────────────────────┐ \\
3376 // │ Raphaël 2 - JavaScript Vector Library                               │ \\
3377 // ├─────────────────────────────────────────────────────────────────────┤ \\
3378 // │ SVG Module                                                          │ \\
3379 // ├─────────────────────────────────────────────────────────────────────┤ \\
3380 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
3381 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
3382 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
3383 // └─────────────────────────────────────────────────────────────────────┘ \\
3384 window.Raphael.svg && function (R) {
3385     var has = "hasOwnProperty",
3386         Str = String,
3387         toFloat = parseFloat,
3388         toInt = parseInt,
3389         math = Math,
3390         mmax = math.max,
3391         abs = math.abs,
3392         pow = math.pow,
3393         separator = /[, ]+/,
3394         eve = R.eve,
3395         E = "",
3396         S = " ";
3397     var xlink = "http://www.w3.org/1999/xlink",
3398         markers = {
3399             block: "M5,0 0,2.5 5,5z",
3400             classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z",
3401             diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z",
3402             open: "M6,1 1,3.5 6,6",
3403             oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"
3404         },
3405         markerCounter = {};
3406     R.toString = function () {
3407         return  "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version;
3408     };
3409     var $ = function (el, attr) {
3410         if (attr) {
3411             if (typeof el == "string") {
3412                 el = $(el);
3413             }
3414             for (var key in attr) if (attr[has](key)) {
3415                 if (key.substring(0, 6) == "xlink:") {
3416                     el.setAttributeNS(xlink, key.substring(6), Str(attr[key]));
3417                 } else {
3418                     el.setAttribute(key, Str(attr[key]));
3419                 }
3420             }
3421         } else {
3422             el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el);
3423             el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)");
3424         }
3425         return el;
3426     },
3427     gradients = {},
3428     rgGrad = /^url\(#(.*)\)$/,
3429     removeGradientFill = function (node, paper) {
3430         var oid = node.getAttribute("fill");
3431         oid = oid && oid.match(rgGrad);
3432         if (oid && !--gradients[oid[1]]) {
3433             delete gradients[oid[1]];
3434             paper.defs.removeChild(R._g.doc.getElementById(oid[1]));
3435         }
3436     },
3437     addGradientFill = function (element, gradient) {
3438         var type = "linear",
3439             id = element.id + gradient,
3440             fx = .5, fy = .5,
3441             o = element.node,
3442             SVG = element.paper,
3443             s = o.style,
3444             el = R._g.doc.getElementById(id);
3445         if (!el) {
3446             gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) {
3447                 type = "radial";
3448                 if (_fx && _fy) {
3449                     fx = toFloat(_fx);
3450                     fy = toFloat(_fy);
3451                     var dir = ((fy > .5) * 2 - 1);
3452                     pow(fx - .5, 2) + pow(fy - .5, 2) > .25 &&
3453                         (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) &&
3454                         fy != .5 &&
3455                         (fy = fy.toFixed(5) - 1e-5 * dir);
3456                 }
3457                 return E;
3458             });
3459             gradient = gradient.split(/\s*\-\s*/);
3460             if (type == "linear") {
3461                 var angle = gradient.shift();
3462                 angle = -toFloat(angle);
3463                 if (isNaN(angle)) {
3464                     return null;
3465                 }
3466                 var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))],
3467                     max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1);
3468                 vector[2] *= max;
3469                 vector[3] *= max;
3470                 if (vector[2] < 0) {
3471                     vector[0] = -vector[2];
3472                     vector[2] = 0;
3473                 }
3474                 if (vector[3] < 0) {
3475                     vector[1] = -vector[3];
3476                     vector[3] = 0;
3477                 }
3478             }
3479             var dots = R._parseDots(gradient);
3480             if (!dots) {
3481                 return null;
3482             }
3483             if (element.gradient) {
3484                 SVG.defs.removeChild(element.gradient);
3485                 delete element.gradient;
3486             }
3487
3488             id = id.replace(/[\(\)\s,\xb0#]/g, "-");
3489             el = $(type + "Gradient", {id: id});
3490             element.gradient = el;
3491             $(el, type == "radial" ? {
3492                 fx: fx,
3493                 fy: fy
3494             } : {
3495                 x1: vector[0],
3496                 y1: vector[1],
3497                 x2: vector[2],
3498                 y2: vector[3],
3499                 gradientTransform: element.matrix.invert()
3500             });
3501             SVG.defs.appendChild(el);
3502             for (var i = 0, ii = dots.length; i < ii; i++) {
3503                 el.appendChild($("stop", {
3504                     offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
3505                     "stop-color": dots[i].color || "#fff"
3506                 }));
3507             }
3508         }
3509         $(o, {
3510             fill: "url(#" + id + ")",
3511             opacity: 1,
3512             "fill-opacity": 1
3513         });
3514         s.fill = E;
3515         s.opacity = 1;
3516         s.fillOpacity = 1;
3517         return 1;
3518     },
3519     updatePosition = function (o) {
3520         var bbox = o.getBBox(1);
3521         $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"});
3522     },
3523     addArrow = function (o, value, isEnd) {
3524         if (o.type == "path") {
3525             var values = Str(value).toLowerCase().split("-"),
3526                 p = o.paper,
3527                 se = isEnd ? "end" : "start",
3528                 node = o.node,
3529                 attrs = o.attrs,
3530                 stroke = attrs["stroke-width"],
3531                 i = values.length,
3532                 type = "classic",
3533                 from,
3534                 to,
3535                 dx,
3536                 refX,
3537                 attr,
3538                 w = 3,
3539                 h = 3,
3540                 t = 5;
3541             while (i--) {
3542                 switch (values[i]) {
3543                     case "block":
3544                     case "classic":
3545                     case "oval":
3546                     case "diamond":
3547                     case "open":
3548                     case "none":
3549                         type = values[i];
3550                         break;
3551                     case "wide": h = 5; break;
3552                     case "narrow": h = 2; break;
3553                     case "long": w = 5; break;
3554                     case "short": w = 2; break;
3555                 }
3556             }
3557             if (type == "open") {
3558                 w += 2;
3559                 h += 2;
3560                 t += 2;
3561                 dx = 1;
3562                 refX = isEnd ? 4 : 1;
3563                 attr = {
3564                     fill: "none",
3565                     stroke: attrs.stroke
3566                 };
3567             } else {
3568                 refX = dx = w / 2;
3569                 attr = {
3570                     fill: attrs.stroke,
3571                     stroke: "none"
3572                 };
3573             }
3574             if (o._.arrows) {
3575                 if (isEnd) {
3576                     o._.arrows.endPath && markerCounter[o._.arrows.endPath]--;
3577                     o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--;
3578                 } else {
3579                     o._.arrows.startPath && markerCounter[o._.arrows.startPath]--;
3580                     o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--;
3581                 }
3582             } else {
3583                 o._.arrows = {};
3584             }
3585             if (type != "none") {
3586                 var pathId = "raphael-marker-" + type,
3587                     markerId = "raphael-marker-" + se + type + w + h;
3588                 if (!R._g.doc.getElementById(pathId)) {
3589                     p.defs.appendChild($($("path"), {
3590                         "stroke-linecap": "round",
3591                         d: markers[type],
3592                         id: pathId
3593                     }));
3594                     markerCounter[pathId] = 1;
3595                 } else {
3596                     markerCounter[pathId]++;
3597                 }
3598                 var marker = R._g.doc.getElementById(markerId),
3599                     use;
3600                 if (!marker) {
3601                     marker = $($("marker"), {
3602                         id: markerId,
3603                         markerHeight: h,
3604                         markerWidth: w,
3605                         orient: "auto",
3606                         refX: refX,
3607                         refY: h / 2
3608                     });
3609                     use = $($("use"), {
3610                         "xlink:href": "#" + pathId,
3611                         transform: (isEnd ? " rotate(180 " + w / 2 + " " + h / 2 + ") " : S) + "scale(" + w / t + "," + h / t + ")",
3612                         "stroke-width": 1 / ((w / t + h / t) / 2)
3613                     });
3614                     marker.appendChild(use);
3615                     p.defs.appendChild(marker);
3616                     markerCounter[markerId] = 1;
3617                 } else {
3618                     markerCounter[markerId]++;
3619                     use = marker.getElementsByTagName("use")[0];
3620                 }
3621                 $(use, attr);
3622                 var delta = dx * (type != "diamond" && type != "oval");
3623                 if (isEnd) {
3624                     from = o._.arrows.startdx * stroke || 0;
3625                     to = R.getTotalLength(attrs.path) - delta * stroke;
3626                 } else {
3627                     from = delta * stroke;
3628                     to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
3629                 }
3630                 attr = {};
3631                 attr["marker-" + se] = "url(#" + markerId + ")";
3632                 if (to || from) {
3633                     attr.d = Raphael.getSubpath(attrs.path, from, to);
3634                 }
3635                 $(node, attr);
3636                 o._.arrows[se + "Path"] = pathId;
3637                 o._.arrows[se + "Marker"] = markerId;
3638                 o._.arrows[se + "dx"] = delta;
3639                 o._.arrows[se + "Type"] = type;
3640                 o._.arrows[se + "String"] = value;
3641             } else {
3642                 if (isEnd) {
3643                     from = o._.arrows.startdx * stroke || 0;
3644                     to = R.getTotalLength(attrs.path) - from;
3645                 } else {
3646                     from = 0;
3647                     to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
3648                 }
3649                 o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)});
3650                 delete o._.arrows[se + "Path"];
3651                 delete o._.arrows[se + "Marker"];
3652                 delete o._.arrows[se + "dx"];
3653                 delete o._.arrows[se + "Type"];
3654                 delete o._.arrows[se + "String"];
3655             }
3656             for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) {
3657                 var item = R._g.doc.getElementById(attr);
3658                 item && item.parentNode.removeChild(item);
3659             }
3660         }
3661     },
3662     dasharray = {
3663         "": [0],
3664         "none": [0],
3665         "-": [3, 1],
3666         ".": [1, 1],
3667         "-.": [3, 1, 1, 1],
3668         "-..": [3, 1, 1, 1, 1, 1],
3669         ". ": [1, 3],
3670         "- ": [4, 3],
3671         "--": [8, 3],
3672         "- .": [4, 3, 1, 3],
3673         "--.": [8, 3, 1, 3],
3674         "--..": [8, 3, 1, 3, 1, 3]
3675     },
3676     addDashes = function (o, value, params) {
3677         value = dasharray[Str(value).toLowerCase()];
3678         if (value) {
3679             var width = o.attrs["stroke-width"] || "1",
3680                 butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
3681                 dashes = [],
3682                 i = value.length;
3683             while (i--) {
3684                 dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
3685             }
3686             $(o.node, {"stroke-dasharray": dashes.join(",")});
3687         }
3688     },
3689     setFillAndStroke = function (o, params) {
3690         var node = o.node,
3691             attrs = o.attrs,
3692             vis = node.style.visibility;
3693         node.style.visibility = "hidden";
3694         for (var att in params) {
3695             if (params[has](att)) {
3696                 if (!R._availableAttrs[has](att)) {
3697                     continue;
3698                 }
3699                 var value = params[att];
3700                 attrs[att] = value;
3701                 switch (att) {
3702                     case "blur":
3703                         o.blur(value);
3704                         break;
3705                     case "href":
3706                     case "title":
3707                     case "target":
3708                         var pn = node.parentNode;
3709                         if (pn.tagName.toLowerCase() != "a") {
3710                             var hl = $("a");
3711                             pn.insertBefore(hl, node);
3712                             hl.appendChild(node);
3713                             pn = hl;
3714                         }
3715                         if (att == "target" && value == "blank") {
3716                             pn.setAttributeNS(xlink, "show", "new");
3717                         } else {
3718                             pn.setAttributeNS(xlink, att, value);
3719                         }
3720                         break;
3721                     case "cursor":
3722                         node.style.cursor = value;
3723                         break;
3724                     case "transform":
3725                         o.transform(value);
3726                         break;
3727                     case "arrow-start":
3728                         addArrow(o, value);
3729                         break;
3730                     case "arrow-end":
3731                         addArrow(o, value, 1);
3732                         break;
3733                     case "clip-rect":
3734                         var rect = Str(value).split(separator);
3735                         if (rect.length == 4) {
3736                             o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
3737                             var el = $("clipPath"),
3738                                 rc = $("rect");
3739                             el.id = R.createUUID();
3740                             $(rc, {
3741                                 x: rect[0],
3742                                 y: rect[1],
3743                                 width: rect[2],
3744                                 height: rect[3]
3745                             });
3746                             el.appendChild(rc);
3747                             o.paper.defs.appendChild(el);
3748                             $(node, {"clip-path": "url(#" + el.id + ")"});
3749                             o.clip = rc;
3750                         }
3751                         if (!value) {
3752                             var clip = R._g.doc.getElementById(node.getAttribute("clip-path").replace(/(^url\(#|\)$)/g, E));
3753                             clip && clip.parentNode.removeChild(clip);
3754                             $(node, {"clip-path": E});
3755                             delete o.clip;
3756                         }
3757                     break;
3758                     case "path":
3759                         if (o.type == "path") {
3760                             $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"});
3761                             o._.dirty = 1;
3762                             if (o._.arrows) {
3763                                 "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3764                                 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3765                             }
3766                         }
3767                         break;
3768                     case "width":
3769                         node.setAttribute(att, value);
3770                         o._.dirty = 1;
3771                         if (attrs.fx) {
3772                             att = "x";
3773                             value = attrs.x;
3774                         } else {
3775                             break;
3776                         }
3777                     case "x":
3778                         if (attrs.fx) {
3779                             value = -attrs.x - (attrs.width || 0);
3780                         }
3781                     case "rx":
3782                         if (att == "rx" && o.type == "rect") {
3783                             break;
3784                         }
3785                     case "cx":
3786                         node.setAttribute(att, value);
3787                         o.pattern && updatePosition(o);
3788                         o._.dirty = 1;
3789                         break;
3790                     case "height":
3791                         node.setAttribute(att, value);
3792                         o._.dirty = 1;
3793                         if (attrs.fy) {
3794                             att = "y";
3795                             value = attrs.y;
3796                         } else {
3797                             break;
3798                         }
3799                     case "y":
3800                         if (attrs.fy) {
3801                             value = -attrs.y - (attrs.height || 0);
3802                         }
3803                     case "ry":
3804                         if (att == "ry" && o.type == "rect") {
3805                             break;
3806                         }
3807                     case "cy":
3808                         node.setAttribute(att, value);
3809                         o.pattern && updatePosition(o);
3810                         o._.dirty = 1;
3811                         break;
3812                     case "r":
3813                         if (o.type == "rect") {
3814                             $(node, {rx: value, ry: value});
3815                         } else {
3816                             node.setAttribute(att, value);
3817                         }
3818                         o._.dirty = 1;
3819                         break;
3820                     case "src":
3821                         if (o.type == "image") {
3822                             node.setAttributeNS(xlink, "href", value);
3823                         }
3824                         break;
3825                     case "stroke-width":
3826                         if (o._.sx != 1 || o._.sy != 1) {
3827                             value /= mmax(abs(o._.sx), abs(o._.sy)) || 1;
3828                         }
3829                         if (o.paper._vbSize) {
3830                             value *= o.paper._vbSize;
3831                         }
3832                         node.setAttribute(att, value);
3833                         if (attrs["stroke-dasharray"]) {
3834                             addDashes(o, attrs["stroke-dasharray"], params);
3835                         }
3836                         if (o._.arrows) {
3837                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3838                             "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3839                         }
3840                         break;
3841                     case "stroke-dasharray":
3842                         addDashes(o, value, params);
3843                         break;
3844                     case "fill":
3845                         var isURL = Str(value).match(R._ISURL);
3846                         if (isURL) {
3847                             el = $("pattern");
3848                             var ig = $("image");
3849                             el.id = R.createUUID();
3850                             $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1});
3851                             $(ig, {x: 0, y: 0, "xlink:href": isURL[1]});
3852                             el.appendChild(ig);
3853
3854                             (function (el) {
3855                                 R._preload(isURL[1], function () {
3856                                     var w = this.offsetWidth,
3857                                         h = this.offsetHeight;
3858                                     $(el, {width: w, height: h});
3859                                     $(ig, {width: w, height: h});
3860                                     o.paper.safari();
3861                                 });
3862                             })(el);
3863                             o.paper.defs.appendChild(el);
3864                             node.style.fill = "url(#" + el.id + ")";
3865                             $(node, {fill: "url(#" + el.id + ")"});
3866                             o.pattern = el;
3867                             o.pattern && updatePosition(o);
3868                             break;
3869                         }
3870                         var clr = R.getRGB(value);
3871                         if (!clr.error) {
3872                             delete params.gradient;
3873                             delete attrs.gradient;
3874                             !R.is(attrs.opacity, "undefined") &&
3875                                 R.is(params.opacity, "undefined") &&
3876                                 $(node, {opacity: attrs.opacity});
3877                             !R.is(attrs["fill-opacity"], "undefined") &&
3878                                 R.is(params["fill-opacity"], "undefined") &&
3879                                 $(node, {"fill-opacity": attrs["fill-opacity"]});
3880                         } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) {
3881                             if ("opacity" in attrs || "fill-opacity" in attrs) {
3882                                 var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
3883                                 if (gradient) {
3884                                     var stops = gradient.getElementsByTagName("stop");
3885                                     $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)});
3886                                 }
3887                             }
3888                             attrs.gradient = value;
3889                             attrs.fill = "none";
3890                             break;
3891                         }
3892                         clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
3893                     case "stroke":
3894                         clr = R.getRGB(value);
3895                         node.setAttribute(att, clr.hex);
3896                         att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
3897                         if (att == "stroke" && o._.arrows) {
3898                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3899                             "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3900                         }
3901                         break;
3902                     case "gradient":
3903                         (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value);
3904                         break;
3905                     case "opacity":
3906                         if (attrs.gradient && !attrs[has]("stroke-opacity")) {
3907                             $(node, {"stroke-opacity": value > 1 ? value / 100 : value});
3908                         }
3909                         // fall
3910                     case "fill-opacity":
3911                         if (attrs.gradient) {
3912                             gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
3913                             if (gradient) {
3914                                 stops = gradient.getElementsByTagName("stop");
3915                                 $(stops[stops.length - 1], {"stop-opacity": value});
3916                             }
3917                             break;
3918                         }
3919                     default:
3920                         att == "font-size" && (value = toInt(value, 10) + "px");
3921                         var cssrule = att.replace(/(\-.)/g, function (w) {
3922                             return w.substring(1).toUpperCase();
3923                         });
3924                         node.style[cssrule] = value;
3925                         o._.dirty = 1;
3926                         node.setAttribute(att, value);
3927                         break;
3928                 }
3929             }
3930         }
3931
3932         tuneText(o, params);
3933         node.style.visibility = vis;
3934     },
3935     leading = 1.2,
3936     tuneText = function (el, params) {
3937         if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) {
3938             return;
3939         }
3940         var a = el.attrs,
3941             node = el.node,
3942             fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10;
3943
3944         if (params[has]("text")) {
3945             a.text = params.text;
3946             while (node.firstChild) {
3947                 node.removeChild(node.firstChild);
3948             }
3949             var texts = Str(params.text).split("\n"),
3950                 tspans = [],
3951                 tspan;
3952             for (var i = 0, ii = texts.length; i < ii; i++) {
3953                 tspan = $("tspan");
3954                 i && $(tspan, {dy: fontSize * leading, x: a.x});
3955                 tspan.appendChild(R._g.doc.createTextNode(texts[i]));
3956                 node.appendChild(tspan);
3957                 tspans[i] = tspan;
3958             }
3959         } else {
3960             tspans = node.getElementsByTagName("tspan");
3961             for (i = 0, ii = tspans.length; i < ii; i++) if (i) {
3962                 $(tspans[i], {dy: fontSize * leading, x: a.x});
3963             } else {
3964                 $(tspans[0], {dy: 0});
3965             }
3966         }
3967         $(node, {x: a.x, y: a.y});
3968         el._.dirty = 1;
3969         var bb = el._getBBox(),
3970             dif = a.y - (bb.y + bb.height / 2);
3971         dif && R.is(dif, "finite") && $(tspans[0], {dy: dif});
3972     },
3973     Element = function (node, svg) {
3974         var X = 0,
3975             Y = 0;
3976         
3977         this[0] = this.node = node;
3978         
3979         node.raphael = true;
3980         
3981         this.id = R._oid++;
3982         node.raphaelid = this.id;
3983         this.matrix = R.matrix();
3984         this.realPath = null;
3985         
3986         this.paper = svg;
3987         this.attrs = this.attrs || {};
3988         this._ = {
3989             transform: [],
3990             sx: 1,
3991             sy: 1,
3992             deg: 0,
3993             dx: 0,
3994             dy: 0,
3995             dirty: 1
3996         };
3997         !svg.bottom && (svg.bottom = this);
3998         
3999         this.prev = svg.top;
4000         svg.top && (svg.top.next = this);
4001         svg.top = this;
4002         
4003         this.next = null;
4004     },
4005     elproto = R.el;
4006
4007     Element.prototype = elproto;
4008     elproto.constructor = Element;
4009
4010     R._engine.path = function (pathString, SVG) {
4011         var el = $("path");
4012         SVG.canvas && SVG.canvas.appendChild(el);
4013         var p = new Element(el, SVG);
4014         p.type = "path";
4015         setFillAndStroke(p, {
4016             fill: "none",
4017             stroke: "#000",
4018             path: pathString
4019         });
4020         return p;
4021     };
4022     
4023     elproto.rotate = function (deg, cx, cy) {
4024         if (this.removed) {
4025             return this;
4026         }
4027         deg = Str(deg).split(separator);
4028         if (deg.length - 1) {
4029             cx = toFloat(deg[1]);
4030             cy = toFloat(deg[2]);
4031         }
4032         deg = toFloat(deg[0]);
4033         (cy == null) && (cx = cy);
4034         if (cx == null || cy == null) {
4035             var bbox = this.getBBox(1);
4036             cx = bbox.x + bbox.width / 2;
4037             cy = bbox.y + bbox.height / 2;
4038         }
4039         this.transform(this._.transform.concat([["r", deg, cx, cy]]));
4040         return this;
4041     };
4042     
4043     elproto.scale = function (sx, sy, cx, cy) {
4044         if (this.removed) {
4045             return this;
4046         }
4047         sx = Str(sx).split(separator);
4048         if (sx.length - 1) {
4049             sy = toFloat(sx[1]);
4050             cx = toFloat(sx[2]);
4051             cy = toFloat(sx[3]);
4052         }
4053         sx = toFloat(sx[0]);
4054         (sy == null) && (sy = sx);
4055         (cy == null) && (cx = cy);
4056         if (cx == null || cy == null) {
4057             var bbox = this.getBBox(1);
4058         }
4059         cx = cx == null ? bbox.x + bbox.width / 2 : cx;
4060         cy = cy == null ? bbox.y + bbox.height / 2 : cy;
4061         this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
4062         return this;
4063     };
4064     
4065     elproto.translate = function (dx, dy) {
4066         if (this.removed) {
4067             return this;
4068         }
4069         dx = Str(dx).split(separator);
4070         if (dx.length - 1) {
4071             dy = toFloat(dx[1]);
4072         }
4073         dx = toFloat(dx[0]) || 0;
4074         dy = +dy || 0;
4075         this.transform(this._.transform.concat([["t", dx, dy]]));
4076         return this;
4077     };
4078     
4079     elproto.transform = function (tstr) {
4080         var _ = this._;
4081         if (tstr == null) {
4082             return _.transform;
4083         }
4084         R._extractTransform(this, tstr);
4085
4086         this.clip && $(this.clip, {transform: this.matrix.invert()});
4087         this.pattern && updatePosition(this);
4088         this.node && $(this.node, {transform: this.matrix});
4089     
4090         if (_.sx != 1 || _.sy != 1) {
4091             var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1;
4092             this.attr({"stroke-width": sw});
4093         }
4094
4095         return this;
4096     };
4097     
4098     elproto.hide = function () {
4099         !this.removed && this.paper.safari(this.node.style.display = "none");
4100         return this;
4101     };
4102     
4103     elproto.show = function () {
4104         !this.removed && this.paper.safari(this.node.style.display = "");
4105         return this;
4106     };
4107     
4108     elproto.remove = function () {
4109         if (this.removed) {
4110             return;
4111         }
4112         this.paper.__set__ && this.paper.__set__.exclude(this);
4113         eve.unbind("*.*." + this.id);
4114         R._tear(this, this.paper);
4115         this.node.parentNode.removeChild(this.node);
4116         for (var i in this) {
4117             delete this[i];
4118         }
4119         this.removed = true;
4120     };
4121     elproto._getBBox = function () {
4122         if (this.node.style.display == "none") {
4123             this.show();
4124             var hide = true;
4125         }
4126         var bbox = {};
4127         try {
4128             bbox = this.node.getBBox();
4129         } catch(e) {
4130             // Firefox 3.0.x plays badly here
4131         } finally {
4132             bbox = bbox || {};
4133         }
4134         hide && this.hide();
4135         return bbox;
4136     };
4137     
4138     elproto.attr = function (name, value) {
4139         if (this.removed) {
4140             return this;
4141         }
4142         if (name == null) {
4143             var res = {};
4144             for (var a in this.attrs) if (this.attrs[has](a)) {
4145                 res[a] = this.attrs[a];
4146             }
4147             res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
4148             res.transform = this._.transform;
4149             return res;
4150         }
4151         if (value == null && R.is(name, "string")) {
4152             if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) {
4153                 return this.attrs.gradient;
4154             }
4155             if (name == "transform") {
4156                 return this._.transform;
4157             }
4158             var names = name.split(separator),
4159                 out = {};
4160             for (var i = 0, ii = names.length; i < ii; i++) {
4161                 name = names[i];
4162                 if (name in this.attrs) {
4163                     out[name] = this.attrs[name];
4164                 } else if (R.is(this.paper.customAttributes[name], "function")) {
4165                     out[name] = this.paper.customAttributes[name].def;
4166                 } else {
4167                     out[name] = R._availableAttrs[name];
4168                 }
4169             }
4170             return ii - 1 ? out : out[names[0]];
4171         }
4172         if (value == null && R.is(name, "array")) {
4173             out = {};
4174             for (i = 0, ii = name.length; i < ii; i++) {
4175                 out[name[i]] = this.attr(name[i]);
4176             }
4177             return out;
4178         }
4179         if (value != null) {
4180             var params = {};
4181             params[name] = value;
4182         } else if (name != null && R.is(name, "object")) {
4183             params = name;
4184         }
4185         for (var key in params) {
4186             eve("attr." + key + "." + this.id, this, params[key]);
4187         }
4188         for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
4189             var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
4190             this.attrs[key] = params[key];
4191             for (var subkey in par) if (par[has](subkey)) {
4192                 params[subkey] = par[subkey];
4193             }
4194         }
4195         setFillAndStroke(this, params);
4196         return this;
4197     };
4198     
4199     elproto.toFront = function () {
4200         if (this.removed) {
4201             return this;
4202         }
4203         this.node.parentNode.appendChild(this.node);
4204         var svg = this.paper;
4205         svg.top != this && R._tofront(this, svg);
4206         return this;
4207     };
4208     
4209     elproto.toBack = function () {
4210         if (this.removed) {
4211             return this;
4212         }
4213         if (this.node.parentNode.firstChild != this.node) {
4214             this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
4215             R._toback(this, this.paper);
4216             var svg = this.paper;
4217         }
4218         return this;
4219     };
4220     
4221     elproto.insertAfter = function (element) {
4222         if (this.removed) {
4223             return this;
4224         }
4225         var node = element.node || element[element.length - 1].node;
4226         if (node.nextSibling) {
4227             node.parentNode.insertBefore(this.node, node.nextSibling);
4228         } else {
4229             node.parentNode.appendChild(this.node);
4230         }
4231         R._insertafter(this, element, this.paper);
4232         return this;
4233     };
4234     
4235     elproto.insertBefore = function (element) {
4236         if (this.removed) {
4237             return this;
4238         }
4239         var node = element.node || element[0].node;
4240         node.parentNode.insertBefore(this.node, node);
4241         R._insertbefore(this, element, this.paper);
4242         return this;
4243     };
4244     elproto.blur = function (size) {
4245         // Experimental. No Safari support. Use it on your own risk.
4246         var t = this;
4247         if (+size !== 0) {
4248             var fltr = $("filter"),
4249                 blur = $("feGaussianBlur");
4250             t.attrs.blur = size;
4251             fltr.id = R.createUUID();
4252             $(blur, {stdDeviation: +size || 1.5});
4253             fltr.appendChild(blur);
4254             t.paper.defs.appendChild(fltr);
4255             t._blur = fltr;
4256             $(t.node, {filter: "url(#" + fltr.id + ")"});
4257         } else {
4258             if (t._blur) {
4259                 t._blur.parentNode.removeChild(t._blur);
4260                 delete t._blur;
4261                 delete t.attrs.blur;
4262             }
4263             t.node.removeAttribute("filter");
4264         }
4265     };
4266     R._engine.circle = function (svg, x, y, r) {
4267         var el = $("circle");
4268         svg.canvas && svg.canvas.appendChild(el);
4269         var res = new Element(el, svg);
4270         res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"};
4271         res.type = "circle";
4272         $(el, res.attrs);
4273         return res;
4274     };
4275     R._engine.rect = function (svg, x, y, w, h, r) {
4276         var el = $("rect");
4277         svg.canvas && svg.canvas.appendChild(el);
4278         var res = new Element(el, svg);
4279         res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"};
4280         res.type = "rect";
4281         $(el, res.attrs);
4282         return res;
4283     };
4284     R._engine.ellipse = function (svg, x, y, rx, ry) {
4285         var el = $("ellipse");
4286         svg.canvas && svg.canvas.appendChild(el);
4287         var res = new Element(el, svg);
4288         res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"};
4289         res.type = "ellipse";
4290         $(el, res.attrs);
4291         return res;
4292     };
4293     R._engine.image = function (svg, src, x, y, w, h) {
4294         var el = $("image");
4295         $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"});
4296         el.setAttributeNS(xlink, "href", src);
4297         svg.canvas && svg.canvas.appendChild(el);
4298         var res = new Element(el, svg);
4299         res.attrs = {x: x, y: y, width: w, height: h, src: src};
4300         res.type = "image";
4301         return res;
4302     };
4303     R._engine.text = function (svg, x, y, text) {
4304         var el = $("text");
4305         // $(el, {x: x, y: y, "text-anchor": "middle"});
4306         svg.canvas && svg.canvas.appendChild(el);
4307         var res = new Element(el, svg);
4308         res.attrs = {
4309             x: x,
4310             y: y,
4311             "text-anchor": "middle",
4312             text: text,
4313             font: R._availableAttrs.font,
4314             stroke: "none",
4315             fill: "#000"
4316         };
4317         res.type = "text";
4318         setFillAndStroke(res, res.attrs);
4319         return res;
4320     };
4321     R._engine.setSize = function (width, height) {
4322         this.width = width || this.width;
4323         this.height = height || this.height;
4324         this.canvas.setAttribute("width", this.width);
4325         this.canvas.setAttribute("height", this.height);
4326         if (this._viewBox) {
4327             this.setViewBox.apply(this, this._viewBox);
4328         }
4329         return this;
4330     };
4331     R._engine.create = function () {
4332         var con = R._getContainer.apply(0, arguments),
4333             container = con && con.container,
4334             x = con.x,
4335             y = con.y,
4336             width = con.width,
4337             height = con.height;
4338         if (!container) {
4339             throw new Error("SVG container not found.");
4340         }
4341         var cnvs = $("svg"),
4342             css = "overflow:hidden;",
4343             isFloating;
4344         x = x || 0;
4345         y = y || 0;
4346         width = width || 512;
4347         height = height || 342;
4348         $(cnvs, {
4349             height: height,
4350             version: 1.1,
4351             width: width,
4352             xmlns: "http://www.w3.org/2000/svg"
4353         });
4354         if (container == 1) {
4355             cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
4356             R._g.doc.body.appendChild(cnvs);
4357             isFloating = 1;
4358         } else {
4359             cnvs.style.cssText = css + "position:relative";
4360             if (container.firstChild) {
4361                 container.insertBefore(cnvs, container.firstChild);
4362             } else {
4363                 container.appendChild(cnvs);
4364             }
4365         }
4366         container = new R._Paper;
4367         container.width = width;
4368         container.height = height;
4369         container.canvas = cnvs;
4370         // plugins.call(container, container, R.fn);
4371         container.clear();
4372         container._left = container._top = 0;
4373         isFloating && (container.renderfix = function () {});
4374         container.renderfix();
4375         return container;
4376     };
4377     R._engine.setViewBox = function (x, y, w, h, fit) {
4378         eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]);
4379         var size = mmax(w / this.width, h / this.height),
4380             top = this.top,
4381             aspectRatio = fit ? "meet" : "xMinYMin",
4382             vb,
4383             sw;
4384         if (x == null) {
4385             if (this._vbSize) {
4386                 size = 1;
4387             }
4388             delete this._vbSize;
4389             vb = "0 0 " + this.width + S + this.height;
4390         } else {
4391             this._vbSize = size;
4392             vb = x + S + y + S + w + S + h;
4393         }
4394         $(this.canvas, {
4395             viewBox: vb,
4396             preserveAspectRatio: aspectRatio
4397         });
4398         while (size && top) {
4399             sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1;
4400             top.attr({"stroke-width": sw});
4401             top._.dirty = 1;
4402             top._.dirtyT = 1;
4403             top = top.prev;
4404         }
4405         this._viewBox = [x, y, w, h, !!fit];
4406         return this;
4407     };
4408     
4409     R.prototype.renderfix = function () {
4410         var cnvs = this.canvas,
4411             s = cnvs.style,
4412             pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(),
4413             left = -pos.e % 1,
4414             top = -pos.f % 1;
4415         if (left || top) {
4416             if (left) {
4417                 this._left = (this._left + left) % 1;
4418                 s.left = this._left + "px";
4419             }
4420             if (top) {
4421                 this._top = (this._top + top) % 1;
4422                 s.top = this._top + "px";
4423             }
4424         }
4425     };
4426     
4427     R.prototype.clear = function () {
4428         R.eve("clear", this);
4429         var c = this.canvas;
4430         while (c.firstChild) {
4431             c.removeChild(c.firstChild);
4432         }
4433         this.bottom = this.top = null;
4434         (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version));
4435         c.appendChild(this.desc);
4436         c.appendChild(this.defs = $("defs"));
4437     };
4438     
4439     R.prototype.remove = function () {
4440         eve("remove", this);
4441         this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
4442         for (var i in this) {
4443             this[i] = removed(i);
4444         }
4445     };
4446     var setproto = R.st;
4447     for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
4448         setproto[method] = (function (methodname) {
4449             return function () {
4450                 var arg = arguments;
4451                 return this.forEach(function (el) {
4452                     el[methodname].apply(el, arg);
4453                 });
4454             };
4455         })(method);
4456     }
4457 }(window.Raphael);
4458
4459 // ┌─────────────────────────────────────────────────────────────────────┐ \\
4460 // │ Raphaël 2 - JavaScript Vector Library                               │ \\
4461 // ├─────────────────────────────────────────────────────────────────────┤ \\
4462 // │ VML Module                                                          │ \\
4463 // ├─────────────────────────────────────────────────────────────────────┤ \\
4464 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
4465 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
4466 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
4467 // └─────────────────────────────────────────────────────────────────────┘ \\
4468 window.Raphael.vml && function (R) {
4469     var has = "hasOwnProperty",
4470         Str = String,
4471         toFloat = parseFloat,
4472         math = Math,
4473         round = math.round,
4474         mmax = math.max,
4475         mmin = math.min,
4476         abs = math.abs,
4477         fillString = "fill",
4478         separator = /[, ]+/,
4479         eve = R.eve,
4480         ms = " progid:DXImageTransform.Microsoft",
4481         S = " ",
4482         E = "",
4483         map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"},
4484         bites = /([clmz]),?([^clmz]*)/gi,
4485         blurregexp = / progid:\S+Blur\([^\)]+\)/g,
4486         val = /-?[^,\s-]+/g,
4487         cssDot = "position:absolute;left:0;top:0;width:1px;height:1px",
4488         zoom = 21600,
4489         pathTypes = {path: 1, rect: 1, image: 1},
4490         ovalTypes = {circle: 1, ellipse: 1},
4491         path2vml = function (path) {
4492             var total =  /[ahqstv]/ig,
4493                 command = R._pathToAbsolute;
4494             Str(path).match(total) && (command = R._path2curve);
4495             total = /[clmz]/g;
4496             if (command == R._pathToAbsolute && !Str(path).match(total)) {
4497                 var res = Str(path).replace(bites, function (all, command, args) {
4498                     var vals = [],
4499                         isMove = command.toLowerCase() == "m",
4500                         res = map[command];
4501                     args.replace(val, function (value) {
4502                         if (isMove && vals.length == 2) {
4503                             res += vals + map[command == "m" ? "l" : "L"];
4504                             vals = [];
4505                         }
4506                         vals.push(round(value * zoom));
4507                     });
4508                     return res + vals;
4509                 });
4510                 return res;
4511             }
4512             var pa = command(path), p, r;
4513             res = [];
4514             for (var i = 0, ii = pa.length; i < ii; i++) {
4515                 p = pa[i];
4516                 r = pa[i][0].toLowerCase();
4517                 r == "z" && (r = "x");
4518                 for (var j = 1, jj = p.length; j < jj; j++) {
4519                     r += round(p[j] * zoom) + (j != jj - 1 ? "," : E);
4520                 }
4521                 res.push(r);
4522             }
4523             return res.join(S);
4524         },
4525         compensation = function (deg, dx, dy) {
4526             var m = R.matrix();
4527             m.rotate(-deg, .5, .5);
4528             return {
4529                 dx: m.x(dx, dy),
4530                 dy: m.y(dx, dy)
4531             };
4532         },
4533         setCoords = function (p, sx, sy, dx, dy, deg) {
4534             var _ = p._,
4535                 m = p.matrix,
4536                 fillpos = _.fillpos,
4537                 o = p.node,
4538                 s = o.style,
4539                 y = 1,
4540                 flip = "",
4541                 dxdy,
4542                 kx = zoom / sx,
4543                 ky = zoom / sy;
4544             s.visibility = "hidden";
4545             if (!sx || !sy) {
4546                 return;
4547             }
4548             o.coordsize = abs(kx) + S + abs(ky);
4549             s.rotation = deg * (sx * sy < 0 ? -1 : 1);
4550             if (deg) {
4551                 var c = compensation(deg, dx, dy);
4552                 dx = c.dx;
4553                 dy = c.dy;
4554             }
4555             sx < 0 && (flip += "x");
4556             sy < 0 && (flip += " y") && (y = -1);
4557             s.flip = flip;
4558             o.coordorigin = (dx * -kx) + S + (dy * -ky);
4559             if (fillpos || _.fillsize) {
4560                 var fill = o.getElementsByTagName(fillString);
4561                 fill = fill && fill[0];
4562                 o.removeChild(fill);
4563                 if (fillpos) {
4564                     c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1]));
4565                     fill.position = c.dx * y + S + c.dy * y;
4566                 }
4567                 if (_.fillsize) {
4568                     fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy);
4569                 }
4570                 o.appendChild(fill);
4571             }
4572             s.visibility = "visible";
4573         };
4574     R.toString = function () {
4575         return  "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version;
4576     };
4577     addArrow = function (o, value, isEnd) {
4578         var values = Str(value).toLowerCase().split("-"),
4579             se = isEnd ? "end" : "start",
4580             i = values.length,
4581             type = "classic",
4582             w = "medium",
4583             h = "medium";
4584         while (i--) {
4585             switch (values[i]) {
4586                 case "block":
4587                 case "classic":
4588                 case "oval":
4589                 case "diamond":
4590                 case "open":
4591                 case "none":
4592                     type = values[i];
4593                     break;
4594                 case "wide":
4595                 case "narrow": h = values[i]; break;
4596                 case "long":
4597                 case "short": w = values[i]; break;
4598             }
4599         }
4600         var stroke = o.node.getElementsByTagName("stroke")[0];
4601         stroke[se + "arrow"] = type;
4602         stroke[se + "arrowlength"] = w;
4603         stroke[se + "arrowwidth"] = h;
4604     };
4605     setFillAndStroke = function (o, params) {
4606         // o.paper.canvas.style.display = "none";
4607         o.attrs = o.attrs || {};
4608         var node = o.node,
4609             a = o.attrs,
4610             s = node.style,
4611             xy,
4612             newpath = pathTypes[o.type] && (params.x != a.x || params.y != a.y || params.width != a.width || params.height != a.height || params.cx != a.cx || params.cy != a.cy || params.rx != a.rx || params.ry != a.ry || params.r != a.r),
4613             isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry),
4614             res = o;
4615
4616
4617         for (var par in params) if (params[has](par)) {
4618             a[par] = params[par];
4619         }
4620         if (newpath) {
4621             a.path = R._getPath[o.type](o);
4622             o._.dirty = 1;
4623         }
4624         params.href && (node.href = params.href);
4625         params.title && (node.title = params.title);
4626         params.target && (node.target = params.target);
4627         params.cursor && (s.cursor = params.cursor);
4628         "blur" in params && o.blur(params.blur);
4629         if (params.path && o.type == "path" || newpath) {
4630             node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path);
4631             if (o.type == "image") {
4632                 o._.fillpos = [a.x, a.y];
4633                 o._.fillsize = [a.width, a.height];
4634                 setCoords(o, 1, 1, 0, 0, 0);
4635             }
4636         }
4637         "transform" in params && o.transform(params.transform);
4638         if (isOval) {
4639             var cx = +a.cx,
4640                 cy = +a.cy,
4641                 rx = +a.rx || +a.r || 0,
4642                 ry = +a.ry || +a.r || 0;
4643             node.path = R.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x", round((cx - rx) * zoom), round((cy - ry) * zoom), round((cx + rx) * zoom), round((cy + ry) * zoom), round(cx * zoom));
4644         }
4645         if ("clip-rect" in params) {
4646             var rect = Str(params["clip-rect"]).split(separator);
4647             if (rect.length == 4) {
4648                 rect[2] = +rect[2] + (+rect[0]);
4649                 rect[3] = +rect[3] + (+rect[1]);
4650                 var div = node.clipRect || R._g.doc.createElement("div"),
4651                     dstyle = div.style;
4652                 dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect);
4653                 if (!node.clipRect) {
4654                     dstyle.position = "absolute";
4655                     dstyle.top = 0;
4656                     dstyle.left = 0;
4657                     dstyle.width = o.paper.width + "px";
4658                     dstyle.height = o.paper.height + "px";
4659                     node.parentNode.insertBefore(div, node);
4660                     div.appendChild(node);
4661                     node.clipRect = div;
4662                 }
4663             }
4664             if (!params["clip-rect"]) {
4665                 node.clipRect && (node.clipRect.style.clip = E);
4666             }
4667         }
4668         if (o.textpath) {
4669             var textpathStyle = o.textpath.style;
4670             params.font && (textpathStyle.font = params.font);
4671             params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"');
4672             params["font-size"] && (textpathStyle.fontSize = params["font-size"]);
4673             params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]);
4674             params["font-style"] && (textpathStyle.fontStyle = params["font-style"]);
4675         }
4676         if ("arrow-start" in params) {
4677             addArrow(res, params["arrow-start"]);
4678         }
4679         if ("arrow-end" in params) {
4680             addArrow(res, params["arrow-end"], 1);
4681         }
4682         if (params.opacity != null || 
4683             params["stroke-width"] != null ||
4684             params.fill != null ||
4685             params.src != null ||
4686             params.stroke != null ||
4687             params["stroke-width"] != null ||
4688             params["stroke-opacity"] != null ||
4689             params["fill-opacity"] != null ||
4690             params["stroke-dasharray"] != null ||
4691             params["stroke-miterlimit"] != null ||
4692             params["stroke-linejoin"] != null ||
4693             params["stroke-linecap"] != null) {
4694             var fill = node.getElementsByTagName(fillString),
4695                 newfill = false;
4696             fill = fill && fill[0];
4697             !fill && (newfill = fill = createNode(fillString));
4698             if (o.type == "image" && params.src) {
4699                 fill.src = params.src;
4700             }
4701             params.fill && (fill.on = true);
4702             if (fill.on == null || params.fill == "none" || params.fill === null) {
4703                 fill.on = false;
4704             }
4705             if (fill.on && params.fill) {
4706                 var isURL = Str(params.fill).match(R._ISURL);
4707                 if (isURL) {
4708                     fill.parentNode == node && node.removeChild(fill);
4709                     fill.rotate = true;
4710                     fill.src = isURL[1];
4711                     fill.type = "tile";
4712                     var bbox = o.getBBox(1);
4713                     fill.position = bbox.x + S + bbox.y;
4714                     o._.fillpos = [bbox.x, bbox.y];
4715
4716                     R._preload(isURL[1], function () {
4717                         o._.fillsize = [this.offsetWidth, this.offsetHeight];
4718                     });
4719                 } else {
4720                     fill.color = R.getRGB(params.fill).hex;
4721                     fill.src = E;
4722                     fill.type = "solid";
4723                     if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) {
4724                         a.fill = "none";
4725                         a.gradient = params.fill;
4726                         fill.rotate = false;
4727                     }
4728                 }
4729             }
4730             if ("fill-opacity" in params || "opacity" in params) {
4731                 var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1);
4732                 opacity = mmin(mmax(opacity, 0), 1);
4733                 fill.opacity = opacity;
4734                 if (fill.src) {
4735                     fill.color = "none";
4736                 }
4737             }
4738             node.appendChild(fill);
4739             var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]),
4740             newstroke = false;
4741             !stroke && (newstroke = stroke = createNode("stroke"));
4742             if ((params.stroke && params.stroke != "none") ||
4743                 params["stroke-width"] ||
4744                 params["stroke-opacity"] != null ||
4745                 params["stroke-dasharray"] ||
4746                 params["stroke-miterlimit"] ||
4747                 params["stroke-linejoin"] ||
4748                 params["stroke-linecap"]) {
4749                 stroke.on = true;
4750             }
4751             (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false);
4752             var strokeColor = R.getRGB(params.stroke);
4753             stroke.on && params.stroke && (stroke.color = strokeColor.hex);
4754             opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1);
4755             var width = (toFloat(params["stroke-width"]) || 1) * .75;
4756             opacity = mmin(mmax(opacity, 0), 1);
4757             params["stroke-width"] == null && (width = a["stroke-width"]);
4758             params["stroke-width"] && (stroke.weight = width);
4759             width && width < 1 && (opacity *= width) && (stroke.weight = 1);
4760             stroke.opacity = opacity;
4761         
4762             params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter");
4763             stroke.miterlimit = params["stroke-miterlimit"] || 8;
4764             params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round");
4765             if (params["stroke-dasharray"]) {
4766                 var dasharray = {
4767                     "-": "shortdash",
4768                     ".": "shortdot",
4769                     "-.": "shortdashdot",
4770                     "-..": "shortdashdotdot",
4771                     ". ": "dot",
4772                     "- ": "dash",
4773                     "--": "longdash",
4774                     "- .": "dashdot",
4775                     "--.": "longdashdot",
4776                     "--..": "longdashdotdot"
4777                 };
4778                 stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E;
4779             }
4780             newstroke && node.appendChild(stroke);
4781         }
4782         if (res.type == "text") {
4783             res.paper.canvas.style.display = E;
4784             var span = res.paper.span,
4785                 m = 100,
4786                 fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/);
4787             s = span.style;
4788             a.font && (s.font = a.font);
4789             a["font-family"] && (s.fontFamily = a["font-family"]);
4790             a["font-weight"] && (s.fontWeight = a["font-weight"]);
4791             a["font-style"] && (s.fontStyle = a["font-style"]);
4792             fontSize = toFloat(fontSize ? fontSize[0] : a["font-size"]);
4793             s.fontSize = fontSize * m + "px";
4794             res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/</g, "&#60;").replace(/&/g, "&#38;").replace(/\n/g, "<br>"));
4795             var brect = span.getBoundingClientRect();
4796             res.W = a.w = (brect.right - brect.left) / m;
4797             res.H = a.h = (brect.bottom - brect.top) / m;
4798             // res.paper.canvas.style.display = "none";
4799             res.X = a.x;
4800             res.Y = a.y + res.H / 2;
4801
4802             ("x" in params || "y" in params) && (res.path.v = R.format("m{0},{1}l{2},{1}", round(a.x * zoom), round(a.y * zoom), round(a.x * zoom) + 1));
4803             var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"];
4804             for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) {
4805                 res._.dirty = 1;
4806                 break;
4807             }
4808         
4809             // text-anchor emulation
4810             switch (a["text-anchor"]) {
4811                 case "start":
4812                     res.textpath.style["v-text-align"] = "left";
4813                     res.bbx = res.W / 2;
4814                 break;
4815                 case "end":
4816                     res.textpath.style["v-text-align"] = "right";
4817                     res.bbx = -res.W / 2;
4818                 break;
4819                 default:
4820                     res.textpath.style["v-text-align"] = "center";
4821                     res.bbx = 0;
4822                 break;
4823             }
4824             res.textpath.style["v-text-kern"] = true;
4825         }
4826         // res.paper.canvas.style.display = E;
4827     };
4828     addGradientFill = function (o, gradient, fill) {
4829         o.attrs = o.attrs || {};
4830         var attrs = o.attrs,
4831             pow = Math.pow,
4832             opacity,
4833             oindex,
4834             type = "linear",
4835             fxfy = ".5 .5";
4836         o.attrs.gradient = gradient;
4837         gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) {
4838             type = "radial";
4839             if (fx && fy) {
4840                 fx = toFloat(fx);
4841                 fy = toFloat(fy);
4842                 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5);
4843                 fxfy = fx + S + fy;
4844             }
4845             return E;
4846         });
4847         gradient = gradient.split(/\s*\-\s*/);
4848         if (type == "linear") {
4849             var angle = gradient.shift();
4850             angle = -toFloat(angle);
4851             if (isNaN(angle)) {
4852                 return null;
4853             }
4854         }
4855         var dots = R._parseDots(gradient);
4856         if (!dots) {
4857             return null;
4858         }
4859         o = o.shape || o.node;
4860         if (dots.length) {
4861             o.removeChild(fill);
4862             fill.on = true;
4863             fill.method = "none";
4864             fill.color = dots[0].color;
4865             fill.color2 = dots[dots.length - 1].color;
4866             var clrs = [];
4867             for (var i = 0, ii = dots.length; i < ii; i++) {
4868                 dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color);
4869             }
4870             fill.colors = clrs.length ? clrs.join() : "0% " + fill.color;
4871             if (type == "radial") {
4872                 fill.type = "gradientTitle";
4873                 fill.focus = "100%";
4874                 fill.focussize = "0 0";
4875                 fill.focusposition = fxfy;
4876                 fill.angle = 0;
4877             } else {
4878                 // fill.rotate= true;
4879                 fill.type = "gradient";
4880                 fill.angle = (270 - angle) % 360;
4881             }
4882             o.appendChild(fill);
4883         }
4884         return 1;
4885     };
4886     Element = function (node, vml) {
4887         this[0] = this.node = node;
4888         node.raphael = true;
4889         this.id = R._oid++;
4890         node.raphaelid = this.id;
4891         this.X = 0;
4892         this.Y = 0;
4893         this.attrs = {};
4894         this.paper = vml;
4895         this.matrix = R.matrix();
4896         this._ = {
4897             transform: [],
4898             sx: 1,
4899             sy: 1,
4900             dx: 0,
4901             dy: 0,
4902             deg: 0,
4903             dirty: 1,
4904             dirtyT: 1
4905         };
4906         !vml.bottom && (vml.bottom = this);
4907         this.prev = vml.top;
4908         vml.top && (vml.top.next = this);
4909         vml.top = this;
4910         this.next = null;
4911     };
4912     var elproto = R.el;
4913
4914     Element.prototype = elproto;
4915     elproto.constructor = Element;
4916     elproto.transform = function (tstr) {
4917         if (tstr == null) {
4918             return this._.transform;
4919         }
4920         var vbs = this.paper._viewBoxShift,
4921             vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E,
4922             oldt;
4923         if (vbs) {
4924             oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E);
4925         }
4926         R._extractTransform(this, vbt + tstr);
4927         var matrix = this.matrix.clone(),
4928             skew = this.skew,
4929             o = this.node,
4930             split,
4931             isGrad = ~Str(this.attrs.fill).indexOf("-"),
4932             isPatt = !Str(this.attrs.fill).indexOf("url(");
4933         matrix.translate(-.5, -.5);
4934         if (isPatt || isGrad || this.type == "image") {
4935             skew.matrix = "1 0 0 1";
4936             skew.offset = "0 0";
4937             split = matrix.split();
4938             if ((isGrad && split.noRotation) || !split.isSimple) {
4939                 o.style.filter = matrix.toFilter();
4940                 var bb = this.getBBox(),
4941                     bbt = this.getBBox(1),
4942                     dx = bb.x - bbt.x,
4943                     dy = bb.y - bbt.y;
4944                 o.coordorigin = (dx * -zoom) + S + (dy * -zoom);
4945                 setCoords(this, 1, 1, dx, dy, 0);
4946             } else {
4947                 o.style.filter = E;
4948                 setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate);
4949             }
4950         } else {
4951             o.style.filter = E;
4952             skew.matrix = Str(matrix);
4953             skew.offset = matrix.offset();
4954         }
4955         oldt && (this._.transform = oldt);
4956         return this;
4957     };
4958     elproto.rotate = function (deg, cx, cy) {
4959         if (this.removed) {
4960             return this;
4961         }
4962         if (deg == null) {
4963             return;
4964         }
4965         deg = Str(deg).split(separator);
4966         if (deg.length - 1) {
4967             cx = toFloat(deg[1]);
4968             cy = toFloat(deg[2]);
4969         }
4970         deg = toFloat(deg[0]);
4971         (cy == null) && (cx = cy);
4972         if (cx == null || cy == null) {
4973             var bbox = this.getBBox(1);
4974             cx = bbox.x + bbox.width / 2;
4975             cy = bbox.y + bbox.height / 2;
4976         }
4977         this._.dirtyT = 1;
4978         this.transform(this._.transform.concat([["r", deg, cx, cy]]));
4979         return this;
4980     };
4981     elproto.translate = function (dx, dy) {
4982         if (this.removed) {
4983             return this;
4984         }
4985         dx = Str(dx).split(separator);
4986         if (dx.length - 1) {
4987             dy = toFloat(dx[1]);
4988         }
4989         dx = toFloat(dx[0]) || 0;
4990         dy = +dy || 0;
4991         if (this._.bbox) {
4992             this._.bbox.x += dx;
4993             this._.bbox.y += dy;
4994         }
4995         this.transform(this._.transform.concat([["t", dx, dy]]));
4996         return this;
4997     };
4998     elproto.scale = function (sx, sy, cx, cy) {
4999         if (this.removed) {
5000             return this;
5001         }
5002         sx = Str(sx).split(separator);
5003         if (sx.length - 1) {
5004             sy = toFloat(sx[1]);
5005             cx = toFloat(sx[2]);
5006             cy = toFloat(sx[3]);
5007             isNaN(cx) && (cx = null);
5008             isNaN(cy) && (cy = null);
5009         }
5010         sx = toFloat(sx[0]);
5011         (sy == null) && (sy = sx);
5012         (cy == null) && (cx = cy);
5013         if (cx == null || cy == null) {
5014             var bbox = this.getBBox(1);
5015         }
5016         cx = cx == null ? bbox.x + bbox.width / 2 : cx;
5017         cy = cy == null ? bbox.y + bbox.height / 2 : cy;
5018     
5019         this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
5020         this._.dirtyT = 1;
5021         return this;
5022     };
5023     elproto.hide = function () {
5024         !this.removed && (this.node.style.display = "none");
5025         return this;
5026     };
5027     elproto.show = function () {
5028         !this.removed && (this.node.style.display = E);
5029         return this;
5030     };
5031     elproto._getBBox = function () {
5032         if (this.removed) {
5033             return {};
5034         }
5035         if (this.type == "text") {
5036             return {
5037                 x: this.X + (this.bbx || 0) - this.W / 2,
5038                 y: this.Y - this.H,
5039                 width: this.W,
5040                 height: this.H
5041             };
5042         } else {
5043             return pathDimensions(this.attrs.path);
5044         }
5045     };
5046     elproto.remove = function () {
5047         if (this.removed) {
5048             return;
5049         }
5050         this.paper.__set__ && this.paper.__set__.exclude(this);
5051         R.eve.unbind("*.*." + this.id);
5052         R._tear(this, this.paper);
5053         this.node.parentNode.removeChild(this.node);
5054         this.shape && this.shape.parentNode.removeChild(this.shape);
5055         for (var i in this) {
5056             delete this[i];
5057         }
5058         this.removed = true;
5059     };
5060     elproto.attr = function (name, value) {
5061         if (this.removed) {
5062             return this;
5063         }
5064         if (name == null) {
5065             var res = {};
5066             for (var a in this.attrs) if (this.attrs[has](a)) {
5067                 res[a] = this.attrs[a];
5068             }
5069             res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
5070             res.transform = this._.transform;
5071             return res;
5072         }
5073         if (value == null && R.is(name, "string")) {
5074             if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) {
5075                 return this.attrs.gradient;
5076             }
5077             var names = name.split(separator),
5078                 out = {};
5079             for (var i = 0, ii = names.length; i < ii; i++) {
5080                 name = names[i];
5081                 if (name in this.attrs) {
5082                     out[name] = this.attrs[name];
5083                 } else if (R.is(this.paper.customAttributes[name], "function")) {
5084                     out[name] = this.paper.customAttributes[name].def;
5085                 } else {
5086                     out[name] = R._availableAttrs[name];
5087                 }
5088             }
5089             return ii - 1 ? out : out[names[0]];
5090         }
5091         if (this.attrs && value == null && R.is(name, "array")) {
5092             out = {};
5093             for (i = 0, ii = name.length; i < ii; i++) {
5094                 out[name[i]] = this.attr(name[i]);
5095             }
5096             return out;
5097         }
5098         var params;
5099         if (value != null) {
5100             params = {};
5101             params[name] = value;
5102         }
5103         value == null && R.is(name, "object") && (params = name);
5104         for (var key in params) {
5105             eve("attr." + key + "." + this.id, this, params[key]);
5106         }
5107         if (params) {
5108             for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
5109                 var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
5110                 this.attrs[key] = params[key];
5111                 for (var subkey in par) if (par[has](subkey)) {
5112                     params[subkey] = par[subkey];
5113                 }
5114             }
5115             // this.paper.canvas.style.display = "none";
5116             if (params.text && this.type == "text") {
5117                 this.textpath.string = params.text;
5118             }
5119             setFillAndStroke(this, params);
5120             // this.paper.canvas.style.display = E;
5121         }
5122         return this;
5123     };
5124     elproto.toFront = function () {
5125         !this.removed && this.node.parentNode.appendChild(this.node);
5126         this.paper && this.paper.top != this && R._tofront(this, this.paper);
5127         return this;
5128     };
5129     elproto.toBack = function () {
5130         if (this.removed) {
5131             return this;
5132         }
5133         if (this.node.parentNode.firstChild != this.node) {
5134             this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
5135             R._toback(this, this.paper);
5136         }
5137         return this;
5138     };
5139     elproto.insertAfter = function (element) {
5140         if (this.removed) {
5141             return this;
5142         }
5143         if (element.constructor == R.st.constructor) {
5144             element = element[element.length - 1];
5145         }
5146         if (element.node.nextSibling) {
5147             element.node.parentNode.insertBefore(this.node, element.node.nextSibling);
5148         } else {
5149             element.node.parentNode.appendChild(this.node);
5150         }
5151         R._insertafter(this, element, this.paper);
5152         return this;
5153     };
5154     elproto.insertBefore = function (element) {
5155         if (this.removed) {
5156             return this;
5157         }
5158         if (element.constructor == R.st.constructor) {
5159             element = element[0];
5160         }
5161         element.node.parentNode.insertBefore(this.node, element.node);
5162         R._insertbefore(this, element, this.paper);
5163         return this;
5164     };
5165     elproto.blur = function (size) {
5166         var s = this.node.runtimeStyle,
5167             f = s.filter;
5168         f = f.replace(blurregexp, E);
5169         if (+size !== 0) {
5170             this.attrs.blur = size;
5171             s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")";
5172             s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5));
5173         } else {
5174             s.filter = f;
5175             s.margin = 0;
5176             delete this.attrs.blur;
5177         }
5178     };
5179
5180     R._engine.path = function (pathString, vml) {
5181         var el = createNode("shape");
5182         el.style.cssText = cssDot;
5183         el.coordsize = zoom + S + zoom;
5184         el.coordorigin = vml.coordorigin;
5185         var p = new Element(el, vml),
5186             attr = {fill: "none", stroke: "#000"};
5187         pathString && (attr.path = pathString);
5188         p.type = "path";
5189         p.path = [];
5190         p.Path = E;
5191         setFillAndStroke(p, attr);
5192         vml.canvas.appendChild(el);
5193         var skew = createNode("skew");
5194         skew.on = true;
5195         el.appendChild(skew);
5196         p.skew = skew;
5197         p.transform(E);
5198         return p;
5199     };
5200     R._engine.rect = function (vml, x, y, w, h, r) {
5201         var path = R._rectPath(x, y, w, h, r),
5202             res = vml.path(path),
5203             a = res.attrs;
5204         res.X = a.x = x;
5205         res.Y = a.y = y;
5206         res.W = a.width = w;
5207         res.H = a.height = h;
5208         a.r = r;
5209         a.path = path;
5210         res.type = "rect";
5211         return res;
5212     };
5213     R._engine.ellipse = function (vml, x, y, rx, ry) {
5214         var res = vml.path(),
5215             a = res.attrs;
5216         res.X = x - rx;
5217         res.Y = y - ry;
5218         res.W = rx * 2;
5219         res.H = ry * 2;
5220         res.type = "ellipse";
5221         setFillAndStroke(res, {
5222             cx: x,
5223             cy: y,
5224             rx: rx,
5225             ry: ry
5226         });
5227         return res;
5228     };
5229     R._engine.circle = function (vml, x, y, r) {
5230         var res = vml.path(),
5231             a = res.attrs;
5232         res.X = x - r;
5233         res.Y = y - r;
5234         res.W = res.H = r * 2;
5235         res.type = "circle";
5236         setFillAndStroke(res, {
5237             cx: x,
5238             cy: y,
5239             r: r
5240         });
5241         return res;
5242     };
5243     R._engine.image = function (vml, src, x, y, w, h) {
5244         var path = R._rectPath(x, y, w, h),
5245             res = vml.path(path).attr({stroke: "none"}),
5246             a = res.attrs,
5247             node = res.node,
5248             fill = node.getElementsByTagName(fillString)[0];
5249         a.src = src;
5250         res.X = a.x = x;
5251         res.Y = a.y = y;
5252         res.W = a.width = w;
5253         res.H = a.height = h;
5254         a.path = path;
5255         res.type = "image";
5256         fill.parentNode == node && node.removeChild(fill);
5257         fill.rotate = true;
5258         fill.src = src;
5259         fill.type = "tile";
5260         res._.fillpos = [x, y];
5261         res._.fillsize = [w, h];
5262         node.appendChild(fill);
5263         setCoords(res, 1, 1, 0, 0, 0);
5264         return res;
5265     };
5266     R._engine.text = function (vml, x, y, text) {
5267         var el = createNode("shape"),
5268             path = createNode("path"),
5269             o = createNode("textpath");
5270         x = x || 0;
5271         y = y || 0;
5272         text = text || "";
5273         path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1);
5274         path.textpathok = true;
5275         o.string = Str(text);
5276         o.on = true;
5277         el.style.cssText = cssDot;
5278         el.coordsize = zoom + S + zoom;
5279         el.coordorigin = "0 0";
5280         var p = new Element(el, vml),
5281             attr = {
5282                 fill: "#000",
5283                 stroke: "none",
5284                 font: R._availableAttrs.font,
5285                 text: text
5286             };
5287         p.shape = el;
5288         p.path = path;
5289         p.textpath = o;
5290         p.type = "text";
5291         p.attrs.text = Str(text);
5292         p.attrs.x = x;
5293         p.attrs.y = y;
5294         p.attrs.w = 1;
5295         p.attrs.h = 1;
5296         setFillAndStroke(p, attr);
5297         el.appendChild(o);
5298         el.appendChild(path);
5299         vml.canvas.appendChild(el);
5300         var skew = createNode("skew");
5301         skew.on = true;
5302         el.appendChild(skew);
5303         p.skew = skew;
5304         p.transform(E);
5305         return p;
5306     };
5307     R._engine.setSize = function (width, height) {
5308         var cs = this.canvas.style;
5309         this.width = width;
5310         this.height = height;
5311         width == +width && (width += "px");
5312         height == +height && (height += "px");
5313         cs.width = width;
5314         cs.height = height;
5315         cs.clip = "rect(0 " + width + " " + height + " 0)";
5316         if (this._viewBox) {
5317             setViewBox.apply(this, this._viewBox);
5318         }
5319         return this;
5320     };
5321     R._engine.setViewBox = function (x, y, w, h, fit) {
5322         R.eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]);
5323         var width = this.width,
5324             height = this.height,
5325             size = 1 / mmax(w / width, h / height),
5326             H, W;
5327         if (fit) {
5328             H = height / h;
5329             W = width / w;
5330             if (w * H < width) {
5331                 x -= (width - w * H) / 2 / H;
5332             }
5333             if (h * W < height) {
5334                 y -= (height - h * W) / 2 / W;
5335             }
5336         }
5337         this._viewBox = [x, y, w, h, !!fit];
5338         this._viewBoxShift = {
5339             dx: -x,
5340             dy: -y,
5341             scale: size
5342         };
5343         this.forEach(function (el) {
5344             el.transform("...");
5345         });
5346         return this;
5347     };
5348     var createNode,
5349         initWin = function (win) {
5350             var doc = win.document;
5351             doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
5352             try {
5353                 !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
5354                 createNode = function (tagName) {
5355                     return doc.createElement('<rvml:' + tagName + ' class="rvml">');
5356                 };
5357             } catch (e) {
5358                 createNode = function (tagName) {
5359                     return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
5360                 };
5361             }
5362         };
5363     initWin(R._g.win);
5364     R._engine.create = function () {
5365         var con = R._getContainer.apply(0, arguments),
5366             container = con.container,
5367             height = con.height,
5368             s,
5369             width = con.width,
5370             x = con.x,
5371             y = con.y;
5372         if (!container) {
5373             throw new Error("VML container not found.");
5374         }
5375         var res = new R._Paper,
5376             c = res.canvas = R._g.doc.createElement("div"),
5377             cs = c.style;
5378         x = x || 0;
5379         y = y || 0;
5380         width = width || 512;
5381         height = height || 342;
5382         res.width = width;
5383         res.height = height;
5384         width == +width && (width += "px");
5385         height == +height && (height += "px");
5386         res.coordsize = zoom * 1e3 + S + zoom * 1e3;
5387         res.coordorigin = "0 0";
5388         res.span = R._g.doc.createElement("span");
5389         res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;";
5390         c.appendChild(res.span);
5391         cs.cssText = R.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden", width, height);
5392         if (container == 1) {
5393             R._g.doc.body.appendChild(c);
5394             cs.left = x + "px";
5395             cs.top = y + "px";
5396             cs.position = "absolute";
5397         } else {
5398             if (container.firstChild) {
5399                 container.insertBefore(c, container.firstChild);
5400             } else {
5401                 container.appendChild(c);
5402             }
5403         }
5404         // plugins.call(res, res, R.fn);
5405         res.renderfix = function () {};
5406         return res;
5407     };
5408     R.prototype.clear = function () {
5409         R.eve("clear", this);
5410         this.canvas.innerHTML = E;
5411         this.span = R._g.doc.createElement("span");
5412         this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";
5413         this.canvas.appendChild(this.span);
5414         this.bottom = this.top = null;
5415     };
5416     R.prototype.remove = function () {
5417         R.eve("remove", this);
5418         this.canvas.parentNode.removeChild(this.canvas);
5419         for (var i in this) {
5420             this[i] = removed(i);
5421         }
5422         return true;
5423     };
5424
5425     var setproto = R.st;
5426     for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
5427         setproto[method] = (function (methodname) {
5428             return function () {
5429                 var arg = arguments;
5430                 return this.forEach(function (el) {
5431                     el[methodname].apply(el, arg);
5432                 });
5433             };
5434         })(method);
5435     }
5436 }(window.Raphael);