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