Fixed set removal process and exclude method
[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,
1573                         y1,
1574                         x2,
1575                         y2,
1576                         bb;
1577                     if (t[0] == "t" && tlen == 3) {
1578                         if (absolute) {
1579                             x1 = inver.x(0, 0),
1580                             y1 = inver.y(0, 0),
1581                             x2 = inver.x(t[1], t[2]);
1582                             y2 = inver.y(t[1], t[2]);
1583                             m.translate(x2 - x1, y2 - y1);
1584                         } else {
1585                             m.translate(t[1], t[2]);
1586                         }
1587                     } else if (t[0] == "r") {
1588                         if (tlen == 2) {
1589                             bb = bb || el.getBBox(1);
1590                             m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2);
1591                             deg += t[1];
1592                         } else if (tlen == 4) {
1593                             if (absolute) {
1594                                 x2 = inver.x(t[2], t[3]);
1595                                 y2 = inver.y(t[2], t[3]);
1596                                 m.rotate(t[1], x2, y2);
1597                             } else {
1598                                 m.rotate(t[1], t[2], t[3]);
1599                             }
1600                             deg += t[1];
1601                         }
1602                     } else if (t[0] == "s") {
1603                         if (tlen == 2 || tlen == 3) {
1604                             bb = bb || el.getBBox(1);
1605                             m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2);
1606                             sx *= t[1];
1607                             sy *= t[tlen - 1];
1608                         } else if (tlen == 5) {
1609                             if (absolute) {
1610                                 x2 = inver.x(t[3], t[4]);
1611                                 y2 = inver.y(t[3], t[4]);
1612                                 m.scale(t[1], t[2], x2, y2);
1613                             } else {
1614                                 m.scale(t[1], t[2], t[3], t[4]);
1615                             }
1616                             sx *= t[1];
1617                             sy *= t[2];
1618                         }
1619                     } else if (t[0] == "m" && tlen == 7) {
1620                         m.add(t[1], t[2], t[3], t[4], t[5], t[6]);
1621                     }
1622                     _.dirtyT = 1;
1623                     el.matrix = m;
1624                 }
1625             }
1626
1627             el.matrix = m;
1628
1629             _.sx = sx;
1630             _.sy = sy;
1631             _.deg = deg;
1632             _.dx = dx = m.e;
1633             _.dy = dy = m.f;
1634
1635             if (sx == 1 && sy == 1 && !deg && _.bbox) {
1636                 _.bbox.x += +dx;
1637                 _.bbox.y += +dy;
1638             } else {
1639                 _.dirtyT = 1;
1640             }
1641         },
1642         getEmpty = function (item) {
1643             var l = item[0];
1644             switch (l.toLowerCase()) {
1645                 case "t": return [l, 0, 0];
1646                 case "m": return [l, 1, 0, 0, 1, 0, 0];
1647                 case "r": if (item.length == 4) {
1648                     return [l, 0, item[2], item[3]];
1649                 } else {
1650                     return [l, 0];
1651                 }
1652                 case "s": if (item.length == 5) {
1653                     return [l, 1, 1, item[3], item[4]];
1654                 } else if (item.length == 3) {
1655                     return [l, 1, 1];
1656                 } else {
1657                     return [l, 1];
1658                 }
1659             }
1660         },
1661         equaliseTransform = R._equaliseTransform = function (t1, t2) {
1662             t2 = Str(t2).replace(/\.{3}|\u2026/g, t1);
1663             t1 = R.parseTransformString(t1) || [];
1664             t2 = R.parseTransformString(t2) || [];
1665             var maxlength = mmax(t1.length, t2.length),
1666                 from = [],
1667                 to = [],
1668                 i = 0, j, jj,
1669                 tt1, tt2;
1670             for (; i < maxlength; i++) {
1671                 tt1 = t1[i] || getEmpty(t2[i]);
1672                 tt2 = t2[i] || getEmpty(tt1);
1673                 if ((tt1[0] != tt2[0]) ||
1674                     (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) ||
1675                     (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4]))
1676                     ) {
1677                     return;
1678                 }
1679                 from[i] = [];
1680                 to[i] = [];
1681                 for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) {
1682                     j in tt1 && (from[i][j] = tt1[j]);
1683                     j in tt2 && (to[i][j] = tt2[j]);
1684                 }
1685             }
1686             return {
1687                 from: from,
1688                 to: to
1689             };
1690         };
1691     R._getContainer = function (x, y, w, h) {
1692         var container;
1693         container = h == null && !R.is(x, "object") ? g.doc.getElementById(x) : x;
1694         if (container == null) {
1695             return;
1696         }
1697         if (container.tagName) {
1698             if (y == null) {
1699                 return {
1700                     container: container,
1701                     width: container.style.pixelWidth || container.offsetWidth,
1702                     height: container.style.pixelHeight || container.offsetHeight
1703                 };
1704             } else {
1705                 return {
1706                     container: container,
1707                     width: y,
1708                     height: w
1709                 };
1710             }
1711         }
1712         return {
1713             container: 1,
1714             x: x,
1715             y: y,
1716             width: w,
1717             height: h
1718         };
1719     };
1720     
1721     R.pathToRelative = pathToRelative;
1722     R._engine = {};
1723     
1724     R.path2curve = path2curve;
1725     
1726     R.matrix = function (a, b, c, d, e, f) {
1727         return new Matrix(a, b, c, d, e, f);
1728     };
1729     function Matrix(a, b, c, d, e, f) {
1730         if (a != null) {
1731             this.a = +a;
1732             this.b = +b;
1733             this.c = +c;
1734             this.d = +d;
1735             this.e = +e;
1736             this.f = +f;
1737         } else {
1738             this.a = 1;
1739             this.b = 0;
1740             this.c = 0;
1741             this.d = 1;
1742             this.e = 0;
1743             this.f = 0;
1744         }
1745     }
1746     (function (matrixproto) {
1747         
1748         matrixproto.add = function (a, b, c, d, e, f) {
1749             var out = [[], [], []],
1750                 m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]],
1751                 matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
1752                 x, y, z, res;
1753
1754             if (a && a instanceof Matrix) {
1755                 matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]];
1756             }
1757
1758             for (x = 0; x < 3; x++) {
1759                 for (y = 0; y < 3; y++) {
1760                     res = 0;
1761                     for (z = 0; z < 3; z++) {
1762                         res += m[x][z] * matrix[z][y];
1763                     }
1764                     out[x][y] = res;
1765                 }
1766             }
1767             this.a = out[0][0];
1768             this.b = out[1][0];
1769             this.c = out[0][1];
1770             this.d = out[1][1];
1771             this.e = out[0][2];
1772             this.f = out[1][2];
1773         };
1774         
1775         matrixproto.invert = function () {
1776             var me = this,
1777                 x = me.a * me.d - me.b * me.c;
1778             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);
1779         };
1780         
1781         matrixproto.clone = function () {
1782             return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
1783         };
1784         
1785         matrixproto.translate = function (x, y) {
1786             this.add(1, 0, 0, 1, x, y);
1787         };
1788         
1789         matrixproto.scale = function (x, y, cx, cy) {
1790             y == null && (y = x);
1791             (cx || cy) && this.add(1, 0, 0, 1, cx, cy);
1792             this.add(x, 0, 0, y, 0, 0);
1793             (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy);
1794         };
1795         
1796         matrixproto.rotate = function (a, x, y) {
1797             a = R.rad(a);
1798             x = x || 0;
1799             y = y || 0;
1800             var cos = +math.cos(a).toFixed(9),
1801                 sin = +math.sin(a).toFixed(9);
1802             this.add(cos, sin, -sin, cos, x, y);
1803             this.add(1, 0, 0, 1, -x, -y);
1804         };
1805         
1806         matrixproto.x = function (x, y) {
1807             return x * this.a + y * this.c + this.e;
1808         };
1809         
1810         matrixproto.y = function (x, y) {
1811             return x * this.b + y * this.d + this.f;
1812         };
1813         matrixproto.get = function (i) {
1814             return +this[Str.fromCharCode(97 + i)].toFixed(4);
1815         };
1816         matrixproto.toString = function () {
1817             return R.svg ?
1818                 "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" :
1819                 [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join();
1820         };
1821         matrixproto.toFilter = function () {
1822             return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) +
1823                 ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) +
1824                 ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')";
1825         };
1826         matrixproto.offset = function () {
1827             return [this.e.toFixed(4), this.f.toFixed(4)];
1828         };
1829         function norm(a) {
1830             return a[0] * a[0] + a[1] * a[1];
1831         }
1832         function normalize(a) {
1833             var mag = math.sqrt(norm(a));
1834             a[0] && (a[0] /= mag);
1835             a[1] && (a[1] /= mag);
1836         }
1837         
1838         matrixproto.split = function () {
1839             var out = {};
1840             // translation
1841             out.dx = this.e;
1842             out.dy = this.f;
1843
1844             // scale and shear
1845             var row = [[this.a, this.c], [this.b, this.d]];
1846             out.scalex = math.sqrt(norm(row[0]));
1847             normalize(row[0]);
1848
1849             out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
1850             row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
1851
1852             out.scaley = math.sqrt(norm(row[1]));
1853             normalize(row[1]);
1854             out.shear /= out.scaley;
1855
1856             // rotation
1857             var sin = -row[0][1],
1858                 cos = row[1][1];
1859             if (cos < 0) {
1860                 out.rotate = R.deg(math.acos(cos));
1861                 if (sin < 0) {
1862                     out.rotate = 360 - out.rotate;
1863                 }
1864             } else {
1865                 out.rotate = R.deg(math.asin(sin));
1866             }
1867
1868             out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
1869             out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate;
1870             out.noRotation = !+out.shear.toFixed(9) && !out.rotate;
1871             return out;
1872         };
1873         
1874         matrixproto.toTransformString = function (shorter) {
1875             var s = shorter || this.split();
1876             if (s.isSimple) {
1877                 return "t" + [s.dx, s.dy] + "s" + [s.scalex, s.scaley, 0, 0] + "r" + [s.rotate, 0, 0];
1878             } else {
1879                 return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
1880             }
1881         };
1882     })(Matrix.prototype);
1883
1884     // WebKit rendering bug workaround method
1885     var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/);
1886     if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") ||
1887         (navigator.vendor == "Google Inc." && version && version[1] < 8)) {
1888         
1889         paperproto.safari = function () {
1890             var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"});
1891             setTimeout(function () {rect.remove();});
1892         };
1893     } else {
1894         paperproto.safari = fun;
1895     }
1896  
1897     var preventDefault = function () {
1898         this.returnValue = false;
1899     },
1900     preventTouch = function () {
1901         return this.originalEvent.preventDefault();
1902     },
1903     stopPropagation = function () {
1904         this.cancelBubble = true;
1905     },
1906     stopTouch = function () {
1907         return this.originalEvent.stopPropagation();
1908     },
1909     addEvent = (function () {
1910         if (g.doc.addEventListener) {
1911             return function (obj, type, fn, element) {
1912                 var realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
1913                     f = function (e) {
1914                         var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
1915                             scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
1916                             x = e.clientX + scrollX,
1917                             y = e.clientY + scrollY;
1918                     if (supportsTouch && touchMap[has](type)) {
1919                         for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
1920                             if (e.targetTouches[i].target == obj) {
1921                                 var olde = e;
1922                                 e = e.targetTouches[i];
1923                                 e.originalEvent = olde;
1924                                 e.preventDefault = preventTouch;
1925                                 e.stopPropagation = stopTouch;
1926                                 break;
1927                             }
1928                         }
1929                     }
1930                     return fn.call(element, e, x, y);
1931                 };
1932                 obj.addEventListener(realName, f, false);
1933                 return function () {
1934                     obj.removeEventListener(realName, f, false);
1935                     return true;
1936                 };
1937             };
1938         } else if (g.doc.attachEvent) {
1939             return function (obj, type, fn, element) {
1940                 var f = function (e) {
1941                     e = e || g.win.event;
1942                     var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
1943                         scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
1944                         x = e.clientX + scrollX,
1945                         y = e.clientY + scrollY;
1946                     e.preventDefault = e.preventDefault || preventDefault;
1947                     e.stopPropagation = e.stopPropagation || stopPropagation;
1948                     return fn.call(element, e, x, y);
1949                 };
1950                 obj.attachEvent("on" + type, f);
1951                 var detacher = function () {
1952                     obj.detachEvent("on" + type, f);
1953                     return true;
1954                 };
1955                 return detacher;
1956             };
1957         }
1958     })(),
1959     drag = [],
1960     dragMove = function (e) {
1961         var x = e.clientX,
1962             y = e.clientY,
1963             scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
1964             scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft,
1965             dragi,
1966             j = drag.length;
1967         while (j--) {
1968             dragi = drag[j];
1969             if (supportsTouch) {
1970                 var i = e.touches.length,
1971                     touch;
1972                 while (i--) {
1973                     touch = e.touches[i];
1974                     if (touch.identifier == dragi.el._drag.id) {
1975                         x = touch.clientX;
1976                         y = touch.clientY;
1977                         (e.originalEvent ? e.originalEvent : e).preventDefault();
1978                         break;
1979                     }
1980                 }
1981             } else {
1982                 e.preventDefault();
1983             }
1984             var node = dragi.el.node,
1985                 o,
1986                 next = node.nextSibling,
1987                 parent = node.parentNode,
1988                 display = node.style.display;
1989             g.win.opera && parent.removeChild(node);
1990             node.style.display = "none";
1991             o = dragi.el.paper.getElementByPoint(x, y);
1992             node.style.display = display;
1993             g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
1994             o && eve("drag.over." + dragi.el.id, dragi.el, o);
1995             x += scrollX;
1996             y += scrollY;
1997             eve("drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
1998         }
1999     },
2000     dragUp = function (e) {
2001         R.unmousemove(dragMove).unmouseup(dragUp);
2002         var i = drag.length,
2003             dragi;
2004         while (i--) {
2005             dragi = drag[i];
2006             dragi.el._drag = {};
2007             eve("drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
2008         }
2009         drag = [];
2010     },
2011     
2012     elproto = R.el = {};
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     
2043     
2044     
2045     for (var i = events.length; i--;) {
2046         (function (eventName) {
2047             R[eventName] = elproto[eventName] = function (fn, scope) {
2048                 if (R.is(fn, "function")) {
2049                     this.events = this.events || [];
2050                     this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)});
2051                 }
2052                 return this;
2053             };
2054             R["un" + eventName] = elproto["un" + eventName] = function (fn) {
2055                 var events = this.events,
2056                     l = events.length;
2057                 while (l--) if (events[l].name == eventName && events[l].f == fn) {
2058                     events[l].unbind();
2059                     events.splice(l, 1);
2060                     !events.length && delete this.events;
2061                     return this;
2062                 }
2063                 return this;
2064             };
2065         })(events[i]);
2066     }
2067     
2068     
2069     elproto.data = function (key, value) {
2070         var data = eldata[this.id] = eldata[this.id] || {};
2071         if (arguments.length == 1) {
2072             if (R.is(key, "object")) {
2073                 for (var i in key) if (key[has](i)) {
2074                     this.data(i, key[i]);
2075                 }
2076                 return this;
2077             }
2078             eve("data.get." + this.id, this, data[key], key);
2079             return data[key];
2080         }
2081         data[key] = value;
2082         eve("data.set." + this.id, this, value, key);
2083         return this;
2084     };
2085     
2086     elproto.removeData = function (key) {
2087         if (key == null) {
2088             eldata[this.id] = {};
2089         } else {
2090             eldata[this.id] && delete eldata[this.id][key];
2091         }
2092         return this;
2093     };
2094     
2095     elproto.hover = function (f_in, f_out, scope_in, scope_out) {
2096         return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
2097     };
2098     
2099     elproto.unhover = function (f_in, f_out) {
2100         return this.unmouseover(f_in).unmouseout(f_out);
2101     };
2102     
2103     elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
2104         function start(e) {
2105             (e.originalEvent || e).preventDefault();
2106             var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
2107                 scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
2108             this._drag.x = e.clientX + scrollX;
2109             this._drag.y = e.clientY + scrollY;
2110             this._drag.id = e.identifier;
2111             !drag.length && R.mousemove(dragMove).mouseup(dragUp);
2112             drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope});
2113             onstart && eve.on("drag.start." + this.id, onstart);
2114             onmove && eve.on("drag.move." + this.id, onmove);
2115             onend && eve.on("drag.end." + this.id, onend);
2116             eve("drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e);
2117         }
2118         this._drag = {};
2119         this.mousedown(start);
2120         return this;
2121     };
2122     
2123     elproto.onDragOver = function (f) {
2124         f ? eve.on("drag.over." + this.id, f) : eve.unbind("drag.over." + this.id);
2125     };
2126     
2127     elproto.undrag = function () {
2128         var i = drag.length;
2129         while (i--) if (drag[i].el == this) {
2130             R.unmousedown(drag[i].start);
2131             drag.splice(i++, 1);
2132             eve.unbind("drag.*." + this.id);
2133         }
2134         !drag.length && R.unmousemove(dragMove).unmouseup(dragUp);
2135     };
2136     
2137     paperproto.circle = function (x, y, r) {
2138         var out = R._engine.circle(this, x || 0, y || 0, r || 0);
2139         this.__set__ && this.__set__.push(out);
2140         return out;
2141     };
2142     
2143     paperproto.rect = function (x, y, w, h, r) {
2144         var out = R._engine.rect(this, x || 0, y || 0, w || 0, h || 0, r || 0);
2145         this.__set__ && this.__set__.push(out);
2146         return out;
2147     };
2148     
2149     paperproto.ellipse = function (x, y, rx, ry) {
2150         var out = R._engine.ellipse(this, x || 0, y || 0, rx || 0, ry || 0);
2151         this.__set__ && this.__set__.push(out);
2152         return out;
2153     };
2154     
2155     paperproto.path = function (pathString) {
2156         pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E);
2157         var out = R._engine.path(R.format[apply](R, arguments), this);
2158         this.__set__ && this.__set__.push(out);
2159         return out;
2160     };
2161     
2162     paperproto.image = function (src, x, y, w, h) {
2163         var out = R._engine.image(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0);
2164         this.__set__ && this.__set__.push(out);
2165         return out;
2166     };
2167     
2168     paperproto.text = function (x, y, text) {
2169         var out = R._engine.text(this, x || 0, y || 0, Str(text));
2170         this.__set__ && this.__set__.push(out);
2171         return out;
2172     };
2173     
2174     paperproto.set = function (itemsArray) {
2175         !R.is(itemsArray, "array") && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length));
2176         var out = new Set(itemsArray);
2177         this.__set__ && this.__set__.push(out);
2178         return out;
2179     };
2180     
2181     paperproto.setStart = function (set) {
2182         this.__set__ = set || this.set();
2183     };
2184     
2185     paperproto.setFinish = function (set) {
2186         var out = this.__set__;
2187         delete this.__set__;
2188         return out;
2189     };
2190     
2191     paperproto.setSize = function (width, height) {
2192         return R._engine.setSize.call(this, width, height);
2193     };
2194     
2195     paperproto.setViewBox = function (x, y, w, h, fit) {
2196         return R._engine.setViewBox.call(this, x, y, w, h, fit);
2197     };
2198     
2199     
2200     paperproto.top = paperproto.bottom = null;
2201     
2202     paperproto.raphael = R;
2203     var getOffset = function (elem) {
2204         var box = elem.getBoundingClientRect(),
2205             doc = elem.ownerDocument,
2206             body = doc.body,
2207             docElem = doc.documentElement,
2208             clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
2209             top  = box.top  + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop,
2210             left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
2211         return {
2212             y: top,
2213             x: left
2214         };
2215     };
2216     
2217     paperproto.getElementByPoint = function (x, y) {
2218         var paper = this,
2219             svg = paper.canvas,
2220             target = g.doc.elementFromPoint(x, y);
2221         if (g.win.opera && target.tagName == "svg") {
2222             var so = getOffset(svg),
2223                 sr = svg.createSVGRect();
2224             sr.x = x - so.x;
2225             sr.y = y - so.y;
2226             sr.width = sr.height = 1;
2227             var hits = svg.getIntersectionList(sr, null);
2228             if (hits.length) {
2229                 target = hits[hits.length - 1];
2230             }
2231         }
2232         if (!target) {
2233             return null;
2234         }
2235         while (target.parentNode && target != svg.parentNode && !target.raphael) {
2236             target = target.parentNode;
2237         }
2238         target == paper.canvas.parentNode && (target = svg);
2239         target = target && target.raphael ? paper.getById(target.raphaelid) : null;
2240         return target;
2241     };
2242     
2243     paperproto.getById = function (id) {
2244         var bot = this.bottom;
2245         while (bot) {
2246             if (bot.id == id) {
2247                 return bot;
2248             }
2249             bot = bot.next;
2250         }
2251         return null;
2252     };
2253     
2254     paperproto.forEach = function (callback, thisArg) {
2255         var bot = this.bottom;
2256         while (bot) {
2257             if (callback.call(thisArg, bot) === false) {
2258                 return this;
2259             }
2260             bot = bot.next;
2261         }
2262         return this;
2263     };
2264     function x_y() {
2265         return this.x + S + this.y;
2266     }
2267     function x_y_w_h() {
2268         return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
2269     }
2270     
2271     elproto.getBBox = function (isWithoutTransform) {
2272         if (this.removed) {
2273             return {};
2274         }
2275         var _ = this._;
2276         if (isWithoutTransform) {
2277             if (_.dirty || !_.bboxwt) {
2278                 this.realPath = getPath[this.type](this);
2279                 _.bboxwt = pathDimensions(this.realPath);
2280                 _.bboxwt.toString = x_y_w_h;
2281                 _.dirty = 0;
2282             }
2283             return _.bboxwt;
2284         }
2285         if (_.dirty || _.dirtyT || !_.bbox) {
2286             if (_.dirty || !this.realPath) {
2287                 _.bboxwt = 0;
2288                 this.realPath = getPath[this.type](this);
2289             }
2290             _.bbox = pathDimensions(mapPath(this.realPath, this.matrix));
2291             _.bbox.toString = x_y_w_h;
2292             _.dirty = _.dirtyT = 0;
2293         }
2294         return _.bbox;
2295     };
2296     
2297     elproto.clone = function () {
2298         if (this.removed) {
2299             return null;
2300         }
2301         var out = this.paper[this.type]().attr(this.attr());
2302         this.__set__ && this.__set__.push(out);
2303         return out;
2304     };
2305     
2306     elproto.glow = function (glow) {
2307         if (this.type == "text") {
2308             return null;
2309         }
2310         glow = glow || {};
2311         var s = {
2312             width: (glow.width || 10) + (+this.attr("stroke-width") || 1),
2313             fill: glow.fill || false,
2314             opacity: glow.opacity || .5,
2315             offsetx: glow.offsetx || 0,
2316             offsety: glow.offsety || 0,
2317             color: glow.color || "#000"
2318         },
2319             c = s.width / 2,
2320             r = this.paper,
2321             out = r.set(),
2322             path = this.realPath || getPath[this.type](this);
2323         path = this.matrix ? mapPath(path, this.matrix) : path;
2324         for (var i = 1; i < c + 1; i++) {
2325             out.push(r.path(path).attr({
2326                 stroke: s.color,
2327                 fill: s.fill ? s.color : "none",
2328                 "stroke-linejoin": "round",
2329                 "stroke-linecap": "round",
2330                 "stroke-width": +(s.width / c * i).toFixed(3),
2331                 opacity: +(s.opacity / c).toFixed(3)
2332             }));
2333         }
2334         return out.insertBefore(this).translate(s.offsetx, s.offsety);
2335     };
2336     var curveslengths = {},
2337     getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {
2338         var len = 0,
2339             precision = 100,
2340             name = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y].join(),
2341             cache = curveslengths[name],
2342             old, dot;
2343         !cache && (curveslengths[name] = cache = {data: []});
2344         cache.timer && clearTimeout(cache.timer);
2345         cache.timer = setTimeout(function () {delete curveslengths[name];}, 2e3);
2346         if (length != null && !cache.precision) {
2347             var total = getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
2348             cache.precision = ~~total * 10;
2349             cache.data = [];
2350         }
2351         precision = cache.precision || precision;
2352         for (var i = 0; i < precision + 1; i++) {
2353             if (cache.data[i * precision]) {
2354                 dot = cache.data[i * precision];
2355             } else {
2356                 dot = R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i / precision);
2357                 cache.data[i * precision] = dot;
2358             }
2359             i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5));
2360             if (length != null && len >= length) {
2361                 return dot;
2362             }
2363             old = dot;
2364         }
2365         if (length == null) {
2366             return len;
2367         }
2368     },
2369     getLengthFactory = function (istotal, subpath) {
2370         return function (path, length, onlystart) {
2371             path = path2curve(path);
2372             var x, y, p, l, sp = "", subpaths = {}, point,
2373                 len = 0;
2374             for (var i = 0, ii = path.length; i < ii; i++) {
2375                 p = path[i];
2376                 if (p[0] == "M") {
2377                     x = +p[1];
2378                     y = +p[2];
2379                 } else {
2380                     l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
2381                     if (len + l > length) {
2382                         if (subpath && !subpaths.start) {
2383                             point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
2384                             sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y];
2385                             if (onlystart) {return sp;}
2386                             subpaths.start = sp;
2387                             sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join();
2388                             len += l;
2389                             x = +p[5];
2390                             y = +p[6];
2391                             continue;
2392                         }
2393                         if (!istotal && !subpath) {
2394                             point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
2395                             return {x: point.x, y: point.y, alpha: point.alpha};
2396                         }
2397                     }
2398                     len += l;
2399                     x = +p[5];
2400                     y = +p[6];
2401                 }
2402                 sp += p.shift() + p;
2403             }
2404             subpaths.end = sp;
2405             point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
2406             point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha});
2407             return point;
2408         };
2409     };
2410     var getTotalLength = getLengthFactory(1),
2411         getPointAtLength = getLengthFactory(),
2412         getSubpathsAtLength = getLengthFactory(0, 1);
2413     
2414     R.getTotalLength = getTotalLength;
2415     
2416     R.getPointAtLength = getPointAtLength;
2417     
2418     R.getSubpath = function (path, from, to) {
2419         if (this.getTotalLength(path) - to < 1e-6) {
2420             return getSubpathsAtLength(path, from).end;
2421         }
2422         var a = getSubpathsAtLength(path, to, 1);
2423         return from ? getSubpathsAtLength(a, from).end : a;
2424     };
2425     
2426     elproto.getTotalLength = function () {
2427         if (this.type != "path") {return;}
2428         if (this.node.getTotalLength) {
2429             return this.node.getTotalLength();
2430         }
2431         return getTotalLength(this.attrs.path);
2432     };
2433     
2434     elproto.getPointAtLength = function (length) {
2435         if (this.type != "path") {return;}
2436         return getPointAtLength(this.attrs.path, length);
2437     };
2438     
2439     elproto.getSubpath = function (from, to) {
2440         if (this.type != "path") {return;}
2441         return R.getSubpath(this.attrs.path, from, to);
2442     };
2443     
2444     var ef = R.easing_formulas = {
2445         linear: function (n) {
2446             return n;
2447         },
2448         "<": function (n) {
2449             return pow(n, 1.7);
2450         },
2451         ">": function (n) {
2452             return pow(n, .48);
2453         },
2454         "<>": function (n) {
2455             var q = .48 - n / 1.04,
2456                 Q = math.sqrt(.1734 + q * q),
2457                 x = Q - q,
2458                 X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1),
2459                 y = -Q - q,
2460                 Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1),
2461                 t = X + Y + .5;
2462             return (1 - t) * 3 * t * t + t * t * t;
2463         },
2464         backIn: function (n) {
2465             var s = 1.70158;
2466             return n * n * ((s + 1) * n - s);
2467         },
2468         backOut: function (n) {
2469             n = n - 1;
2470             var s = 1.70158;
2471             return n * n * ((s + 1) * n + s) + 1;
2472         },
2473         elastic: function (n) {
2474             if (n == !!n) {
2475                 return n;
2476             }
2477             return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1;
2478         },
2479         bounce: function (n) {
2480             var s = 7.5625,
2481                 p = 2.75,
2482                 l;
2483             if (n < (1 / p)) {
2484                 l = s * n * n;
2485             } else {
2486                 if (n < (2 / p)) {
2487                     n -= (1.5 / p);
2488                     l = s * n * n + .75;
2489                 } else {
2490                     if (n < (2.5 / p)) {
2491                         n -= (2.25 / p);
2492                         l = s * n * n + .9375;
2493                     } else {
2494                         n -= (2.625 / p);
2495                         l = s * n * n + .984375;
2496                     }
2497                 }
2498             }
2499             return l;
2500         }
2501     };
2502     ef.easeIn = ef["ease-in"] = ef["<"];
2503     ef.easeOut = ef["ease-out"] = ef[">"];
2504     ef.easeInOut = ef["ease-in-out"] = ef["<>"];
2505     ef["back-in"] = ef.backIn;
2506     ef["back-out"] = ef.backOut;
2507
2508     var animationElements = [],
2509         requestAnimFrame = window.requestAnimationFrame       ||
2510                            window.webkitRequestAnimationFrame ||
2511                            window.mozRequestAnimationFrame    ||
2512                            window.oRequestAnimationFrame      ||
2513                            window.msRequestAnimationFrame     ||
2514                            function (callback) {
2515                                setTimeout(callback, 16);
2516                            },
2517         animation = function () {
2518             var Now = +new Date,
2519                 l = 0;
2520             for (; l < animationElements.length; l++) {
2521                 var e = animationElements[l];
2522                 if (e.el.removed || e.paused) {
2523                     continue;
2524                 }
2525                 var time = Now - e.start,
2526                     ms = e.ms,
2527                     easing = e.easing,
2528                     from = e.from,
2529                     diff = e.diff,
2530                     to = e.to,
2531                     t = e.t,
2532                     that = e.el,
2533                     set = {},
2534                     now;
2535                 if (e.initstatus) {
2536                     time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms;
2537                     e.status = e.initstatus;
2538                     delete e.initstatus;
2539                     e.stop && animationElements.splice(l--, 1);
2540                 } else {
2541                     e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top;
2542                 }
2543                 if (time < 0) {
2544                     continue;
2545                 }
2546                 if (time < ms) {
2547                     var pos = easing(time / ms);
2548                     for (var attr in from) if (from[has](attr)) {
2549                         switch (availableAnimAttrs[attr]) {
2550                             case nu:
2551                                 now = +from[attr] + pos * ms * diff[attr];
2552                                 break;
2553                             case "colour":
2554                                 now = "rgb(" + [
2555                                     upto255(round(from[attr].r + pos * ms * diff[attr].r)),
2556                                     upto255(round(from[attr].g + pos * ms * diff[attr].g)),
2557                                     upto255(round(from[attr].b + pos * ms * diff[attr].b))
2558                                 ].join(",") + ")";
2559                                 break;
2560                             case "path":
2561                                 now = [];
2562                                 for (var i = 0, ii = from[attr].length; i < ii; i++) {
2563                                     now[i] = [from[attr][i][0]];
2564                                     for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
2565                                         now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j];
2566                                     }
2567                                     now[i] = now[i].join(S);
2568                                 }
2569                                 now = now.join(S);
2570                                 break;
2571                             case "transform":
2572                                 if (diff[attr].real) {
2573                                     now = [];
2574                                     for (i = 0, ii = from[attr].length; i < ii; i++) {
2575                                         now[i] = [from[attr][i][0]];
2576                                         for (j = 1, jj = from[attr][i].length; j < jj; j++) {
2577                                             now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j];
2578                                         }
2579                                     }
2580                                 } else {
2581                                     var get = function (i) {
2582                                         return +from[attr][i] + pos * ms * diff[attr][i];
2583                                     };
2584                                     // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]];
2585                                     now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]];
2586                                 }
2587                                 break;
2588                             case "csv":
2589                                 if (attr == "clip-rect") {
2590                                     now = [];
2591                                     i = 4;
2592                                     while (i--) {
2593                                         now[i] = +from[attr][i] + pos * ms * diff[attr][i];
2594                                     }
2595                                 }
2596                                 break;
2597                             default:
2598                                 var from2 = [].concat(from[attr]);
2599                                 now = [];
2600                                 i = that.paper.customAttributes[attr].length;
2601                                 while (i--) {
2602                                     now[i] = +from2[i] + pos * ms * diff[attr][i];
2603                                 }
2604                                 break;
2605                         }
2606                         set[attr] = now;
2607                     }
2608                     that.attr(set);
2609                     (function (id, that, anim) {
2610                         setTimeout(function () {
2611                             eve("anim.frame." + id, that, anim);
2612                         });
2613                     })(that.id, that, e.anim);
2614                 } else {
2615                     (function(f, el, a) {
2616                         setTimeout(function() {
2617                             eve("anim.frame." + el.id, el, a);
2618                             eve("anim.finish." + el.id, el, a);
2619                             R.is(f, "function") && f.call(el);
2620                         });
2621                     })(e.callback, that, e.anim);
2622                     that.attr(to);
2623                     animationElements.splice(l--, 1);
2624                     if (e.repeat > 1 && !e.next) {
2625                         runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1);
2626                     }
2627                     if (e.next && !e.stop) {
2628                         runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat);
2629                     }
2630                 }
2631             }
2632             R.svg && that && that.paper && that.paper.safari();
2633             animationElements.length && requestAnimFrame(animation);
2634         },
2635         upto255 = function (color) {
2636             return color > 255 ? 255 : color < 0 ? 0 : color;
2637         };
2638     
2639     elproto.animateWith = function (element, anim, params, ms, easing, callback) {
2640         var a = params ? R.animation(params, ms, easing, callback) : anim;
2641             status = element.status(anim);
2642         return this.animate(a).status(a, status * anim.ms / a.ms);
2643     };
2644     function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) {
2645         var cx = 3 * p1x,
2646             bx = 3 * (p2x - p1x) - cx,
2647             ax = 1 - cx - bx,
2648             cy = 3 * p1y,
2649             by = 3 * (p2y - p1y) - cy,
2650             ay = 1 - cy - by;
2651         function sampleCurveX(t) {
2652             return ((ax * t + bx) * t + cx) * t;
2653         }
2654         function solve(x, epsilon) {
2655             var t = solveCurveX(x, epsilon);
2656             return ((ay * t + by) * t + cy) * t;
2657         }
2658         function solveCurveX(x, epsilon) {
2659             var t0, t1, t2, x2, d2, i;
2660             for(t2 = x, i = 0; i < 8; i++) {
2661                 x2 = sampleCurveX(t2) - x;
2662                 if (abs(x2) < epsilon) {
2663                     return t2;
2664                 }
2665                 d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
2666                 if (abs(d2) < 1e-6) {
2667                     break;
2668                 }
2669                 t2 = t2 - x2 / d2;
2670             }
2671             t0 = 0;
2672             t1 = 1;
2673             t2 = x;
2674             if (t2 < t0) {
2675                 return t0;
2676             }
2677             if (t2 > t1) {
2678                 return t1;
2679             }
2680             while (t0 < t1) {
2681                 x2 = sampleCurveX(t2);
2682                 if (abs(x2 - x) < epsilon) {
2683                     return t2;
2684                 }
2685                 if (x > x2) {
2686                     t0 = t2;
2687                 } else {
2688                     t1 = t2;
2689                 }
2690                 t2 = (t1 - t0) / 2 + t0;
2691             }
2692             return t2;
2693         }
2694         return solve(t, 1 / (200 * duration));
2695     }
2696     elproto.onAnimation = function (f) {
2697         f ? eve.on("anim.frame." + this.id, f) : eve.unbind("anim.frame." + this.id);
2698         return this;
2699     };
2700     function Animation(anim, ms) {
2701         var percents = [],
2702             newAnim = {};
2703         this.ms = ms;
2704         this.times = 1;
2705         if (anim) {
2706             for (var attr in anim) if (anim[has](attr)) {
2707                 newAnim[toFloat(attr)] = anim[attr];
2708                 percents.push(toFloat(attr));
2709             }
2710             percents.sort(sortByNumber);
2711         }
2712         this.anim = newAnim;
2713         this.top = percents[percents.length - 1];
2714         this.percents = percents;
2715     }
2716     
2717     Animation.prototype.delay = function (delay) {
2718         var a = new Animation(this.anim, this.ms);
2719         a.times = this.times;
2720         a.del = +delay || 0;
2721         return a;
2722     };
2723     
2724     Animation.prototype.repeat = function (times) { 
2725         var a = new Animation(this.anim, this.ms);
2726         a.del = this.del;
2727         a.times = math.floor(mmax(times, 0)) || 1;
2728         return a;
2729     };
2730     function runAnimation(anim, element, percent, status, totalOrigin, times) {
2731         percent = toFloat(percent);
2732         var params,
2733             isInAnim,
2734             isInAnimSet,
2735             percents = [],
2736             next,
2737             prev,
2738             timestamp,
2739             ms = anim.ms,
2740             from = {},
2741             to = {},
2742             diff = {};
2743         if (status) {
2744             for (i = 0, ii = animationElements.length; i < ii; i++) {
2745                 var e = animationElements[i];
2746                 if (e.el.id == element.id && e.anim == anim) {
2747                     if (e.percent != percent) {
2748                         animationElements.splice(i, 1);
2749                         isInAnimSet = 1;
2750                     } else {
2751                         isInAnim = e;
2752                     }
2753                     element.attr(e.totalOrigin);
2754                     break;
2755                 }
2756             }
2757         } else {
2758             status = +to; // NaN
2759         }
2760         for (var i = 0, ii = anim.percents.length; i < ii; i++) {
2761             if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) {
2762                 percent = anim.percents[i];
2763                 prev = anim.percents[i - 1] || 0;
2764                 ms = ms / anim.top * (percent - prev);
2765                 next = anim.percents[i + 1];
2766                 params = anim.anim[percent];
2767                 break;
2768             } else if (status) {
2769                 element.attr(anim.anim[anim.percents[i]]);
2770             }
2771         }
2772         if (!params) {
2773             return;
2774         }
2775         if (!isInAnim) {
2776             for (attr in params) if (params[has](attr)) {
2777                 if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) {
2778                     from[attr] = element.attr(attr);
2779                     (from[attr] == null) && (from[attr] = availableAttrs[attr]);
2780                     to[attr] = params[attr];
2781                     switch (availableAnimAttrs[attr]) {
2782                         case nu:
2783                             diff[attr] = (to[attr] - from[attr]) / ms;
2784                             break;
2785                         case "colour":
2786                             from[attr] = R.getRGB(from[attr]);
2787                             var toColour = R.getRGB(to[attr]);
2788                             diff[attr] = {
2789                                 r: (toColour.r - from[attr].r) / ms,
2790                                 g: (toColour.g - from[attr].g) / ms,
2791                                 b: (toColour.b - from[attr].b) / ms
2792                             };
2793                             break;
2794                         case "path":
2795                             var pathes = path2curve(from[attr], to[attr]),
2796                                 toPath = pathes[1];
2797                             from[attr] = pathes[0];
2798                             diff[attr] = [];
2799                             for (i = 0, ii = from[attr].length; i < ii; i++) {
2800                                 diff[attr][i] = [0];
2801                                 for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
2802                                     diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms;
2803                                 }
2804                             }
2805                             break;
2806                         case "transform":
2807                             var _ = element._,
2808                                 eq = equaliseTransform(_[attr], to[attr]);
2809                             if (eq) {
2810                                 from[attr] = eq.from;
2811                                 to[attr] = eq.to;
2812                                 diff[attr] = [];
2813                                 diff[attr].real = true;
2814                                 for (i = 0, ii = from[attr].length; i < ii; i++) {
2815                                     diff[attr][i] = [from[attr][i][0]];
2816                                     for (j = 1, jj = from[attr][i].length; j < jj; j++) {
2817                                         diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms;
2818                                     }
2819                                 }
2820                             } else {
2821                                 var m = (element.matrix || new Matrix),
2822                                     to2 = {
2823                                         _: {transform: _.transform},
2824                                         getBBox: function () {
2825                                             return element.getBBox(1);
2826                                         }
2827                                     };
2828                                 from[attr] = [
2829                                     m.a,
2830                                     m.b,
2831                                     m.c,
2832                                     m.d,
2833                                     m.e,
2834                                     m.f
2835                                 ];
2836                                 extractTransform(to2, to[attr]);
2837                                 to[attr] = to2._.transform;
2838                                 diff[attr] = [
2839                                     (to2.matrix.a - m.a) / ms,
2840                                     (to2.matrix.b - m.b) / ms,
2841                                     (to2.matrix.c - m.c) / ms,
2842                                     (to2.matrix.d - m.d) / ms,
2843                                     (to2.matrix.e - m.e) / ms,
2844                                     (to2.matrix.e - m.f) / ms
2845                                 ];
2846                                 // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy];
2847                                 // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }};
2848                                 // extractTransform(to2, to[attr]);
2849                                 // diff[attr] = [
2850                                 //     (to2._.sx - _.sx) / ms,
2851                                 //     (to2._.sy - _.sy) / ms,
2852                                 //     (to2._.deg - _.deg) / ms,
2853                                 //     (to2._.dx - _.dx) / ms,
2854                                 //     (to2._.dy - _.dy) / ms
2855                                 // ];
2856                             }
2857                             break;
2858                         case "csv":
2859                             var values = Str(params[attr]).split(separator),
2860                                 from2 = Str(from[attr]).split(separator);
2861                             if (attr == "clip-rect") {
2862                                 from[attr] = from2;
2863                                 diff[attr] = [];
2864                                 i = from2.length;
2865                                 while (i--) {
2866                                     diff[attr][i] = (values[i] - from[attr][i]) / ms;
2867                                 }
2868                             }
2869                             to[attr] = values;
2870                             break;
2871                         default:
2872                             values = [].concat(params[attr]);
2873                             from2 = [].concat(from[attr]);
2874                             diff[attr] = [];
2875                             i = element.paper.customAttributes[attr].length;
2876                             while (i--) {
2877                                 diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms;
2878                             }
2879                             break;
2880                     }
2881                 }
2882             }
2883             var easing = params.easing,
2884                 easyeasy = R.easing_formulas[easing];
2885             if (!easyeasy) {
2886                 easyeasy = Str(easing).match(bezierrg);
2887                 if (easyeasy && easyeasy.length == 5) {
2888                     var curve = easyeasy;
2889                     easyeasy = function (t) {
2890                         return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms);
2891                     };
2892                 } else {
2893                     easyeasy = pipe;
2894                 }
2895             }
2896             timestamp = params.start || anim.start || +new Date;
2897             e = {
2898                 anim: anim,
2899                 percent: percent,
2900                 timestamp: timestamp,
2901                 start: timestamp + (anim.del || 0),
2902                 status: 0,
2903                 initstatus: status || 0,
2904                 stop: false,
2905                 ms: ms,
2906                 easing: easyeasy,
2907                 from: from,
2908                 diff: diff,
2909                 to: to,
2910                 el: element,
2911                 callback: params.callback,
2912                 prev: prev,
2913                 next: next,
2914                 repeat: times || anim.times,
2915                 origin: element.attr(),
2916                 totalOrigin: totalOrigin
2917             };
2918             animationElements.push(e);
2919             if (status && !isInAnim && !isInAnimSet) {
2920                 e.stop = true;
2921                 e.start = new Date - ms * status;
2922                 if (animationElements.length == 1) {
2923                     return animation();
2924                 }
2925             }
2926             if (isInAnimSet) {
2927                 e.start = new Date - e.ms * status;
2928             }
2929             animationElements.length == 1 && requestAnimFrame(animation);
2930         } else {
2931             isInAnim.initstatus = status;
2932             isInAnim.start = new Date - isInAnim.ms * status;
2933         }
2934         eve("anim.start." + element.id, element, anim);
2935     }
2936     
2937     R.animation = function (params, ms, easing, callback) {
2938         if (params instanceof Animation) {
2939             return params;
2940         }
2941         if (R.is(easing, "function") || !easing) {
2942             callback = callback || easing || null;
2943             easing = null;
2944         }
2945         params = Object(params);
2946         ms = +ms || 0;
2947         var p = {},
2948             json,
2949             attr;
2950         for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) {
2951             json = true;
2952             p[attr] = params[attr];
2953         }
2954         if (!json) {
2955             return new Animation(params, ms);
2956         } else {
2957             easing && (p.easing = easing);
2958             callback && (p.callback = callback);
2959             return new Animation({100: p}, ms);
2960         }
2961     };
2962     
2963     elproto.animate = function (params, ms, easing, callback) {
2964         var element = this;
2965         if (element.removed) {
2966             callback && callback.call(element);
2967             return element;
2968         }
2969         var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback);
2970         runAnimation(anim, element, anim.percents[0], null, element.attr());
2971         return element;
2972     };
2973     
2974     elproto.setTime = function (anim, value) {
2975         if (anim && value != null) {
2976             this.status(anim, mmin(value, anim.ms) / anim.ms);
2977         }
2978         return this;
2979     };
2980     
2981     elproto.status = function (anim, value) {
2982         var out = [],
2983             i = 0,
2984             len,
2985             e;
2986         if (value != null) {
2987             runAnimation(anim, this, -1, mmin(value, 1));
2988             return this;
2989         } else {
2990             len = animationElements.length;
2991             for (; i < len; i++) {
2992                 e = animationElements[i];
2993                 if (e.el.id == this.id && (!anim || e.anim == anim)) {
2994                     if (anim) {
2995                         return e.status;
2996                     }
2997                     out.push({
2998                         anim: e.anim,
2999                         status: e.status
3000                     });
3001                 }
3002             }
3003             if (anim) {
3004                 return 0;
3005             }
3006             return out;
3007         }
3008     };
3009     
3010     elproto.pause = function (anim) {
3011         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
3012             if (eve("anim.pause." + this.id, this, animationElements[i].anim) !== false) {
3013                 animationElements[i].paused = true;
3014             }
3015         }
3016         return this;
3017     };
3018     
3019     elproto.resume = function (anim) {
3020         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
3021             var e = animationElements[i];
3022             if (eve("anim.resume." + this.id, this, e.anim) !== false) {
3023                 delete e.paused;
3024                 this.status(e.anim, e.status);
3025             }
3026         }
3027         return this;
3028     };
3029     
3030     elproto.stop = function (anim) {
3031         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
3032             if (eve("anim.stop." + this.id, this, animationElements[i].anim) !== false) {
3033                 animationElements.splice(i--, 1);
3034             }
3035         }
3036         return this;
3037     };
3038     elproto.toString = function () {
3039         return "Rapha\xebl\u2019s object";
3040     };
3041
3042     // Set
3043     var Set = function (items) {
3044         this.items = [];
3045         this.length = 0;
3046         this.type = "set";
3047         if (items) {
3048             for (var i = 0, ii = items.length; i < ii; i++) {
3049                 if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) {
3050                     this[this.items.length] = this.items[this.items.length] = items[i];
3051                     this.length++;
3052                 }
3053             }
3054         }
3055     },
3056     setproto = Set.prototype;
3057     
3058     setproto.push = function () {
3059         var item,
3060             len;
3061         for (var i = 0, ii = arguments.length; i < ii; i++) {
3062             item = arguments[i];
3063             if (item && (item.constructor == elproto.constructor || item.constructor == Set)) {
3064                 len = this.items.length;
3065                 this[len] = this.items[len] = item;
3066                 this.length++;
3067             }
3068         }
3069         return this;
3070     };
3071     
3072     setproto.pop = function () {
3073         this.length && delete this[this.length--];
3074         return this.items.pop();
3075     };
3076     
3077     setproto.forEach = function (callback, thisArg) {
3078         for (var i = 0, ii = this.items.length; i < ii; i++) {
3079             if (callback.call(thisArg, this.items[i], i) === false) {
3080                 return this;
3081             }
3082         }
3083         return this;
3084     };
3085     for (var method in elproto) if (elproto[has](method)) {
3086         setproto[method] = (function (methodname) {
3087             return function () {
3088                 var arg = arguments;
3089                 return this.forEach(function (el) {
3090                     el[methodname][apply](el, arg);
3091                 });
3092             };
3093         })(method);
3094     }
3095     setproto.attr = function (name, value) {
3096         if (name && R.is(name, array) && R.is(name[0], "object")) {
3097             for (var j = 0, jj = name.length; j < jj; j++) {
3098                 this.items[j].attr(name[j]);
3099             }
3100         } else {
3101             for (var i = 0, ii = this.items.length; i < ii; i++) {
3102                 this.items[i].attr(name, value);
3103             }
3104         }
3105         return this;
3106     };
3107     
3108     setproto.clear = function () {
3109         while (this.length) {
3110             this.pop();
3111         }
3112     };
3113     
3114     setproto.splice = function (index, count, insertion) {
3115         index = index < 0 ? mmax(this.length + index, 0) : index;
3116         count = mmax(0, mmin(this.length - index, count));
3117         var tail = [],
3118             todel = [],
3119             args = [],
3120             i;
3121         for (i = 2; i < arguments.length; i++) {
3122             args.push(arguments[i]);
3123         }
3124         for (i = 0; i < count; i++) {
3125             todel.push(this[index + i]);
3126         }
3127         for (; i < this.length - index; i++) {
3128             tail.push(this[index + i]);
3129         }
3130         var arglen = args.length;
3131         for (i = 0; i < arglen + tail.length; i++) {
3132             this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen];
3133         }
3134         i = this.items.length = this.length -= count - arglen;
3135         while (this[i]) {
3136             delete this[i++];
3137         }
3138         return new Set(todel);
3139     };
3140     
3141     setproto.exclude = function (el) {
3142         for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) {
3143             this.splice(i, 1);
3144             return true;
3145         }
3146     };
3147     setproto.animate = function (params, ms, easing, callback) {
3148         (R.is(easing, "function") || !easing) && (callback = easing || null);
3149         var len = this.items.length,
3150             i = len,
3151             item,
3152             set = this,
3153             collector;
3154         if (!len) {
3155             return this;
3156         }
3157         callback && (collector = function () {
3158             !--len && callback.call(set);
3159         });
3160         easing = R.is(easing, string) ? easing : collector;
3161         var anim = R.animation(params, ms, easing, collector);
3162         item = this.items[--i].animate(anim);
3163         while (i--) {
3164             this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim);
3165         }
3166         return this;
3167     };
3168     setproto.insertAfter = function (el) {
3169         var i = this.items.length;
3170         while (i--) {
3171             this.items[i].insertAfter(el);
3172         }
3173         return this;
3174     };
3175     setproto.getBBox = function () {
3176         var x = [],
3177             y = [],
3178             w = [],
3179             h = [];
3180         for (var i = this.items.length; i--;) if (!this.items[i].removed) {
3181             var box = this.items[i].getBBox();
3182             x.push(box.x);
3183             y.push(box.y);
3184             w.push(box.x + box.width);
3185             h.push(box.y + box.height);
3186         }
3187         x = mmin[apply](0, x);
3188         y = mmin[apply](0, y);
3189         return {
3190             x: x,
3191             y: y,
3192             width: mmax[apply](0, w) - x,
3193             height: mmax[apply](0, h) - y
3194         };
3195     };
3196     setproto.clone = function (s) {
3197         s = new Set;
3198         for (var i = 0, ii = this.items.length; i < ii; i++) {
3199             s.push(this.items[i].clone());
3200         }
3201         return s;
3202     };
3203     setproto.toString = function () {
3204         return "Rapha\xebl\u2018s set";
3205     };
3206
3207     
3208     R.registerFont = function (font) {
3209         if (!font.face) {
3210             return font;
3211         }
3212         this.fonts = this.fonts || {};
3213         var fontcopy = {
3214                 w: font.w,
3215                 face: {},
3216                 glyphs: {}
3217             },
3218             family = font.face["font-family"];
3219         for (var prop in font.face) if (font.face[has](prop)) {
3220             fontcopy.face[prop] = font.face[prop];
3221         }
3222         if (this.fonts[family]) {
3223             this.fonts[family].push(fontcopy);
3224         } else {
3225             this.fonts[family] = [fontcopy];
3226         }
3227         if (!font.svg) {
3228             fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10);
3229             for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) {
3230                 var path = font.glyphs[glyph];
3231                 fontcopy.glyphs[glyph] = {
3232                     w: path.w,
3233                     k: {},
3234                     d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) {
3235                             return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M";
3236                         }) + "z"
3237                 };
3238                 if (path.k) {
3239                     for (var k in path.k) if (path[has](k)) {
3240                         fontcopy.glyphs[glyph].k[k] = path.k[k];
3241                     }
3242                 }
3243             }
3244         }
3245         return font;
3246     };
3247     
3248     paperproto.getFont = function (family, weight, style, stretch) {
3249         stretch = stretch || "normal";
3250         style = style || "normal";
3251         weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400;
3252         if (!R.fonts) {
3253             return;
3254         }
3255         var font = R.fonts[family];
3256         if (!font) {
3257             var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i");
3258             for (var fontName in R.fonts) if (R.fonts[has](fontName)) {
3259                 if (name.test(fontName)) {
3260                     font = R.fonts[fontName];
3261                     break;
3262                 }
3263             }
3264         }
3265         var thefont;
3266         if (font) {
3267             for (var i = 0, ii = font.length; i < ii; i++) {
3268                 thefont = font[i];
3269                 if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) {
3270                     break;
3271                 }
3272             }
3273         }
3274         return thefont;
3275     };
3276     
3277     paperproto.print = function (x, y, string, font, size, origin, letter_spacing) {
3278         origin = origin || "middle"; // baseline|middle
3279         letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1);
3280         var out = this.set(),
3281             letters = Str(string).split(E),
3282             shift = 0,
3283             path = E,
3284             scale;
3285         R.is(font, string) && (font = this.getFont(font));
3286         if (font) {
3287             scale = (size || 16) / font.face["units-per-em"];
3288             var bb = font.face.bbox.split(separator),
3289                 top = +bb[0],
3290                 height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2);
3291             for (var i = 0, ii = letters.length; i < ii; i++) {
3292                 var prev = i && font.glyphs[letters[i - 1]] || {},
3293                     curr = font.glyphs[letters[i]];
3294                 shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0;
3295                 curr && curr.d && out.push(this.path(curr.d).attr({
3296                     fill: "#000",
3297                     stroke: "none",
3298                     transform: [["t", shift * scale, 0]]
3299                 }));
3300             }
3301             out.transform(["...s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]);
3302         }
3303         return out;
3304     };
3305
3306     
3307     R.format = function (token, params) {
3308         var args = R.is(params, array) ? [0][concat](params) : arguments;
3309         token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) {
3310             return args[++i] == null ? E : args[i];
3311         }));
3312         return token || E;
3313     };
3314     
3315     R.fullfill = (function () {
3316         var tokenRegex = /\{([^\}]+)\}/g,
3317             objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
3318             replacer = function (all, key, obj) {
3319                 var res = obj;
3320                 key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
3321                     name = name || quotedName;
3322                     if (res) {
3323                         if (name in res) {
3324                             res = res[name];
3325                         }
3326                         typeof res == "function" && isFunc && (res = res());
3327                     }
3328                 });
3329                 res = (res == null || res == obj ? all : res) + "";
3330                 return res;
3331             };
3332         return function (str, obj) {
3333             return String(str).replace(tokenRegex, function (all, key) {
3334                 return replacer(all, key, obj);
3335             });
3336         };
3337     })();
3338     
3339     R.ninja = function () {
3340         oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael;
3341         return R;
3342     };
3343     
3344     R.st = setproto;
3345     // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
3346     (function (doc, loaded, f) {
3347         if (doc.readyState == null && doc.addEventListener){
3348             doc.addEventListener(loaded, f = function () {
3349                 doc.removeEventListener(loaded, f, false);
3350                 doc.readyState = "complete";
3351             }, false);
3352             doc.readyState = "loading";
3353         }
3354         function isLoaded() {
3355             (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("DOMload");
3356         }
3357         isLoaded();
3358     })(document, "DOMContentLoaded");
3359
3360     oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R);
3361     
3362     eve.on("DOMload", function () {
3363         loaded = true;
3364     });
3365 })();
3366
3367 // ┌─────────────────────────────────────────────────────────────────────┐ \\
3368 // │ Raphaël 2 - JavaScript Vector Library                               │ \\
3369 // ├─────────────────────────────────────────────────────────────────────┤ \\
3370 // │ SVG Module                                                          │ \\
3371 // ├─────────────────────────────────────────────────────────────────────┤ \\
3372 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
3373 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
3374 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
3375 // └─────────────────────────────────────────────────────────────────────┘ \\
3376 window.Raphael.svg && function (R) {
3377     var has = "hasOwnProperty",
3378         Str = String,
3379         toFloat = parseFloat,
3380         toInt = parseInt,
3381         math = Math,
3382         mmax = math.max,
3383         abs = math.abs,
3384         pow = math.pow,
3385         separator = /[, ]+/,
3386         eve = R.eve,
3387         E = "",
3388         S = " ";
3389     var xlink = "http://www.w3.org/1999/xlink",
3390         markers = {
3391             block: "M5,0 0,2.5 5,5z",
3392             classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z",
3393             diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z",
3394             open: "M6,1 1,3.5 6,6",
3395             oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"
3396         },
3397         markerCounter = {};
3398     R.toString = function () {
3399         return  "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version;
3400     };
3401     var $ = function (el, attr) {
3402         if (attr) {
3403             if (typeof el == "string") {
3404                 el = $(el);
3405             }
3406             for (var key in attr) if (attr[has](key)) {
3407                 if (key.substring(0, 6) == "xlink:") {
3408                     el.setAttributeNS(xlink, key.substring(6), Str(attr[key]));
3409                 } else {
3410                     el.setAttribute(key, Str(attr[key]));
3411                 }
3412             }
3413         } else {
3414             el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el);
3415             el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)");
3416         }
3417         return el;
3418     },
3419     gradients = {},
3420     rgGrad = /^url\(#(.*)\)$/,
3421     removeGradientFill = function (node, paper) {
3422         var oid = node.getAttribute("fill");
3423         oid = oid && oid.match(rgGrad);
3424         if (oid && !--gradients[oid[1]]) {
3425             delete gradients[oid[1]];
3426             paper.defs.removeChild(R._g.doc.getElementById(oid[1]));
3427         }
3428     },
3429     addGradientFill = function (element, gradient) {
3430         var type = "linear",
3431             id = element.id + gradient,
3432             fx = .5, fy = .5,
3433             o = element.node,
3434             SVG = element.paper,
3435             s = o.style,
3436             el = R._g.doc.getElementById(id);
3437         if (!el) {
3438             gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) {
3439                 type = "radial";
3440                 if (_fx && _fy) {
3441                     fx = toFloat(_fx);
3442                     fy = toFloat(_fy);
3443                     var dir = ((fy > .5) * 2 - 1);
3444                     pow(fx - .5, 2) + pow(fy - .5, 2) > .25 &&
3445                         (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) &&
3446                         fy != .5 &&
3447                         (fy = fy.toFixed(5) - 1e-5 * dir);
3448                 }
3449                 return E;
3450             });
3451             gradient = gradient.split(/\s*\-\s*/);
3452             if (type == "linear") {
3453                 var angle = gradient.shift();
3454                 angle = -toFloat(angle);
3455                 if (isNaN(angle)) {
3456                     return null;
3457                 }
3458                 var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))],
3459                     max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1);
3460                 vector[2] *= max;
3461                 vector[3] *= max;
3462                 if (vector[2] < 0) {
3463                     vector[0] = -vector[2];
3464                     vector[2] = 0;
3465                 }
3466                 if (vector[3] < 0) {
3467                     vector[1] = -vector[3];
3468                     vector[3] = 0;
3469                 }
3470             }
3471             var dots = R._parseDots(gradient);
3472             if (!dots) {
3473                 return null;
3474             }
3475             if (element.gradient) {
3476                 SVG.defs.removeChild(element.gradient);
3477                 delete element.gradient;
3478             }
3479
3480             id = id.replace(/[\(\)\s,\xb0#]/g, "-");
3481             el = $(type + "Gradient", {id: id});
3482             element.gradient = el;
3483             $(el, type == "radial" ? {
3484                 fx: fx,
3485                 fy: fy
3486             } : {
3487                 x1: vector[0],
3488                 y1: vector[1],
3489                 x2: vector[2],
3490                 y2: vector[3],
3491                 gradientTransform: element.matrix.invert()
3492             });
3493             SVG.defs.appendChild(el);
3494             for (var i = 0, ii = dots.length; i < ii; i++) {
3495                 el.appendChild($("stop", {
3496                     offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
3497                     "stop-color": dots[i].color || "#fff"
3498                 }));
3499             }
3500         }
3501         $(o, {
3502             fill: "url(#" + id + ")",
3503             opacity: 1,
3504             "fill-opacity": 1
3505         });
3506         s.fill = E;
3507         s.opacity = 1;
3508         s.fillOpacity = 1;
3509         return 1;
3510     },
3511     updatePosition = function (o) {
3512         var bbox = o.getBBox(1);
3513         $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"});
3514     },
3515     addArrow = function (o, value, isEnd) {
3516         if (o.type == "path") {
3517             var values = Str(value).toLowerCase().split("-"),
3518                 p = o.paper,
3519                 se = isEnd ? "end" : "start",
3520                 node = o.node,
3521                 attrs = o.attrs,
3522                 stroke = attrs["stroke-width"],
3523                 i = values.length,
3524                 type = "classic",
3525                 from,
3526                 to,
3527                 dx,
3528                 refX,
3529                 attr,
3530                 w = 3,
3531                 h = 3,
3532                 t = 5;
3533             while (i--) {
3534                 switch (values[i]) {
3535                     case "block":
3536                     case "classic":
3537                     case "oval":
3538                     case "diamond":
3539                     case "open":
3540                     case "none":
3541                         type = values[i];
3542                         break;
3543                     case "wide": h = 5; break;
3544                     case "narrow": h = 2; break;
3545                     case "long": w = 5; break;
3546                     case "short": w = 2; break;
3547                 }
3548             }
3549             if (type == "open") {
3550                 w += 2;
3551                 h += 2;
3552                 t += 2;
3553                 dx = 1;
3554                 refX = isEnd ? 4 : 1;
3555                 attr = {
3556                     fill: "none",
3557                     stroke: attrs.stroke
3558                 };
3559             } else {
3560                 refX = dx = w / 2;
3561                 attr = {
3562                     fill: attrs.stroke,
3563                     stroke: "none"
3564                 };
3565             }
3566             if (o._.arrows) {
3567                 if (isEnd) {
3568                     o._.arrows.endPath && markerCounter[o._.arrows.endPath]--;
3569                     o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--;
3570                 } else {
3571                     o._.arrows.startPath && markerCounter[o._.arrows.startPath]--;
3572                     o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--;
3573                 }
3574             } else {
3575                 o._.arrows = {};
3576             }
3577             if (type != "none") {
3578                 var pathId = "raphael-marker-" + type,
3579                     markerId = "raphael-marker-" + se + type + w + h;
3580                 if (!R._g.doc.getElementById(pathId)) {
3581                     p.defs.appendChild($($("path"), {
3582                         "stroke-linecap": "round",
3583                         d: markers[type],
3584                         id: pathId
3585                     }));
3586                     markerCounter[pathId] = 1;
3587                 } else {
3588                     markerCounter[pathId]++;
3589                 }
3590                 var marker = R._g.doc.getElementById(markerId),
3591                     use;
3592                 if (!marker) {
3593                     marker = $($("marker"), {
3594                         id: markerId,
3595                         markerHeight: h,
3596                         markerWidth: w,
3597                         orient: "auto",
3598                         refX: refX,
3599                         refY: h / 2
3600                     });
3601                     use = $($("use"), {
3602                         "xlink:href": "#" + pathId,
3603                         transform: (isEnd ? " rotate(180 " + w / 2 + " " + h / 2 + ") " : S) + "scale(" + w / t + "," + h / t + ")",
3604                         "stroke-width": 1 / ((w / t + h / t) / 2)
3605                     });
3606                     marker.appendChild(use);
3607                     p.defs.appendChild(marker);
3608                     markerCounter[markerId] = 1;
3609                 } else {
3610                     markerCounter[markerId]++;
3611                     use = marker.getElementsByTagName("use")[0];
3612                 }
3613                 $(use, attr);
3614                 var delta = dx * (type != "diamond" && type != "oval");
3615                 if (isEnd) {
3616                     from = o._.arrows.startdx * stroke || 0;
3617                     to = R.getTotalLength(attrs.path) - delta * stroke;
3618                 } else {
3619                     from = delta * stroke;
3620                     to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
3621                 }
3622                 attr = {};
3623                 attr["marker-" + se] = "url(#" + markerId + ")";
3624                 if (to || from) {
3625                     attr.d = Raphael.getSubpath(attrs.path, from, to);
3626                 }
3627                 $(node, attr);
3628                 o._.arrows[se + "Path"] = pathId;
3629                 o._.arrows[se + "Marker"] = markerId;
3630                 o._.arrows[se + "dx"] = delta;
3631                 o._.arrows[se + "Type"] = type;
3632                 o._.arrows[se + "String"] = value;
3633             } else {
3634                 if (isEnd) {
3635                     from = o._.arrows.startdx * stroke || 0;
3636                     to = R.getTotalLength(attrs.path) - from;
3637                 } else {
3638                     from = 0;
3639                     to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
3640                 }
3641                 o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)});
3642                 delete o._.arrows[se + "Path"];
3643                 delete o._.arrows[se + "Marker"];
3644                 delete o._.arrows[se + "dx"];
3645                 delete o._.arrows[se + "Type"];
3646                 delete o._.arrows[se + "String"];
3647             }
3648             for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) {
3649                 var item = R._g.doc.getElementById(attr);
3650                 item && item.parentNode.removeChild(item);
3651             }
3652         }
3653     },
3654     dasharray = {
3655         "": [0],
3656         "none": [0],
3657         "-": [3, 1],
3658         ".": [1, 1],
3659         "-.": [3, 1, 1, 1],
3660         "-..": [3, 1, 1, 1, 1, 1],
3661         ". ": [1, 3],
3662         "- ": [4, 3],
3663         "--": [8, 3],
3664         "- .": [4, 3, 1, 3],
3665         "--.": [8, 3, 1, 3],
3666         "--..": [8, 3, 1, 3, 1, 3]
3667     },
3668     addDashes = function (o, value, params) {
3669         value = dasharray[Str(value).toLowerCase()];
3670         if (value) {
3671             var width = o.attrs["stroke-width"] || "1",
3672                 butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
3673                 dashes = [],
3674                 i = value.length;
3675             while (i--) {
3676                 dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
3677             }
3678             $(o.node, {"stroke-dasharray": dashes.join(",")});
3679         }
3680     },
3681     setFillAndStroke = function (o, params) {
3682         var node = o.node,
3683             attrs = o.attrs,
3684             vis = node.style.visibility;
3685         node.style.visibility = "hidden";
3686         for (var att in params) {
3687             if (params[has](att)) {
3688                 if (!R._availableAttrs[has](att)) {
3689                     continue;
3690                 }
3691                 var value = params[att];
3692                 attrs[att] = value;
3693                 switch (att) {
3694                     case "blur":
3695                         o.blur(value);
3696                         break;
3697                     case "href":
3698                     case "title":
3699                     case "target":
3700                         var pn = node.parentNode;
3701                         if (pn.tagName.toLowerCase() != "a") {
3702                             var hl = $("a");
3703                             pn.insertBefore(hl, node);
3704                             hl.appendChild(node);
3705                             pn = hl;
3706                         }
3707                         if (att == "target" && value == "blank") {
3708                             pn.setAttributeNS(xlink, "show", "new");
3709                         } else {
3710                             pn.setAttributeNS(xlink, att, value);
3711                         }
3712                         break;
3713                     case "cursor":
3714                         node.style.cursor = value;
3715                         break;
3716                     case "transform":
3717                         o.transform(value);
3718                         break;
3719                     case "arrow-start":
3720                         addArrow(o, value);
3721                         break;
3722                     case "arrow-end":
3723                         addArrow(o, value, 1);
3724                         break;
3725                     case "clip-rect":
3726                         var rect = Str(value).split(separator);
3727                         if (rect.length == 4) {
3728                             o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
3729                             var el = $("clipPath"),
3730                                 rc = $("rect");
3731                             el.id = R.createUUID();
3732                             $(rc, {
3733                                 x: rect[0],
3734                                 y: rect[1],
3735                                 width: rect[2],
3736                                 height: rect[3]
3737                             });
3738                             el.appendChild(rc);
3739                             o.paper.defs.appendChild(el);
3740                             $(node, {"clip-path": "url(#" + el.id + ")"});
3741                             o.clip = rc;
3742                         }
3743                         if (!value) {
3744                             var clip = R._g.doc.getElementById(node.getAttribute("clip-path").replace(/(^url\(#|\)$)/g, E));
3745                             clip && clip.parentNode.removeChild(clip);
3746                             $(node, {"clip-path": E});
3747                             delete o.clip;
3748                         }
3749                     break;
3750                     case "path":
3751                         if (o.type == "path") {
3752                             $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"});
3753                             o._.dirty = 1;
3754                             if (o._.arrows) {
3755                                 "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3756                                 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3757                             }
3758                         }
3759                         break;
3760                     case "width":
3761                         node.setAttribute(att, value);
3762                         o._.dirty = 1;
3763                         if (attrs.fx) {
3764                             att = "x";
3765                             value = attrs.x;
3766                         } else {
3767                             break;
3768                         }
3769                     case "x":
3770                         if (attrs.fx) {
3771                             value = -attrs.x - (attrs.width || 0);
3772                         }
3773                     case "rx":
3774                         if (att == "rx" && o.type == "rect") {
3775                             break;
3776                         }
3777                     case "cx":
3778                         node.setAttribute(att, value);
3779                         o.pattern && updatePosition(o);
3780                         o._.dirty = 1;
3781                         break;
3782                     case "height":
3783                         node.setAttribute(att, value);
3784                         o._.dirty = 1;
3785                         if (attrs.fy) {
3786                             att = "y";
3787                             value = attrs.y;
3788                         } else {
3789                             break;
3790                         }
3791                     case "y":
3792                         if (attrs.fy) {
3793                             value = -attrs.y - (attrs.height || 0);
3794                         }
3795                     case "ry":
3796                         if (att == "ry" && o.type == "rect") {
3797                             break;
3798                         }
3799                     case "cy":
3800                         node.setAttribute(att, value);
3801                         o.pattern && updatePosition(o);
3802                         o._.dirty = 1;
3803                         break;
3804                     case "r":
3805                         if (o.type == "rect") {
3806                             $(node, {rx: value, ry: value});
3807                         } else {
3808                             node.setAttribute(att, value);
3809                         }
3810                         o._.dirty = 1;
3811                         break;
3812                     case "src":
3813                         if (o.type == "image") {
3814                             node.setAttributeNS(xlink, "href", value);
3815                         }
3816                         break;
3817                     case "stroke-width":
3818                         if (o._.sx != 1 || o._.sy != 1) {
3819                             value /= mmax(abs(o._.sx), abs(o._.sy)) || 1;
3820                         }
3821                         if (o.paper._vbSize) {
3822                             value *= o.paper._vbSize;
3823                         }
3824                         node.setAttribute(att, value);
3825                         if (attrs["stroke-dasharray"]) {
3826                             addDashes(o, attrs["stroke-dasharray"], params);
3827                         }
3828                         if (o._.arrows) {
3829                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3830                             "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3831                         }
3832                         break;
3833                     case "stroke-dasharray":
3834                         addDashes(o, value, params);
3835                         break;
3836                     case "fill":
3837                         var isURL = Str(value).match(R._ISURL);
3838                         if (isURL) {
3839                             el = $("pattern");
3840                             var ig = $("image");
3841                             el.id = R.createUUID();
3842                             $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1});
3843                             $(ig, {x: 0, y: 0, "xlink:href": isURL[1]});
3844                             el.appendChild(ig);
3845
3846                             (function (el) {
3847                                 R._preload(isURL[1], function () {
3848                                     var w = this.offsetWidth,
3849                                         h = this.offsetHeight;
3850                                     $(el, {width: w, height: h});
3851                                     $(ig, {width: w, height: h});
3852                                     o.paper.safari();
3853                                 });
3854                             })(el);
3855                             o.paper.defs.appendChild(el);
3856                             node.style.fill = "url(#" + el.id + ")";
3857                             $(node, {fill: "url(#" + el.id + ")"});
3858                             o.pattern = el;
3859                             o.pattern && updatePosition(o);
3860                             break;
3861                         }
3862                         var clr = R.getRGB(value);
3863                         if (!clr.error) {
3864                             delete params.gradient;
3865                             delete attrs.gradient;
3866                             !R.is(attrs.opacity, "undefined") &&
3867                                 R.is(params.opacity, "undefined") &&
3868                                 $(node, {opacity: attrs.opacity});
3869                             !R.is(attrs["fill-opacity"], "undefined") &&
3870                                 R.is(params["fill-opacity"], "undefined") &&
3871                                 $(node, {"fill-opacity": attrs["fill-opacity"]});
3872                         } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) {
3873                             if ("opacity" in attrs || "fill-opacity" in attrs) {
3874                                 var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
3875                                 if (gradient) {
3876                                     var stops = gradient.getElementsByTagName("stop");
3877                                     $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)});
3878                                 }
3879                             }
3880                             attrs.gradient = value;
3881                             attrs.fill = "none";
3882                             break;
3883                         }
3884                         clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
3885                     case "stroke":
3886                         clr = R.getRGB(value);
3887                         node.setAttribute(att, clr.hex);
3888                         att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
3889                         if (att == "stroke" && o._.arrows) {
3890                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3891                             "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3892                         }
3893                         break;
3894                     case "gradient":
3895                         (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value);
3896                         break;
3897                     case "opacity":
3898                         if (attrs.gradient && !attrs[has]("stroke-opacity")) {
3899                             $(node, {"stroke-opacity": value > 1 ? value / 100 : value});
3900                         }
3901                         // fall
3902                     case "fill-opacity":
3903                         if (attrs.gradient) {
3904                             gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
3905                             if (gradient) {
3906                                 stops = gradient.getElementsByTagName("stop");
3907                                 $(stops[stops.length - 1], {"stop-opacity": value});
3908                             }
3909                             break;
3910                         }
3911                     default:
3912                         att == "font-size" && (value = toInt(value, 10) + "px");
3913                         var cssrule = att.replace(/(\-.)/g, function (w) {
3914                             return w.substring(1).toUpperCase();
3915                         });
3916                         node.style[cssrule] = value;
3917                         o._.dirty = 1;
3918                         node.setAttribute(att, value);
3919                         break;
3920                 }
3921             }
3922         }
3923
3924         tuneText(o, params);
3925         node.style.visibility = vis;
3926     },
3927     leading = 1.2,
3928     tuneText = function (el, params) {
3929         if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) {
3930             return;
3931         }
3932         var a = el.attrs,
3933             node = el.node,
3934             fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10;
3935
3936         if (params[has]("text")) {
3937             a.text = params.text;
3938             while (node.firstChild) {
3939                 node.removeChild(node.firstChild);
3940             }
3941             var texts = Str(params.text).split("\n"),
3942                 tspans = [],
3943                 tspan;
3944             for (var i = 0, ii = texts.length; i < ii; i++) {
3945                 tspan = $("tspan");
3946                 i && $(tspan, {dy: fontSize * leading, x: a.x});
3947                 tspan.appendChild(R._g.doc.createTextNode(texts[i]));
3948                 node.appendChild(tspan);
3949                 tspans[i] = tspan;
3950             }
3951         } else {
3952             tspans = node.getElementsByTagName("tspan");
3953             for (i = 0, ii = tspans.length; i < ii; i++) if (i) {
3954                 $(tspans[i], {dy: fontSize * leading, x: a.x});
3955             } else {
3956                 $(tspans[0], {dy: 0});
3957             }
3958         }
3959         $(node, {x: a.x, y: a.y});
3960         el._.dirty = 1;
3961         var bb = el._getBBox(),
3962             dif = a.y - (bb.y + bb.height / 2);
3963         dif && R.is(dif, "finite") && $(tspans[0], {dy: dif});
3964     },
3965     Element = function (node, svg) {
3966         var X = 0,
3967             Y = 0;
3968         
3969         this[0] = this.node = node;
3970         
3971         node.raphael = true;
3972         
3973         this.id = R._oid++;
3974         node.raphaelid = this.id;
3975         this.matrix = R.matrix();
3976         this.realPath = null;
3977         
3978         this.paper = svg;
3979         this.attrs = this.attrs || {};
3980         this._ = {
3981             transform: [],
3982             sx: 1,
3983             sy: 1,
3984             deg: 0,
3985             dx: 0,
3986             dy: 0,
3987             dirty: 1
3988         };
3989         !svg.bottom && (svg.bottom = this);
3990         
3991         this.prev = svg.top;
3992         svg.top && (svg.top.next = this);
3993         svg.top = this;
3994         
3995         this.next = null;
3996     },
3997     elproto = R.el;
3998
3999     Element.prototype = elproto;
4000     elproto.constructor = Element;
4001
4002     R._engine.path = function (pathString, SVG) {
4003         var el = $("path");
4004         SVG.canvas && SVG.canvas.appendChild(el);
4005         var p = new Element(el, SVG);
4006         p.type = "path";
4007         setFillAndStroke(p, {
4008             fill: "none",
4009             stroke: "#000",
4010             path: pathString
4011         });
4012         return p;
4013     };
4014     
4015     elproto.rotate = function (deg, cx, cy) {
4016         if (this.removed) {
4017             return this;
4018         }
4019         deg = Str(deg).split(separator);
4020         if (deg.length - 1) {
4021             cx = toFloat(deg[1]);
4022             cy = toFloat(deg[2]);
4023         }
4024         deg = toFloat(deg[0]);
4025         (cy == null) && (cx = cy);
4026         if (cx == null || cy == null) {
4027             var bbox = this.getBBox(1);
4028             cx = bbox.x + bbox.width / 2;
4029             cy = bbox.y + bbox.height / 2;
4030         }
4031         this.transform(this._.transform.concat([["r", deg, cx, cy]]));
4032         return this;
4033     };
4034     
4035     elproto.scale = function (sx, sy, cx, cy) {
4036         if (this.removed) {
4037             return this;
4038         }
4039         sx = Str(sx).split(separator);
4040         if (sx.length - 1) {
4041             sy = toFloat(sx[1]);
4042             cx = toFloat(sx[2]);
4043             cy = toFloat(sx[3]);
4044         }
4045         sx = toFloat(sx[0]);
4046         (sy == null) && (sy = sx);
4047         (cy == null) && (cx = cy);
4048         if (cx == null || cy == null) {
4049             var bbox = this.getBBox(1);
4050         }
4051         cx = cx == null ? bbox.x + bbox.width / 2 : cx;
4052         cy = cy == null ? bbox.y + bbox.height / 2 : cy;
4053         this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
4054         return this;
4055     };
4056     
4057     elproto.translate = function (dx, dy) {
4058         if (this.removed) {
4059             return this;
4060         }
4061         dx = Str(dx).split(separator);
4062         if (dx.length - 1) {
4063             dy = toFloat(dx[1]);
4064         }
4065         dx = toFloat(dx[0]) || 0;
4066         dy = +dy || 0;
4067         this.transform(this._.transform.concat([["t", dx, dy]]));
4068         return this;
4069     };
4070     
4071     elproto.transform = function (tstr) {
4072         var _ = this._;
4073         if (tstr == null) {
4074             return _.transform;
4075         }
4076         R._extractTransform(this, tstr);
4077
4078         this.clip && $(this.clip, {transform: this.matrix.invert()});
4079         this.pattern && updatePosition(this);
4080         this.node && $(this.node, {transform: this.matrix});
4081     
4082         if (_.sx != 1 || _.sy != 1) {
4083             var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1;
4084             this.attr({"stroke-width": sw});
4085         }
4086
4087         return this;
4088     };
4089     
4090     elproto.hide = function () {
4091         !this.removed && this.paper.safari(this.node.style.display = "none");
4092         return this;
4093     };
4094     
4095     elproto.show = function () {
4096         !this.removed && this.paper.safari(this.node.style.display = "");
4097         return this;
4098     };
4099     
4100     elproto.remove = function () {
4101         if (this.removed) {
4102             return;
4103         }
4104         this.paper.__set__ && this.paper.__set__.exclude(this);
4105         eve.unbind("*.*." + this.id);
4106         R._tear(this, this.paper);
4107         this.node.parentNode.removeChild(this.node);
4108         for (var i in this) {
4109             delete this[i];
4110         }
4111         this.removed = true;
4112     };
4113     elproto._getBBox = function () {
4114         if (this.node.style.display == "none") {
4115             this.show();
4116             var hide = true;
4117         }
4118         var bbox = {};
4119         try {
4120             bbox = this.node.getBBox();
4121         } catch(e) {
4122             // Firefox 3.0.x plays badly here
4123         } finally {
4124             bbox = bbox || {};
4125         }
4126         hide && this.hide();
4127         return bbox;
4128     };
4129     
4130     elproto.attr = function (name, value) {
4131         if (this.removed) {
4132             return this;
4133         }
4134         if (name == null) {
4135             var res = {};
4136             for (var a in this.attrs) if (this.attrs[has](a)) {
4137                 res[a] = this.attrs[a];
4138             }
4139             res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
4140             res.transform = this._.transform;
4141             return res;
4142         }
4143         if (value == null && R.is(name, "string")) {
4144             if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) {
4145                 return this.attrs.gradient;
4146             }
4147             if (name == "transform") {
4148                 return this._.transform;
4149             }
4150             var names = name.split(separator),
4151                 out = {};
4152             for (var i = 0, ii = names.length; i < ii; i++) {
4153                 name = names[i];
4154                 if (name in this.attrs) {
4155                     out[name] = this.attrs[name];
4156                 } else if (R.is(this.paper.customAttributes[name], "function")) {
4157                     out[name] = this.paper.customAttributes[name].def;
4158                 } else {
4159                     out[name] = R._availableAttrs[name];
4160                 }
4161             }
4162             return ii - 1 ? out : out[names[0]];
4163         }
4164         if (value == null && R.is(name, "array")) {
4165             out = {};
4166             for (i = 0, ii = name.length; i < ii; i++) {
4167                 out[name[i]] = this.attr(name[i]);
4168             }
4169             return out;
4170         }
4171         if (value != null) {
4172             var params = {};
4173             params[name] = value;
4174         } else if (name != null && R.is(name, "object")) {
4175             params = name;
4176         }
4177         for (var key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
4178             var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
4179             this.attrs[key] = params[key];
4180             for (var subkey in par) if (par[has](subkey)) {
4181                 params[subkey] = par[subkey];
4182             }
4183         }
4184         setFillAndStroke(this, params);
4185         return this;
4186     };
4187     
4188     elproto.toFront = function () {
4189         if (this.removed) {
4190             return this;
4191         }
4192         this.node.parentNode.appendChild(this.node);
4193         var svg = this.paper;
4194         svg.top != this && R._tofront(this, svg);
4195         return this;
4196     };
4197     
4198     elproto.toBack = function () {
4199         if (this.removed) {
4200             return this;
4201         }
4202         if (this.node.parentNode.firstChild != this.node) {
4203             this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
4204             R._toback(this, this.paper);
4205             var svg = this.paper;
4206         }
4207         return this;
4208     };
4209     
4210     elproto.insertAfter = function (element) {
4211         if (this.removed) {
4212             return this;
4213         }
4214         var node = element.node || element[element.length - 1].node;
4215         if (node.nextSibling) {
4216             node.parentNode.insertBefore(this.node, node.nextSibling);
4217         } else {
4218             node.parentNode.appendChild(this.node);
4219         }
4220         R._insertafter(this, element, this.paper);
4221         return this;
4222     };
4223     
4224     elproto.insertBefore = function (element) {
4225         if (this.removed) {
4226             return this;
4227         }
4228         var node = element.node || element[0].node;
4229         node.parentNode.insertBefore(this.node, node);
4230         R._insertbefore(this, element, this.paper);
4231         return this;
4232     };
4233     elproto.blur = function (size) {
4234         // Experimental. No Safari support. Use it on your own risk.
4235         var t = this;
4236         if (+size !== 0) {
4237             var fltr = $("filter"),
4238                 blur = $("feGaussianBlur");
4239             t.attrs.blur = size;
4240             fltr.id = R.createUUID();
4241             $(blur, {stdDeviation: +size || 1.5});
4242             fltr.appendChild(blur);
4243             t.paper.defs.appendChild(fltr);
4244             t._blur = fltr;
4245             $(t.node, {filter: "url(#" + fltr.id + ")"});
4246         } else {
4247             if (t._blur) {
4248                 t._blur.parentNode.removeChild(t._blur);
4249                 delete t._blur;
4250                 delete t.attrs.blur;
4251             }
4252             t.node.removeAttribute("filter");
4253         }
4254     };
4255     R._engine.circle = function (svg, x, y, r) {
4256         var el = $("circle");
4257         svg.canvas && svg.canvas.appendChild(el);
4258         var res = new Element(el, svg);
4259         res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"};
4260         res.type = "circle";
4261         $(el, res.attrs);
4262         return res;
4263     };
4264     R._engine.rect = function (svg, x, y, w, h, r) {
4265         var el = $("rect");
4266         svg.canvas && svg.canvas.appendChild(el);
4267         var res = new Element(el, svg);
4268         res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"};
4269         res.type = "rect";
4270         $(el, res.attrs);
4271         return res;
4272     };
4273     R._engine.ellipse = function (svg, x, y, rx, ry) {
4274         var el = $("ellipse");
4275         svg.canvas && svg.canvas.appendChild(el);
4276         var res = new Element(el, svg);
4277         res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"};
4278         res.type = "ellipse";
4279         $(el, res.attrs);
4280         return res;
4281     };
4282     R._engine.image = function (svg, src, x, y, w, h) {
4283         var el = $("image");
4284         $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"});
4285         el.setAttributeNS(xlink, "href", src);
4286         svg.canvas && svg.canvas.appendChild(el);
4287         var res = new Element(el, svg);
4288         res.attrs = {x: x, y: y, width: w, height: h, src: src};
4289         res.type = "image";
4290         return res;
4291     };
4292     R._engine.text = function (svg, x, y, text) {
4293         var el = $("text");
4294         // $(el, {x: x, y: y, "text-anchor": "middle"});
4295         svg.canvas && svg.canvas.appendChild(el);
4296         var res = new Element(el, svg);
4297         res.attrs = {
4298             x: x,
4299             y: y,
4300             "text-anchor": "middle",
4301             text: text,
4302             font: R._availableAttrs.font,
4303             stroke: "none",
4304             fill: "#000"
4305         };
4306         res.type = "text";
4307         setFillAndStroke(res, res.attrs);
4308         return res;
4309     };
4310     R._engine.setSize = function (width, height) {
4311         this.width = width || this.width;
4312         this.height = height || this.height;
4313         this.canvas.setAttribute("width", this.width);
4314         this.canvas.setAttribute("height", this.height);
4315         if (this._viewBox) {
4316             this.setViewBox.apply(this, this._viewBox);
4317         }
4318         return this;
4319     };
4320     R._engine.create = function () {
4321         var con = R._getContainer.apply(0, arguments),
4322             container = con && con.container,
4323             x = con.x,
4324             y = con.y,
4325             width = con.width,
4326             height = con.height;
4327         if (!container) {
4328             throw new Error("SVG container not found.");
4329         }
4330         var cnvs = $("svg"),
4331             css = "overflow:hidden;",
4332             isFloating;
4333         x = x || 0;
4334         y = y || 0;
4335         width = width || 512;
4336         height = height || 342;
4337         $(cnvs, {
4338             height: height,
4339             version: 1.1,
4340             width: width,
4341             xmlns: "http://www.w3.org/2000/svg"
4342         });
4343         if (container == 1) {
4344             cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
4345             R._g.doc.body.appendChild(cnvs);
4346             isFloating = 1;
4347         } else {
4348             cnvs.style.cssText = css + "position:relative";
4349             if (container.firstChild) {
4350                 container.insertBefore(cnvs, container.firstChild);
4351             } else {
4352                 container.appendChild(cnvs);
4353             }
4354         }
4355         container = new R._Paper;
4356         container.width = width;
4357         container.height = height;
4358         container.canvas = cnvs;
4359         // plugins.call(container, container, R.fn);
4360         container.clear();
4361         container._left = container._top = 0;
4362         isFloating && (container.renderfix = function () {});
4363         container.renderfix();
4364         return container;
4365     };
4366     R._engine.setViewBox = function (x, y, w, h, fit) {
4367         eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]);
4368         var size = mmax(w / this.width, h / this.height),
4369             top = this.top,
4370             aspectRatio = fit ? "meet" : "xMinYMin",
4371             vb,
4372             sw;
4373         if (x == null) {
4374             if (this._vbSize) {
4375                 size = 1;
4376             }
4377             delete this._vbSize;
4378             vb = "0 0 " + this.width + S + this.height;
4379         } else {
4380             this._vbSize = size;
4381             vb = x + S + y + S + w + S + h;
4382         }
4383         $(this.canvas, {
4384             viewBox: vb,
4385             preserveAspectRatio: aspectRatio
4386         });
4387         while (size && top) {
4388             sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1;
4389             top.attr({"stroke-width": sw});
4390             top._.dirty = 1;
4391             top._.dirtyT = 1;
4392             top = top.prev;
4393         }
4394         this._viewBox = [x, y, w, h, !!fit];
4395         return this;
4396     };
4397     
4398     R.prototype.renderfix = function () {
4399         var cnvs = this.canvas,
4400             s = cnvs.style,
4401             pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(),
4402             left = -pos.e % 1,
4403             top = -pos.f % 1;
4404         if (left || top) {
4405             if (left) {
4406                 this._left = (this._left + left) % 1;
4407                 s.left = this._left + "px";
4408             }
4409             if (top) {
4410                 this._top = (this._top + top) % 1;
4411                 s.top = this._top + "px";
4412             }
4413         }
4414     };
4415     
4416     R.prototype.clear = function () {
4417         R.eve("clear", this);
4418         var c = this.canvas;
4419         while (c.firstChild) {
4420             c.removeChild(c.firstChild);
4421         }
4422         this.bottom = this.top = null;
4423         (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version));
4424         c.appendChild(this.desc);
4425         c.appendChild(this.defs = $("defs"));
4426     };
4427     
4428     R.prototype.remove = function () {
4429         eve("remove", this);
4430         this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
4431         for (var i in this) {
4432             this[i] = removed(i);
4433         }
4434     };
4435     var setproto = R.st;
4436     for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
4437         setproto[method] = (function (methodname) {
4438             return function () {
4439                 var arg = arguments;
4440                 return this.forEach(function (el) {
4441                     el[methodname].apply(el, arg);
4442                 });
4443             };
4444         })(method);
4445     }
4446 }(window.Raphael);
4447
4448 // ┌─────────────────────────────────────────────────────────────────────┐ \\
4449 // │ Raphaël 2 - JavaScript Vector Library                               │ \\
4450 // ├─────────────────────────────────────────────────────────────────────┤ \\
4451 // │ VML Module                                                          │ \\
4452 // ├─────────────────────────────────────────────────────────────────────┤ \\
4453 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
4454 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
4455 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
4456 // └─────────────────────────────────────────────────────────────────────┘ \\
4457 window.Raphael.vml && function (R) {
4458     var has = "hasOwnProperty",
4459         Str = String,
4460         toFloat = parseFloat,
4461         math = Math,
4462         round = math.round,
4463         mmax = math.max,
4464         mmin = math.min,
4465         abs = math.abs,
4466         fillString = "fill",
4467         separator = /[, ]+/,
4468         eve = R.eve,
4469         ms = " progid:DXImageTransform.Microsoft",
4470         S = " ",
4471         E = "",
4472         map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"},
4473         bites = /([clmz]),?([^clmz]*)/gi,
4474         blurregexp = / progid:\S+Blur\([^\)]+\)/g,
4475         val = /-?[^,\s-]+/g,
4476         cssDot = "position:absolute;left:0;top:0;width:1px;height:1px",
4477         zoom = 21600,
4478         pathTypes = {path: 1, rect: 1, image: 1},
4479         ovalTypes = {circle: 1, ellipse: 1},
4480         path2vml = function (path) {
4481             var total =  /[ahqstv]/ig,
4482                 command = R._pathToAbsolute;
4483             Str(path).match(total) && (command = R._path2curve);
4484             total = /[clmz]/g;
4485             if (command == R._pathToAbsolute && !Str(path).match(total)) {
4486                 var res = Str(path).replace(bites, function (all, command, args) {
4487                     var vals = [],
4488                         isMove = command.toLowerCase() == "m",
4489                         res = map[command];
4490                     args.replace(val, function (value) {
4491                         if (isMove && vals.length == 2) {
4492                             res += vals + map[command == "m" ? "l" : "L"];
4493                             vals = [];
4494                         }
4495                         vals.push(round(value * zoom));
4496                     });
4497                     return res + vals;
4498                 });
4499                 return res;
4500             }
4501             var pa = command(path), p, r;
4502             res = [];
4503             for (var i = 0, ii = pa.length; i < ii; i++) {
4504                 p = pa[i];
4505                 r = pa[i][0].toLowerCase();
4506                 r == "z" && (r = "x");
4507                 for (var j = 1, jj = p.length; j < jj; j++) {
4508                     r += round(p[j] * zoom) + (j != jj - 1 ? "," : E);
4509                 }
4510                 res.push(r);
4511             }
4512             return res.join(S);
4513         },
4514         compensation = function (deg, dx, dy) {
4515             var m = R.matrix();
4516             m.rotate(-deg, .5, .5);
4517             return {
4518                 dx: m.x(dx, dy),
4519                 dy: m.y(dx, dy)
4520             };
4521         },
4522         setCoords = function (p, sx, sy, dx, dy, deg) {
4523             var _ = p._,
4524                 m = p.matrix,
4525                 fillpos = _.fillpos,
4526                 o = p.node,
4527                 s = o.style,
4528                 y = 1,
4529                 flip = "",
4530                 dxdy,
4531                 kx = zoom / sx,
4532                 ky = zoom / sy;
4533             s.visibility = "hidden";
4534             if (!sx || !sy) {
4535                 return;
4536             }
4537             o.coordsize = abs(kx) + S + abs(ky);
4538             s.rotation = deg * (sx * sy < 0 ? -1 : 1);
4539             if (deg) {
4540                 var c = compensation(deg, dx, dy);
4541                 dx = c.dx;
4542                 dy = c.dy;
4543             }
4544             sx < 0 && (flip += "x");
4545             sy < 0 && (flip += " y") && (y = -1);
4546             s.flip = flip;
4547             o.coordorigin = (dx * -kx) + S + (dy * -ky);
4548             if (fillpos || _.fillsize) {
4549                 var fill = o.getElementsByTagName(fillString);
4550                 fill = fill && fill[0];
4551                 o.removeChild(fill);
4552                 if (fillpos) {
4553                     c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1]));
4554                     fill.position = c.dx * y + S + c.dy * y;
4555                 }
4556                 if (_.fillsize) {
4557                     fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy);
4558                 }
4559                 o.appendChild(fill);
4560             }
4561             s.visibility = "visible";
4562         };
4563     R.toString = function () {
4564         return  "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version;
4565     };
4566     addArrow = function (o, value, isEnd) {
4567         var values = Str(value).toLowerCase().split("-"),
4568             se = isEnd ? "end" : "start",
4569             i = values.length,
4570             type = "classic",
4571             w = "medium",
4572             h = "medium";
4573         while (i--) {
4574             switch (values[i]) {
4575                 case "block":
4576                 case "classic":
4577                 case "oval":
4578                 case "diamond":
4579                 case "open":
4580                 case "none":
4581                     type = values[i];
4582                     break;
4583                 case "wide":
4584                 case "narrow": h = values[i]; break;
4585                 case "long":
4586                 case "short": w = values[i]; break;
4587             }
4588         }
4589         var stroke = o.node.getElementsByTagName("stroke")[0];
4590         stroke[se + "arrow"] = type;
4591         stroke[se + "arrowlength"] = w;
4592         stroke[se + "arrowwidth"] = h;
4593     };
4594     setFillAndStroke = function (o, params) {
4595         // o.paper.canvas.style.display = "none";
4596         o.attrs = o.attrs || {};
4597         var node = o.node,
4598             a = o.attrs,
4599             s = node.style,
4600             xy,
4601             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),
4602             isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry),
4603             res = o;
4604
4605
4606         for (var par in params) if (params[has](par)) {
4607             a[par] = params[par];
4608         }
4609         if (newpath) {
4610             a.path = R._getPath[o.type](o);
4611             o._.dirty = 1;
4612         }
4613         params.href && (node.href = params.href);
4614         params.title && (node.title = params.title);
4615         params.target && (node.target = params.target);
4616         params.cursor && (s.cursor = params.cursor);
4617         "blur" in params && o.blur(params.blur);
4618         if (params.path && o.type == "path" || newpath) {
4619             node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path);
4620             if (o.type == "image") {
4621                 o._.fillpos = [a.x, a.y];
4622                 o._.fillsize = [a.width, a.height];
4623                 setCoords(o, 1, 1, 0, 0, 0);
4624             }
4625         }
4626         "transform" in params && o.transform(params.transform);
4627         if (isOval) {
4628             var cx = +a.cx,
4629                 cy = +a.cy,
4630                 rx = +a.rx || +a.r || 0,
4631                 ry = +a.ry || +a.r || 0;
4632             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));
4633         }
4634         if ("clip-rect" in params) {
4635             var rect = Str(params["clip-rect"]).split(separator);
4636             if (rect.length == 4) {
4637                 rect[2] = +rect[2] + (+rect[0]);
4638                 rect[3] = +rect[3] + (+rect[1]);
4639                 var div = node.clipRect || R._g.doc.createElement("div"),
4640                     dstyle = div.style;
4641                 dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect);
4642                 if (!node.clipRect) {
4643                     dstyle.position = "absolute";
4644                     dstyle.top = 0;
4645                     dstyle.left = 0;
4646                     dstyle.width = o.paper.width + "px";
4647                     dstyle.height = o.paper.height + "px";
4648                     node.parentNode.insertBefore(div, node);
4649                     div.appendChild(node);
4650                     node.clipRect = div;
4651                 }
4652             }
4653             if (!params["clip-rect"]) {
4654                 node.clipRect && (node.clipRect.style.clip = E);
4655             }
4656         }
4657         if (o.textpath) {
4658             var textpathStyle = o.textpath.style;
4659             params.font && (textpathStyle.font = params.font);
4660             params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"');
4661             params["font-size"] && (textpathStyle.fontSize = params["font-size"]);
4662             params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]);
4663             params["font-style"] && (textpathStyle.fontStyle = params["font-style"]);
4664         }
4665         if ("arrow-start" in params) {
4666             addArrow(res, params["arrow-start"]);
4667         }
4668         if ("arrow-end" in params) {
4669             addArrow(res, params["arrow-end"], 1);
4670         }
4671         if (params.opacity != null || 
4672             params["stroke-width"] != null ||
4673             params.fill != null ||
4674             params.src != null ||
4675             params.stroke != null ||
4676             params["stroke-width"] != null ||
4677             params["stroke-opacity"] != null ||
4678             params["fill-opacity"] != null ||
4679             params["stroke-dasharray"] != null ||
4680             params["stroke-miterlimit"] != null ||
4681             params["stroke-linejoin"] != null ||
4682             params["stroke-linecap"] != null) {
4683             var fill = node.getElementsByTagName(fillString),
4684                 newfill = false;
4685             fill = fill && fill[0];
4686             !fill && (newfill = fill = createNode(fillString));
4687             if (o.type == "image" && params.src) {
4688                 fill.src = params.src;
4689             }
4690             params.fill && (fill.on = true);
4691             if (fill.on == null || params.fill == "none" || params.fill === null) {
4692                 fill.on = false;
4693             }
4694             if (fill.on && params.fill) {
4695                 var isURL = Str(params.fill).match(R._ISURL);
4696                 if (isURL) {
4697                     fill.parentNode == node && node.removeChild(fill);
4698                     fill.rotate = true;
4699                     fill.src = isURL[1];
4700                     fill.type = "tile";
4701                     var bbox = o.getBBox(1);
4702                     fill.position = bbox.x + S + bbox.y;
4703                     o._.fillpos = [bbox.x, bbox.y];
4704
4705                     R._preload(isURL[1], function () {
4706                         o._.fillsize = [this.offsetWidth, this.offsetHeight];
4707                     });
4708                 } else {
4709                     fill.color = R.getRGB(params.fill).hex;
4710                     fill.src = E;
4711                     fill.type = "solid";
4712                     if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) {
4713                         a.fill = "none";
4714                         a.gradient = params.fill;
4715                         fill.rotate = false;
4716                     }
4717                 }
4718             }
4719             if ("fill-opacity" in params || "opacity" in params) {
4720                 var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1);
4721                 opacity = mmin(mmax(opacity, 0), 1);
4722                 fill.opacity = opacity;
4723                 if (fill.src) {
4724                     fill.color = "none";
4725                 }
4726             }
4727             node.appendChild(fill);
4728             var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]),
4729             newstroke = false;
4730             !stroke && (newstroke = stroke = createNode("stroke"));
4731             if ((params.stroke && params.stroke != "none") ||
4732                 params["stroke-width"] ||
4733                 params["stroke-opacity"] != null ||
4734                 params["stroke-dasharray"] ||
4735                 params["stroke-miterlimit"] ||
4736                 params["stroke-linejoin"] ||
4737                 params["stroke-linecap"]) {
4738                 stroke.on = true;
4739             }
4740             (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false);
4741             var strokeColor = R.getRGB(params.stroke);
4742             stroke.on && params.stroke && (stroke.color = strokeColor.hex);
4743             opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1);
4744             var width = (toFloat(params["stroke-width"]) || 1) * .75;
4745             opacity = mmin(mmax(opacity, 0), 1);
4746             params["stroke-width"] == null && (width = a["stroke-width"]);
4747             params["stroke-width"] && (stroke.weight = width);
4748             width && width < 1 && (opacity *= width) && (stroke.weight = 1);
4749             stroke.opacity = opacity;
4750         
4751             params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter");
4752             stroke.miterlimit = params["stroke-miterlimit"] || 8;
4753             params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round");
4754             if (params["stroke-dasharray"]) {
4755                 var dasharray = {
4756                     "-": "shortdash",
4757                     ".": "shortdot",
4758                     "-.": "shortdashdot",
4759                     "-..": "shortdashdotdot",
4760                     ". ": "dot",
4761                     "- ": "dash",
4762                     "--": "longdash",
4763                     "- .": "dashdot",
4764                     "--.": "longdashdot",
4765                     "--..": "longdashdotdot"
4766                 };
4767                 stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E;
4768             }
4769             newstroke && node.appendChild(stroke);
4770         }
4771         if (res.type == "text") {
4772             res.paper.canvas.style.display = E;
4773             var span = res.paper.span,
4774                 m = 100,
4775                 fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/);
4776             s = span.style;
4777             a.font && (s.font = a.font);
4778             a["font-family"] && (s.fontFamily = a["font-family"]);
4779             a["font-weight"] && (s.fontWeight = a["font-weight"]);
4780             a["font-style"] && (s.fontStyle = a["font-style"]);
4781             fontSize = toFloat(fontSize ? fontSize[0] : a["font-size"]);
4782             s.fontSize = fontSize * m + "px";
4783             res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/</g, "&#60;").replace(/&/g, "&#38;").replace(/\n/g, "<br>"));
4784             var brect = span.getBoundingClientRect();
4785             res.W = a.w = (brect.right - brect.left) / m;
4786             res.H = a.h = (brect.bottom - brect.top) / m;
4787             // res.paper.canvas.style.display = "none";
4788             res.X = a.x;
4789             res.Y = a.y + res.H / 2;
4790
4791             ("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));
4792             var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"];
4793             for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) {
4794                 res._.dirty = 1;
4795                 break;
4796             }
4797         
4798             // text-anchor emulation
4799             switch (a["text-anchor"]) {
4800                 case "start":
4801                     res.textpath.style["v-text-align"] = "left";
4802                     res.bbx = res.W / 2;
4803                 break;
4804                 case "end":
4805                     res.textpath.style["v-text-align"] = "right";
4806                     res.bbx = -res.W / 2;
4807                 break;
4808                 default:
4809                     res.textpath.style["v-text-align"] = "center";
4810                     res.bbx = 0;
4811                 break;
4812             }
4813             res.textpath.style["v-text-kern"] = true;
4814         }
4815         // res.paper.canvas.style.display = E;
4816     };
4817     addGradientFill = function (o, gradient, fill) {
4818         o.attrs = o.attrs || {};
4819         var attrs = o.attrs,
4820             opacity,
4821             oindex,
4822             type = "linear",
4823             fxfy = ".5 .5";
4824         o.attrs.gradient = gradient;
4825         gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) {
4826             type = "radial";
4827             if (fx && fy) {
4828                 fx = toFloat(fx);
4829                 fy = toFloat(fy);
4830                 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5);
4831                 fxfy = fx + S + fy;
4832             }
4833             return E;
4834         });
4835         gradient = gradient.split(/\s*\-\s*/);
4836         if (type == "linear") {
4837             var angle = gradient.shift();
4838             angle = -toFloat(angle);
4839             if (isNaN(angle)) {
4840                 return null;
4841             }
4842         }
4843         var dots = R._parseDots(gradient);
4844         if (!dots) {
4845             return null;
4846         }
4847         o = o.shape || o.node;
4848         if (dots.length) {
4849             o.removeChild(fill);
4850             fill.on = true;
4851             fill.method = "none";
4852             fill.color = dots[0].color;
4853             fill.color2 = dots[dots.length - 1].color;
4854             var clrs = [];
4855             for (var i = 0, ii = dots.length; i < ii; i++) {
4856                 dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color);
4857             }
4858             fill.colors = clrs.length ? clrs.join() : "0% " + fill.color;
4859             if (type == "radial") {
4860                 fill.type = "gradientTitle";
4861                 fill.focus = "100%";
4862                 fill.focussize = "0 0";
4863                 fill.focusposition = fxfy;
4864                 fill.angle = 0;
4865             } else {
4866                 // fill.rotate= true;
4867                 fill.type = "gradient";
4868                 fill.angle = (270 - angle) % 360;
4869             }
4870             o.appendChild(fill);
4871         }
4872         return 1;
4873     };
4874     Element = function (node, vml) {
4875         this[0] = this.node = node;
4876         node.raphael = true;
4877         this.id = R._oid++;
4878         node.raphaelid = this.id;
4879         this.X = 0;
4880         this.Y = 0;
4881         this.attrs = {};
4882         this.paper = vml;
4883         this.matrix = R.matrix();
4884         this._ = {
4885             transform: [],
4886             sx: 1,
4887             sy: 1,
4888             dx: 0,
4889             dy: 0,
4890             deg: 0,
4891             dirty: 1,
4892             dirtyT: 1
4893         };
4894         !vml.bottom && (vml.bottom = this);
4895         this.prev = vml.top;
4896         vml.top && (vml.top.next = this);
4897         vml.top = this;
4898         this.next = null;
4899     };
4900     var elproto = R.el;
4901
4902     Element.prototype = elproto;
4903     elproto.constructor = Element;
4904     elproto.transform = function (tstr) {
4905         if (tstr == null) {
4906             return this._.transform;
4907         }
4908         var vbs = this.paper._viewBoxShift,
4909             vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E,
4910             oldt;
4911         if (vbs) {
4912             oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E);
4913         }
4914         R._extractTransform(this, vbt + tstr);
4915         var matrix = this.matrix.clone(),
4916             skew = this.skew,
4917             o = this.node,
4918             split,
4919             isGrad = ~Str(this.attrs.fill).indexOf("-"),
4920             isPatt = !Str(this.attrs.fill).indexOf("url(");
4921         matrix.translate(-.5, -.5);
4922         if (isPatt || isGrad || this.type == "image") {
4923             skew.matrix = "1 0 0 1";
4924             skew.offset = "0 0";
4925             split = matrix.split();
4926             if ((isGrad && split.noRotation) || !split.isSimple) {
4927                 o.style.filter = matrix.toFilter();
4928                 var bb = this.getBBox(),
4929                     bbt = this.getBBox(1),
4930                     dx = bb.x - bbt.x,
4931                     dy = bb.y - bbt.y;
4932                 o.coordorigin = (dx * -zoom) + S + (dy * -zoom);
4933                 setCoords(this, 1, 1, dx, dy, 0);
4934             } else {
4935                 o.style.filter = E;
4936                 setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate);
4937             }
4938         } else {
4939             o.style.filter = E;
4940             skew.matrix = Str(matrix);
4941             skew.offset = matrix.offset();
4942         }
4943         oldt && (this._.transform = oldt);
4944         return this;
4945     };
4946     elproto.rotate = function (deg, cx, cy) {
4947         if (this.removed) {
4948             return this;
4949         }
4950         if (deg == null) {
4951             return;
4952         }
4953         deg = Str(deg).split(separator);
4954         if (deg.length - 1) {
4955             cx = toFloat(deg[1]);
4956             cy = toFloat(deg[2]);
4957         }
4958         deg = toFloat(deg[0]);
4959         (cy == null) && (cx = cy);
4960         if (cx == null || cy == null) {
4961             var bbox = this.getBBox(1);
4962             cx = bbox.x + bbox.width / 2;
4963             cy = bbox.y + bbox.height / 2;
4964         }
4965         this._.dirtyT = 1;
4966         this.transform(this._.transform.concat([["r", deg, cx, cy]]));
4967         return this;
4968     };
4969     elproto.translate = function (dx, dy) {
4970         if (this.removed) {
4971             return this;
4972         }
4973         dx = Str(dx).split(separator);
4974         if (dx.length - 1) {
4975             dy = toFloat(dx[1]);
4976         }
4977         dx = toFloat(dx[0]) || 0;
4978         dy = +dy || 0;
4979         if (this._.bbox) {
4980             this._.bbox.x += dx;
4981             this._.bbox.y += dy;
4982         }
4983         this.transform(this._.transform.concat([["t", dx, dy]]));
4984         return this;
4985     };
4986     elproto.scale = function (sx, sy, cx, cy) {
4987         if (this.removed) {
4988             return this;
4989         }
4990         sx = Str(sx).split(separator);
4991         if (sx.length - 1) {
4992             sy = toFloat(sx[1]);
4993             cx = toFloat(sx[2]);
4994             cy = toFloat(sx[3]);
4995             isNaN(cx) && (cx = null);
4996             isNaN(cy) && (cy = null);
4997         }
4998         sx = toFloat(sx[0]);
4999         (sy == null) && (sy = sx);
5000         (cy == null) && (cx = cy);
5001         if (cx == null || cy == null) {
5002             var bbox = this.getBBox(1);
5003         }
5004         cx = cx == null ? bbox.x + bbox.width / 2 : cx;
5005         cy = cy == null ? bbox.y + bbox.height / 2 : cy;
5006     
5007         this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
5008         this._.dirtyT = 1;
5009         return this;
5010     };
5011     elproto.hide = function () {
5012         !this.removed && (this.node.style.display = "none");
5013         return this;
5014     };
5015     elproto.show = function () {
5016         !this.removed && (this.node.style.display = E);
5017         return this;
5018     };
5019     elproto._getBBox = function () {
5020         if (this.removed) {
5021             return {};
5022         }
5023         if (this.type == "text") {
5024             return {
5025                 x: this.X + (this.bbx || 0) - this.W / 2,
5026                 y: this.Y - this.H,
5027                 width: this.W,
5028                 height: this.H
5029             };
5030         } else {
5031             return pathDimensions(this.attrs.path);
5032         }
5033     };
5034     elproto.remove = function () {
5035         if (this.removed) {
5036             return;
5037         }
5038         this.paper.__set__ && this.paper.__set__.exclude(this);
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);