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