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