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