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