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