Animation status fix
[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 = /([achlmrqstvz])[\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, r: 4, 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, anim, params, ms, easing, callback) {
2563         var a = params ? R.animation(params, ms, easing, callback) : anim;
2564             status = element.status(anim);
2565         this.animate(a);
2566         return this.status(a, status * anim.ms / a.ms);
2567     };
2568     function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) {
2569         var cx = 3 * p1x,
2570             bx = 3 * (p2x - p1x) - cx,
2571             ax = 1 - cx - bx,
2572             cy = 3 * p1y,
2573             by = 3 * (p2y - p1y) - cy,
2574             ay = 1 - cy - by;
2575         function sampleCurveX(t) {
2576             return ((ax * t + bx) * t + cx) * t;
2577         }
2578         function solve(x, epsilon) {
2579             var t = solveCurveX(x, epsilon);
2580             return ((ay * t + by) * t + cy) * t;
2581         }
2582         function solveCurveX(x, epsilon) {
2583             var t0, t1, t2, x2, d2, i;
2584             for(t2 = x, i = 0; i < 8; i++) {
2585                 x2 = sampleCurveX(t2) - x;
2586                 if (abs(x2) < epsilon) {
2587                     return t2;
2588                 }
2589                 d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
2590                 if (abs(d2) < 1e-6) {
2591                     break;
2592                 }
2593                 t2 = t2 - x2 / d2;
2594             }
2595             t0 = 0;
2596             t1 = 1;
2597             t2 = x;
2598             if (t2 < t0) {
2599                 return t0;
2600             }
2601             if (t2 > t1) {
2602                 return t1;
2603             }
2604             while (t0 < t1) {
2605                 x2 = sampleCurveX(t2);
2606                 if (abs(x2 - x) < epsilon) {
2607                     return t2;
2608                 }
2609                 if (x > x2) {
2610                     t0 = t2;
2611                 } else {
2612                     t1 = t2;
2613                 }
2614                 t2 = (t1 - t0) / 2 + t0;
2615             }
2616             return t2;
2617         }
2618         return solve(t, 1 / (200 * duration));
2619     }
2620     elproto.onAnimation = function (f) {
2621         f ? eve.on("anim.frame." + this.id, f) : eve.unbind("anim.frame." + this.id);
2622         return this;
2623     };
2624     function Animation(anim, ms) {
2625         var percents = [];
2626         this.anim = anim;
2627         this.ms = ms;
2628         this.times = 1;
2629         if (this.anim) {
2630             for (var attr in this.anim) if (this.anim[has](attr)) {
2631                 percents.push(+attr);
2632             }
2633             percents.sort(sortByNumber);
2634         }
2635         this.top = percents[percents.length - 1];
2636         this.percents = percents;
2637     }
2638     
2639     Animation.prototype.delay = function (delay) {
2640         var a = new Animation(this.anim, this.ms);
2641         a.times = this.times;
2642         a.del = +delay || 0;
2643         return a;
2644     };
2645     
2646     Animation.prototype.repeat = function (times) { 
2647         var a = new Animation(this.anim, this.ms);
2648         a.del = this.del;
2649         a.times = math.floor(mmax(times, 0)) || 1;
2650         return a;
2651     };
2652     function runAnimation(anim, element, percent, status, totalOrigin, times) {
2653         percent = toFloat(percent);
2654         var params,
2655             isInAnim,
2656             isInAnimSet,
2657             percents = [],
2658             next,
2659             prev,
2660             timestamp,
2661             ms = anim.ms,
2662             from = {},
2663             to = {},
2664             diff = {};
2665         if (status) {
2666             for (i = 0, ii = animationElements.length; i < ii; i++) {
2667                 var e = animationElements[i];
2668                 if (e.el.id == element.id && e.anim == anim) {
2669                     if (e.percent != percent) {
2670                         animationElements.splice(i, 1);
2671                         isInAnimSet = 1;
2672                     } else {
2673                         isInAnim = e;
2674                     }
2675                     element.attr(e.totalOrigin);
2676                     break;
2677                 }
2678             }
2679         } else {
2680             status = +to; // NaN
2681         }
2682         for (var i = 0, ii = anim.percents.length; i < ii; i++) {
2683             if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) {
2684                 percent = anim.percents[i];
2685                 prev = anim.percents[i - 1] || 0;
2686                 ms = ms / anim.top * (percent - prev);
2687                 next = anim.percents[i + 1];
2688                 params = anim.anim[percent];
2689                 break;
2690             } else if (status) {
2691                 element.attr(anim.anim[anim.percents[i]]);
2692             }
2693         }
2694         if (!params) {
2695             return;
2696         }
2697         if (!isInAnim) {
2698             for (attr in params) if (params[has](attr)) {
2699                 if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) {
2700                     from[attr] = element.attr(attr);
2701                     (from[attr] == null) && (from[attr] = availableAttrs[attr]);
2702                     to[attr] = params[attr];
2703                     switch (availableAnimAttrs[attr]) {
2704                         case nu:
2705                             diff[attr] = (to[attr] - from[attr]) / ms;
2706                             break;
2707                         case "colour":
2708                             from[attr] = R.getRGB(from[attr]);
2709                             var toColour = R.getRGB(to[attr]);
2710                             diff[attr] = {
2711                                 r: (toColour.r - from[attr].r) / ms,
2712                                 g: (toColour.g - from[attr].g) / ms,
2713                                 b: (toColour.b - from[attr].b) / ms
2714                             };
2715                             break;
2716                         case "path":
2717                             var pathes = path2curve(from[attr], to[attr]),
2718                                 toPath = pathes[1];
2719                             from[attr] = pathes[0];
2720                             diff[attr] = [];
2721                             for (i = 0, ii = from[attr].length; i < ii; i++) {
2722                                 diff[attr][i] = [0];
2723                                 for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
2724                                     diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms;
2725                                 }
2726                             }
2727                             break;
2728                         case "transform":
2729                             var _ = element._,
2730                                 eq = equaliseTransform(_[attr], to[attr]);
2731                             if (eq) {
2732                                 from[attr] = eq.from;
2733                                 to[attr] = eq.to;
2734                                 diff[attr] = [];
2735                                 diff[attr].real = true;
2736                                 for (i = 0, ii = from[attr].length; i < ii; i++) {
2737                                     diff[attr][i] = [from[attr][i][0]];
2738                                     for (j = 1, jj = from[attr][i].length; j < jj; j++) {
2739                                         diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms;
2740                                     }
2741                                 }
2742                             } else {
2743                                 var m = (element.matrix || new Matrix),
2744                                     to2 = {
2745                                         _: {transform: _.transform},
2746                                         getBBox: function () {
2747                                             return element.getBBox(1);
2748                                         }
2749                                     };
2750                                 from[attr] = [
2751                                     m.a,
2752                                     m.b,
2753                                     m.c,
2754                                     m.d,
2755                                     m.e,
2756                                     m.f
2757                                 ];
2758                                 extractTransform(to2, to[attr]);
2759                                 to[attr] = to2._.transform;
2760                                 diff[attr] = [
2761                                     (to2.matrix.a - m.a) / ms,
2762                                     (to2.matrix.b - m.b) / ms,
2763                                     (to2.matrix.c - m.c) / ms,
2764                                     (to2.matrix.d - m.d) / ms,
2765                                     (to2.matrix.e - m.e) / ms,
2766                                     (to2.matrix.e - m.f) / ms
2767                                 ];
2768                                 // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy];
2769                                 // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }};
2770                                 // extractTransform(to2, to[attr]);
2771                                 // diff[attr] = [
2772                                 //     (to2._.sx - _.sx) / ms,
2773                                 //     (to2._.sy - _.sy) / ms,
2774                                 //     (to2._.deg - _.deg) / ms,
2775                                 //     (to2._.dx - _.dx) / ms,
2776                                 //     (to2._.dy - _.dy) / ms
2777                                 // ];
2778                             }
2779                             break;
2780                         case "csv":
2781                             var values = Str(params[attr]).split(separator),
2782                                 from2 = Str(from[attr]).split(separator);
2783                             if (attr == "clip-rect") {
2784                                 from[attr] = from2;
2785                                 diff[attr] = [];
2786                                 i = from2.length;
2787                                 while (i--) {
2788                                     diff[attr][i] = (values[i] - from[attr][i]) / ms;
2789                                 }
2790                             }
2791                             to[attr] = values;
2792                             break;
2793                         default:
2794                             values = [].concat(params[attr]);
2795                             from2 = [].concat(from[attr]);
2796                             diff[attr] = [];
2797                             i = element.paper.customAttributes[attr].length;
2798                             while (i--) {
2799                                 diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms;
2800                             }
2801                             break;
2802                     }
2803                 }
2804             }
2805             var easing = params.easing,
2806                 easyeasy = R.easing_formulas[easing];
2807             if (!easyeasy) {
2808                 easyeasy = Str(easing).match(bezierrg);
2809                 if (easyeasy && easyeasy.length == 5) {
2810                     var curve = easyeasy;
2811                     easyeasy = function (t) {
2812                         return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms);
2813                     };
2814                 } else {
2815                     easyeasy = pipe;
2816                 }
2817             }
2818             timestamp = params.start || anim.start || +new Date;
2819             e = {
2820                 anim: anim,
2821                 percent: percent,
2822                 timestamp: timestamp,
2823                 start: timestamp + (anim.del || 0),
2824                 status: 0,
2825                 initstatus: status || 0,
2826                 stop: false,
2827                 ms: ms,
2828                 easing: easyeasy,
2829                 from: from,
2830                 diff: diff,
2831                 to: to,
2832                 el: element,
2833                 callback: params.callback,
2834                 prev: prev,
2835                 next: next,
2836                 repeat: times || anim.times,
2837                 origin: element.attr(),
2838                 totalOrigin: totalOrigin
2839             };
2840             animationElements.push(e);
2841             if (status && !isInAnim && !isInAnimSet) {
2842                 e.stop = true;
2843                 e.start = new Date - ms * status;
2844                 if (animationElements.length == 1) {
2845                     return animation();
2846                 }
2847             }
2848             if (isInAnimSet) {
2849                 e.start = new Date - e.ms * status;
2850             }
2851             animationElements.length == 1 && requestAnimFrame(animation);
2852         } else {
2853             isInAnim.initstatus = status;
2854             isInAnim.start = new Date - isInAnim.ms * status;
2855         }
2856         eve("anim.start." + element.id, element, anim);
2857     }
2858     
2859     R.animation = function (params, ms, easing, callback) {
2860         if (params instanceof Animation) {
2861             return params;
2862         }
2863         if (R.is(easing, "function") || !easing) {
2864             callback = callback || easing || null;
2865             easing = null;
2866         }
2867         params = Object(params);
2868         ms = +ms || 0;
2869         var p = {},
2870             json,
2871             attr;
2872         for (attr in params) if (params[has](attr) && toFloat(attr) != attr) {
2873             json = true;
2874             p[attr] = params[attr];
2875         }
2876         if (!json) {
2877             return new Animation(params, ms);
2878         } else {
2879             easing && (p.easing = easing);
2880             callback && (p.callback = callback);
2881             return new Animation({100: p}, ms);
2882         }
2883     };
2884     
2885     elproto.animate = function (params, ms, easing, callback) {
2886         var element = this;
2887         if (element.removed) {
2888             callback && callback.call(element);
2889             return element;
2890         }
2891         var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback);
2892         runAnimation(anim, element, anim.percents[0], null, element.attr());
2893         return element;
2894     };
2895     
2896     elproto.setTime = function (anim, value) {
2897         if (anim && value != null) {
2898             this.status(anim, mmin(value, anim.ms) / anim.ms);
2899         }
2900         return this;
2901     };
2902     
2903     elproto.status = function (anim, value) {
2904         var out = [],
2905             i = 0,
2906             len,
2907             e;
2908         if (value != null) {
2909             runAnimation(anim, this, -1, mmin(value, 1));
2910             return this;
2911         } else {
2912             len = animationElements.length;
2913             for (; i < len; i++) {
2914                 e = animationElements[i];
2915                 if (e.el.id == this.id && (!anim || e.anim == anim)) {
2916                     if (anim) {
2917                         return e.status;
2918                     }
2919                     out.push({
2920                         anim: e.anim,
2921                         status: e.status
2922                     });
2923                 }
2924             }
2925             if (anim) {
2926                 return 0;
2927             }
2928             return out;
2929         }
2930     };
2931     
2932     elproto.pause = function (anim) {
2933         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
2934             if (eve("anim.pause." + this.id, this, animationElements[i].anim) !== false) {
2935                 animationElements[i].paused = true;
2936             }
2937         }
2938         return this;
2939     };
2940     
2941     elproto.resume = function (anim) {
2942         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
2943             var e = animationElements[i];
2944             if (eve("anim.resume." + this.id, this, e.anim) !== false) {
2945                 delete e.paused;
2946                 this.status(e.anim, e.status);
2947             }
2948         }
2949         return this;
2950     };
2951     
2952     elproto.stop = function (anim) {
2953         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
2954             if (eve("anim.stop." + this.id, this, animationElements[i].anim) !== false) {
2955                 animationElements.splice(i--, 1);
2956             }
2957         }
2958         return this;
2959     };
2960     elproto.toString = function () {
2961         return "Rapha\xebl\u2019s object";
2962     };
2963
2964     // Set
2965     var Set = function (items) {
2966         this.items = [];
2967         this.length = 0;
2968         this.type = "set";
2969         if (items) {
2970             for (var i = 0, ii = items.length; i < ii; i++) {
2971                 if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) {
2972                     this[this.items.length] = this.items[this.items.length] = items[i];
2973                     this.length++;
2974                 }
2975             }
2976         }
2977     },
2978     setproto = Set.prototype;
2979     
2980     setproto.push = function () {
2981         var item,
2982             len;
2983         for (var i = 0, ii = arguments.length; i < ii; i++) {
2984             item = arguments[i];
2985             if (item && (item.constructor == elproto.constructor || item.constructor == Set)) {
2986                 len = this.items.length;
2987                 this[len] = this.items[len] = item;
2988                 this.length++;
2989             }
2990         }
2991         return this;
2992     };
2993     
2994     setproto.pop = function () {
2995         this.length && delete this[this.length--];
2996         return this.items.pop();
2997     };
2998     
2999     setproto.forEach = function (callback, thisArg) {
3000         for (var i = 0, ii = this.items.length; i < ii; i++) {
3001             if (callback.call(thisArg, this.items[i]) === false) {
3002                 return this;
3003             }
3004         }
3005         return this;
3006     };
3007     for (var method in elproto) if (elproto[has](method)) {
3008         setproto[method] = (function (methodname) {
3009             return function () {
3010                 var arg = arguments;
3011                 return this.forEach(function (el) {
3012                     el[methodname][apply](el, arg);
3013                 });
3014             };
3015         })(method);
3016     }
3017     setproto.attr = function (name, value) {
3018         if (name && R.is(name, array) && R.is(name[0], "object")) {
3019             for (var j = 0, jj = name.length; j < jj; j++) {
3020                 this.items[j].attr(name[j]);
3021             }
3022         } else {
3023             for (var i = 0, ii = this.items.length; i < ii; i++) {
3024                 this.items[i].attr(name, value);
3025             }
3026         }
3027         return this;
3028     };
3029     
3030     setproto.clear = function () {
3031         while (this.length) {
3032             this.pop();
3033         }
3034     };
3035     
3036     setproto.splice = function (index, count, insertion) {
3037         index = index < 0 ? mmax(this.length + index, 0) : index;
3038         count = mmax(0, mmin(this.length - index, count));
3039         var tail = [],
3040             todel = [],
3041             args = [],
3042             i;
3043         for (i = 2; i < arguments.length; i++) {
3044             args.push(arguments[i]);
3045         }
3046         for (i = 0; i < count; i++) {
3047             todel.push(this[index + i]);
3048         }
3049         for (; i < this.length - index; i++) {
3050             tail.push(this[index + i]);
3051         }
3052         var arglen = args.length;
3053         for (i = 0; i < arglen + tail.length; i++) {
3054             this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen];
3055         }
3056         i = this.items.length = this.length -= count - arglen;
3057         while (this[i]) {
3058             delete this[i++];
3059         }
3060         return new Set(todel);
3061     };
3062     
3063     setproto.exclude = function (el) {
3064         for (var i = 0, ii = this.length, found; i < ii; i++) if (found || this[i] == el) {
3065             this[i] = this[i + 1];
3066             found = 1;
3067         }
3068         if (found) {
3069             this.length--;
3070             delete this[i];
3071             return true;
3072         }
3073     };
3074     setproto.animate = function (params, ms, easing, callback) {
3075         (R.is(easing, "function") || !easing) && (callback = easing || null);
3076         var len = this.items.length,
3077             i = len,
3078             item,
3079             set = this,
3080             collector;
3081         if (!len) {
3082             return this;
3083         }
3084         callback && (collector = function () {
3085             !--len && callback.call(set);
3086         });
3087         easing = R.is(easing, string) ? easing : collector;
3088         var anim = R.animation(params, ms, easing, collector);
3089         item = this.items[--i].animate(anim);
3090         while (i--) {
3091             this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim);
3092         }
3093         return this;
3094     };
3095     setproto.insertAfter = function (el) {
3096         var i = this.items.length;
3097         while (i--) {
3098             this.items[i].insertAfter(el);
3099         }
3100         return this;
3101     };
3102     setproto.getBBox = function () {
3103         var x = [],
3104             y = [],
3105             w = [],
3106             h = [];
3107         for (var i = this.items.length; i--;) if (!this.items[i].removed) {
3108             var box = this.items[i].getBBox();
3109             x.push(box.x);
3110             y.push(box.y);
3111             w.push(box.x + box.width);
3112             h.push(box.y + box.height);
3113         }
3114         x = mmin[apply](0, x);
3115         y = mmin[apply](0, y);
3116         return {
3117             x: x,
3118             y: y,
3119             width: mmax[apply](0, w) - x,
3120             height: mmax[apply](0, h) - y
3121         };
3122     };
3123     setproto.clone = function (s) {
3124         s = new Set;
3125         for (var i = 0, ii = this.items.length; i < ii; i++) {
3126             s.push(this.items[i].clone());
3127         }
3128         return s;
3129     };
3130     setproto.toString = function () {
3131         return "Rapha\xebl\u2018s set";
3132     };
3133
3134     
3135     R.registerFont = function (font) {
3136         if (!font.face) {
3137             return font;
3138         }
3139         this.fonts = this.fonts || {};
3140         var fontcopy = {
3141                 w: font.w,
3142                 face: {},
3143                 glyphs: {}
3144             },
3145             family = font.face["font-family"];
3146         for (var prop in font.face) if (font.face[has](prop)) {
3147             fontcopy.face[prop] = font.face[prop];
3148         }
3149         if (this.fonts[family]) {
3150             this.fonts[family].push(fontcopy);
3151         } else {
3152             this.fonts[family] = [fontcopy];
3153         }
3154         if (!font.svg) {
3155             fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10);
3156             for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) {
3157                 var path = font.glyphs[glyph];
3158                 fontcopy.glyphs[glyph] = {
3159                     w: path.w,
3160                     k: {},
3161                     d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) {
3162                             return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M";
3163                         }) + "z"
3164                 };
3165                 if (path.k) {
3166                     for (var k in path.k) if (path[has](k)) {
3167                         fontcopy.glyphs[glyph].k[k] = path.k[k];
3168                     }
3169                 }
3170             }
3171         }
3172         return font;
3173     };
3174     
3175     paperproto.getFont = function (family, weight, style, stretch) {
3176         stretch = stretch || "normal";
3177         style = style || "normal";
3178         weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400;
3179         if (!R.fonts) {
3180             return;
3181         }
3182         var font = R.fonts[family];
3183         if (!font) {
3184             var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i");
3185             for (var fontName in R.fonts) if (R.fonts[has](fontName)) {
3186                 if (name.test(fontName)) {
3187                     font = R.fonts[fontName];
3188                     break;
3189                 }
3190             }
3191         }
3192         var thefont;
3193         if (font) {
3194             for (var i = 0, ii = font.length; i < ii; i++) {
3195                 thefont = font[i];
3196                 if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) {
3197                     break;
3198                 }
3199             }
3200         }
3201         return thefont;
3202     };
3203     
3204     paperproto.print = function (x, y, string, font, size, origin, letter_spacing) {
3205         origin = origin || "middle"; // baseline|middle
3206         letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1);
3207         var out = this.set(),
3208             letters = Str(string).split(E),
3209             shift = 0,
3210             path = E,
3211             scale;
3212         R.is(font, string) && (font = this.getFont(font));
3213         if (font) {
3214             scale = (size || 16) / font.face["units-per-em"];
3215             var bb = font.face.bbox.split(separator),
3216                 top = +bb[0],
3217                 height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2);
3218             for (var i = 0, ii = letters.length; i < ii; i++) {
3219                 var prev = i && font.glyphs[letters[i - 1]] || {},
3220                     curr = font.glyphs[letters[i]];
3221                 shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0;
3222                 curr && curr.d && out.push(this.path(curr.d).attr({
3223                     fill: "#000",
3224                     stroke: "none",
3225                     transform: [["t", shift * scale, 0]]
3226                 }));
3227             }
3228             out.transform(["...s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]);
3229         }
3230         return out;
3231     };
3232
3233     
3234     R.format = function (token, params) {
3235         var args = R.is(params, array) ? [0][concat](params) : arguments;
3236         token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) {
3237             return args[++i] == null ? E : args[i];
3238         }));
3239         return token || E;
3240     };
3241     
3242     R.fullfill = (function () {
3243         var tokenRegex = /\{([^\}]+)\}/g,
3244             objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
3245             replacer = function (all, key, obj) {
3246                 var res = obj;
3247                 key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
3248                     name = name || quotedName;
3249                     if (res) {
3250                         if (name in res) {
3251                             res = res[name];
3252                         }
3253                         typeof res == "function" && isFunc && (res = res());
3254                     }
3255                 });
3256                 res = (res == null || res == obj ? all : res) + "";
3257                 return res;
3258             };
3259         return function (str, obj) {
3260             return String(str).replace(tokenRegex, function (all, key) {
3261                 return replacer(all, key, obj);
3262             });
3263         };
3264     })();
3265     
3266     R.ninja = function () {
3267         oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael;
3268         return R;
3269     };
3270     
3271     R.st = setproto;
3272     // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
3273     (function (doc, loaded, f) {
3274         if (doc.readyState == null && doc.addEventListener){
3275             doc.addEventListener(loaded, f = function () {
3276                 doc.removeEventListener(loaded, f, false);
3277                 doc.readyState = "complete";
3278             }, false);
3279             doc.readyState = "loading";
3280         }
3281         function isLoaded() {
3282             (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("DOMload");
3283         }
3284         isLoaded();
3285     })(document, "DOMContentLoaded");
3286
3287     oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R);
3288     
3289     eve.on("DOMload", function () {
3290         loaded = true;
3291     });
3292 })();
3293
3294 // ┌─────────────────────────────────────────────────────────────────────┐ \\
3295 // │ Raphaël 2 - JavaScript Vector Library                               │ \\
3296 // ├─────────────────────────────────────────────────────────────────────┤ \\
3297 // │ SVG Module                                                          │ \\
3298 // ├─────────────────────────────────────────────────────────────────────┤ \\
3299 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
3300 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
3301 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
3302 // └─────────────────────────────────────────────────────────────────────┘ \\
3303 window.Raphael.svg && function (R) {
3304     var has = "hasOwnProperty",
3305         Str = String,
3306         toFloat = parseFloat,
3307         toInt = parseInt,
3308         math = Math,
3309         mmax = math.max,
3310         abs = math.abs,
3311         pow = math.pow,
3312         separator = /[, ]+/,
3313         eve = R.eve,
3314         E = "",
3315         S = " ";
3316     var xlink = "http://www.w3.org/1999/xlink",
3317         markers = {
3318             block: "M5,0 0,2.5 5,5z",
3319             classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z",
3320             diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z",
3321             open: "M6,1 1,3.5 6,6",
3322             oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"
3323         },
3324         markerCounter = {};
3325     R.toString = function () {
3326         return  "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version;
3327     };
3328     var $ = function (el, attr) {
3329         if (attr) {
3330             if (typeof el == "string") {
3331                 el = $(el);
3332             }
3333             for (var key in attr) if (attr[has](key)) {
3334                 if (key.substring(0, 6) == "xlink:") {
3335                     el.setAttributeNS(xlink, key.substring(6), Str(attr[key]));
3336                 } else {
3337                     el.setAttribute(key, Str(attr[key]));
3338                 }
3339             }
3340         } else {
3341             el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el);
3342             el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)");
3343         }
3344         return el;
3345     },
3346     gradients = {},
3347     rgGrad = /^url\(#(.*)\)$/,
3348     removeGradientFill = function (node, paper) {
3349         var oid = node.getAttribute("fill");
3350         oid = oid && oid.match(rgGrad);
3351         if (oid && !--gradients[oid[1]]) {
3352             delete gradients[oid[1]];
3353             paper.defs.removeChild(R._g.doc.getElementById(oid[1]));
3354         }
3355     },
3356     addGradientFill = function (element, gradient) {
3357         var type = "linear",
3358             id = element.id + gradient,
3359             fx = .5, fy = .5,
3360             o = element.node,
3361             SVG = element.paper,
3362             s = o.style,
3363             el = R._g.doc.getElementById(id);
3364         if (!el) {
3365             gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) {
3366                 type = "radial";
3367                 if (_fx && _fy) {
3368                     fx = toFloat(_fx);
3369                     fy = toFloat(_fy);
3370                     var dir = ((fy > .5) * 2 - 1);
3371                     pow(fx - .5, 2) + pow(fy - .5, 2) > .25 &&
3372                         (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) &&
3373                         fy != .5 &&
3374                         (fy = fy.toFixed(5) - 1e-5 * dir);
3375                 }
3376                 return E;
3377             });
3378             gradient = gradient.split(/\s*\-\s*/);
3379             if (type == "linear") {
3380                 var angle = gradient.shift();
3381                 angle = -toFloat(angle);
3382                 if (isNaN(angle)) {
3383                     return null;
3384                 }
3385                 var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))],
3386                     max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1);
3387                 vector[2] *= max;
3388                 vector[3] *= max;
3389                 if (vector[2] < 0) {
3390                     vector[0] = -vector[2];
3391                     vector[2] = 0;
3392                 }
3393                 if (vector[3] < 0) {
3394                     vector[1] = -vector[3];
3395                     vector[3] = 0;
3396                 }
3397             }
3398             var dots = R._parseDots(gradient);
3399             if (!dots) {
3400                 return null;
3401             }
3402             if (element.gradient) {
3403                 SVG.defs.removeChild(element.gradient);
3404                 delete element.gradient;
3405             }
3406
3407             id = id.replace(/[\(\)\s,\xb0#]/g, "-");
3408             el = $(type + "Gradient", {id: id});
3409             element.gradient = el;
3410             $(el, type == "radial" ? {
3411                 fx: fx,
3412                 fy: fy
3413             } : {
3414                 x1: vector[0],
3415                 y1: vector[1],
3416                 x2: vector[2],
3417                 y2: vector[3],
3418                 gradientTransform: element.matrix.invert()
3419             });
3420             SVG.defs.appendChild(el);
3421             for (var i = 0, ii = dots.length; i < ii; i++) {
3422                 el.appendChild($("stop", {
3423                     offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
3424                     "stop-color": dots[i].color || "#fff"
3425                 }));
3426             }
3427         }
3428         $(o, {
3429             fill: "url(#" + id + ")",
3430             opacity: 1,
3431             "fill-opacity": 1
3432         });
3433         s.fill = E;
3434         s.opacity = 1;
3435         s.fillOpacity = 1;
3436         return 1;
3437     },
3438     updatePosition = function (o) {
3439         var bbox = o.getBBox(1);
3440         $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"});
3441     },
3442     addArrow = function (o, value, isEnd) {
3443         if (o.type == "path") {
3444             var values = Str(value).toLowerCase().split("-"),
3445                 p = o.paper,
3446                 se = isEnd ? "end" : "start",
3447                 node = o.node,
3448                 attrs = o.attrs,
3449                 stroke = attrs["stroke-width"],
3450                 i = values.length,
3451                 type = "classic",
3452                 from,
3453                 to,
3454                 dx,
3455                 refX,
3456                 attr,
3457                 w = 3,
3458                 h = 3,
3459                 t = 5;
3460             while (i--) {
3461                 switch (values[i]) {
3462                     case "block":
3463                     case "classic":
3464                     case "oval":
3465                     case "diamond":
3466                     case "open":
3467                     case "none":
3468                         type = values[i];
3469                         break;
3470                     case "wide": h = 5; break;
3471                     case "narrow": h = 2; break;
3472                     case "long": w = 5; break;
3473                     case "short": w = 2; break;
3474                 }
3475             }
3476             if (type == "open") {
3477                 w += 2;
3478                 h += 2;
3479                 t += 2;
3480                 dx = 1;
3481                 refX = isEnd ? 4 : 1;
3482                 attr = {
3483                     fill: "none",
3484                     stroke: attrs.stroke
3485                 };
3486             } else {
3487                 refX = dx = w / 2;
3488                 attr = {
3489                     fill: attrs.stroke,
3490                     stroke: "none"
3491                 };
3492             }
3493             if (o._.arrows) {
3494                 if (isEnd) {
3495                     o._.arrows.endPath && markerCounter[o._.arrows.endPath]--;
3496                     o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--;
3497                 } else {
3498                     o._.arrows.startPath && markerCounter[o._.arrows.startPath]--;
3499                     o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--;
3500                 }
3501             } else {
3502                 o._.arrows = {};
3503             }
3504             if (type != "none") {
3505                 var pathId = "raphael-marker-" + type,
3506                     markerId = "raphael-marker-" + se + type + w + h;
3507                 if (!R._g.doc.getElementById(pathId)) {
3508                     p.defs.appendChild($($("path"), {
3509                         "stroke-linecap": "round",
3510                         d: markers[type],
3511                         id: pathId
3512                     }));
3513                     markerCounter[pathId] = 1;
3514                 } else {
3515                     markerCounter[pathId]++;
3516                 }
3517                 var marker = R._g.doc.getElementById(markerId),
3518                     use;
3519                 if (!marker) {
3520                     marker = $($("marker"), {
3521                         id: markerId,
3522                         markerHeight: h,
3523                         markerWidth: w,
3524                         orient: "auto",
3525                         refX: refX,
3526                         refY: h / 2
3527                     });
3528                     use = $($("use"), {
3529                         "xlink:href": "#" + pathId,
3530                         transform: (isEnd ? " rotate(180 " + w / 2 + " " + h / 2 + ") " : S) + "scale(" + w / t + "," + h / t + ")",
3531                         "stroke-width": 1 / ((w / t + h / t) / 2)
3532                     });
3533                     marker.appendChild(use);
3534                     p.defs.appendChild(marker);
3535                     markerCounter[markerId] = 1;
3536                 } else {
3537                     markerCounter[markerId]++;
3538                     use = marker.getElementsByTagName("use")[0];
3539                 }
3540                 $(use, attr);
3541                 var delta = dx * (type != "diamond" && type != "oval");
3542                 if (isEnd) {
3543                     from = o._.arrows.startdx * stroke || 0;
3544                     to = R.getTotalLength(attrs.path) - delta * stroke;
3545                 } else {
3546                     from = delta * stroke;
3547                     to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
3548                 }
3549                 attr = {};
3550                 attr["marker-" + se] = "url(#" + markerId + ")";
3551                 if (to || from) {
3552                     attr.d = Raphael.getSubpath(attrs.path, from, to);
3553                 }
3554                 $(node, attr);
3555                 o._.arrows[se + "Path"] = pathId;
3556                 o._.arrows[se + "Marker"] = markerId;
3557                 o._.arrows[se + "dx"] = delta;
3558                 o._.arrows[se + "Type"] = type;
3559                 o._.arrows[se + "String"] = value;
3560             } else {
3561                 if (isEnd) {
3562                     from = o._.arrows.startdx * stroke || 0;
3563                     to = R.getTotalLength(attrs.path) - from;
3564                 } else {
3565                     from = 0;
3566                     to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
3567                 }
3568                 o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)});
3569                 delete o._.arrows[se + "Path"];
3570                 delete o._.arrows[se + "Marker"];
3571                 delete o._.arrows[se + "dx"];
3572                 delete o._.arrows[se + "Type"];
3573                 delete o._.arrows[se + "String"];
3574             }
3575             for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) {
3576                 var item = R._g.doc.getElementById(attr);
3577                 item && item.parentNode.removeChild(item);
3578             }
3579         }
3580     },
3581     dasharray = {
3582         "": [0],
3583         "none": [0],
3584         "-": [3, 1],
3585         ".": [1, 1],
3586         "-.": [3, 1, 1, 1],
3587         "-..": [3, 1, 1, 1, 1, 1],
3588         ". ": [1, 3],
3589         "- ": [4, 3],
3590         "--": [8, 3],
3591         "- .": [4, 3, 1, 3],
3592         "--.": [8, 3, 1, 3],
3593         "--..": [8, 3, 1, 3, 1, 3]
3594     },
3595     addDashes = function (o, value, params) {
3596         value = dasharray[Str(value).toLowerCase()];
3597         if (value) {
3598             var width = o.attrs["stroke-width"] || "1",
3599                 butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
3600                 dashes = [],
3601                 i = value.length;
3602             while (i--) {
3603                 dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
3604             }
3605             $(o.node, {"stroke-dasharray": dashes.join(",")});
3606         }
3607     },
3608     setFillAndStroke = function (o, params) {
3609         var node = o.node,
3610             attrs = o.attrs,
3611             vis = node.style.visibility;
3612         node.style.visibility = "hidden";
3613         for (var att in params) {
3614             if (params[has](att)) {
3615                 if (!R._availableAttrs[has](att)) {
3616                     continue;
3617                 }
3618                 var value = params[att];
3619                 attrs[att] = value;
3620                 switch (att) {
3621                     case "blur":
3622                         o.blur(value);
3623                         break;
3624                     case "href":
3625                     case "title":
3626                     case "target":
3627                         var pn = node.parentNode;
3628                         if (pn.tagName.toLowerCase() != "a") {
3629                             var hl = $("a");
3630                             pn.insertBefore(hl, node);
3631                             hl.appendChild(node);
3632                             pn = hl;
3633                         }
3634                         if (att == "target" && value == "blank") {
3635                             pn.setAttributeNS(xlink, "show", "new");
3636                         } else {
3637                             pn.setAttributeNS(xlink, att, value);
3638                         }
3639                         break;
3640                     case "cursor":
3641                         node.style.cursor = value;
3642                         break;
3643                     case "transform":
3644                         o.transform(value);
3645                         break;
3646                     case "arrow-start":
3647                         addArrow(o, value);
3648                         break;
3649                     case "arrow-end":
3650                         addArrow(o, value, 1);
3651                         break;
3652                     case "clip-rect":
3653                         var rect = Str(value).split(separator);
3654                         if (rect.length == 4) {
3655                             o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
3656                             var el = $("clipPath"),
3657                                 rc = $("rect");
3658                             el.id = R._createUUID();
3659                             $(rc, {
3660                                 x: rect[0],
3661                                 y: rect[1],
3662                                 width: rect[2],
3663                                 height: rect[3]
3664                             });
3665                             el.appendChild(rc);
3666                             o.paper.defs.appendChild(el);
3667                             $(node, {"clip-path": "url(#" + el.id + ")"});
3668                             o.clip = rc;
3669                         }
3670                         if (!value) {
3671                             var clip = R._g.doc.getElementById(node.getAttribute("clip-path").replace(/(^url\(#|\)$)/g, E));
3672                             clip && clip.parentNode.removeChild(clip);
3673                             $(node, {"clip-path": E});
3674                             delete o.clip;
3675                         }
3676                     break;
3677                     case "path":
3678                         if (o.type == "path") {
3679                             $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"});
3680                             o._.dirty = 1;
3681                             if (o._.arrows) {
3682                                 "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3683                                 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3684                             }
3685                         }
3686                         break;
3687                     case "width":
3688                         node.setAttribute(att, value);
3689                         o._.dirty = 1;
3690                         if (attrs.fx) {
3691                             att = "x";
3692                             value = attrs.x;
3693                         } else {
3694                             break;
3695                         }
3696                     case "x":
3697                         if (attrs.fx) {
3698                             value = -attrs.x - (attrs.width || 0);
3699                         }
3700                     case "rx":
3701                         if (att == "rx" && o.type == "rect") {
3702                             break;
3703                         }
3704                     case "cx":
3705                         node.setAttribute(att, value);
3706                         o.pattern && updatePosition(o);
3707                         o._.dirty = 1;
3708                         break;
3709                     case "height":
3710                         node.setAttribute(att, value);
3711                         o._.dirty = 1;
3712                         if (attrs.fy) {
3713                             att = "y";
3714                             value = attrs.y;
3715                         } else {
3716                             break;
3717                         }
3718                     case "y":
3719                         if (attrs.fy) {
3720                             value = -attrs.y - (attrs.height || 0);
3721                         }
3722                     case "ry":
3723                         if (att == "ry" && o.type == "rect") {
3724                             break;
3725                         }
3726                     case "cy":
3727                         node.setAttribute(att, value);
3728                         o.pattern && updatePosition(o);
3729                         o._.dirty = 1;
3730                         break;
3731                     case "r":
3732                         if (o.type == "rect") {
3733                             $(node, {rx: value, ry: value});
3734                         } else {
3735                             node.setAttribute(att, value);
3736                         }
3737                         o._.dirty = 1;
3738                         break;
3739                     case "src":
3740                         if (o.type == "image") {
3741                             node.setAttributeNS(xlink, "href", value);
3742                         }
3743                         break;
3744                     case "stroke-width":
3745                         if (o._.sx != 1 || o._.sy != 1) {
3746                             value /= mmax(abs(o._.sx), abs(o._.sy)) || 1;
3747                         }
3748                         if (o.paper._vbSize) {
3749                             value *= o.paper._vbSize;
3750                         }
3751                         node.setAttribute(att, value);
3752                         if (attrs["stroke-dasharray"]) {
3753                             addDashes(o, attrs["stroke-dasharray"], params);
3754                         }
3755                         if (o._.arrows) {
3756                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3757                             "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3758                         }
3759                         break;
3760                     case "stroke-dasharray":
3761                         addDashes(o, value, params);
3762                         break;
3763                     case "fill":
3764                         var isURL = Str(value).match(R._ISURL);
3765                         if (isURL) {
3766                             el = $("pattern");
3767                             var ig = $("image");
3768                             el.id = R._createUUID();
3769                             $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1});
3770                             $(ig, {x: 0, y: 0, "xlink:href": isURL[1]});
3771                             el.appendChild(ig);
3772
3773                             (function (el) {
3774                                 R._preload(isURL[1], function () {
3775                                     var w = this.offsetWidth,
3776                                         h = this.offsetHeight;
3777                                     $(el, {width: w, height: h});
3778                                     $(ig, {width: w, height: h});
3779                                     o.paper.safari();
3780                                 });
3781                             })(el);
3782                             o.paper.defs.appendChild(el);
3783                             node.style.fill = "url(#" + el.id + ")";
3784                             $(node, {fill: "url(#" + el.id + ")"});
3785                             o.pattern = el;
3786                             o.pattern && updatePosition(o);
3787                             break;
3788                         }
3789                         var clr = R.getRGB(value);
3790                         if (!clr.error) {
3791                             delete params.gradient;
3792                             delete attrs.gradient;
3793                             !R.is(attrs.opacity, "undefined") &&
3794                                 R.is(params.opacity, "undefined") &&
3795                                 $(node, {opacity: attrs.opacity});
3796                             !R.is(attrs["fill-opacity"], "undefined") &&
3797                                 R.is(params["fill-opacity"], "undefined") &&
3798                                 $(node, {"fill-opacity": attrs["fill-opacity"]});
3799                         } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) {
3800                             if ("opacity" in attrs || "fill-opacity" in attrs) {
3801                                 var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
3802                                 if (gradient) {
3803                                     var stops = gradient.getElementsByTagName("stop");
3804                                     $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)});
3805                                 }
3806                             }
3807                             attrs.gradient = value;
3808                             attrs.fill = "none";
3809                             break;
3810                         }
3811                         clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
3812                     case "stroke":
3813                         clr = R.getRGB(value);
3814                         node.setAttribute(att, clr.hex);
3815                         att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
3816                         if (att == "stroke" && o._.arrows) {
3817                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3818                             "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3819                         }
3820                         break;
3821                     case "gradient":
3822                         (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value);
3823                         break;
3824                     case "opacity":
3825                         if (attrs.gradient && !attrs[has]("stroke-opacity")) {
3826                             $(node, {"stroke-opacity": value > 1 ? value / 100 : value});
3827                         }
3828                         // fall
3829                     case "fill-opacity":
3830                         if (attrs.gradient) {
3831                             gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
3832                             if (gradient) {
3833                                 stops = gradient.getElementsByTagName("stop");
3834                                 $(stops[stops.length - 1], {"stop-opacity": value});
3835                             }
3836                             break;
3837                         }
3838                     default:
3839                         att == "font-size" && (value = toInt(value, 10) + "px");
3840                         var cssrule = att.replace(/(\-.)/g, function (w) {
3841                             return w.substring(1).toUpperCase();
3842                         });
3843                         node.style[cssrule] = value;
3844                         o._.dirty = 1;
3845                         node.setAttribute(att, value);
3846                         break;
3847                 }
3848             }
3849         }
3850
3851         tuneText(o, params);
3852         node.style.visibility = vis;
3853     },
3854     leading = 1.2,
3855     tuneText = function (el, params) {
3856         if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) {
3857             return;
3858         }
3859         var a = el.attrs,
3860             node = el.node,
3861             fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10;
3862
3863         if (params[has]("text")) {
3864             a.text = params.text;
3865             while (node.firstChild) {
3866                 node.removeChild(node.firstChild);
3867             }
3868             var texts = Str(params.text).split("\n"),
3869                 tspans = [],
3870                 tspan;
3871             for (var i = 0, ii = texts.length; i < ii; i++) {
3872                 tspan = $("tspan");
3873                 i && $(tspan, {dy: fontSize * leading, x: a.x});
3874                 tspan.appendChild(R._g.doc.createTextNode(texts[i]));
3875                 node.appendChild(tspan);
3876                 tspans[i] = tspan;
3877             }
3878         } else {
3879             tspans = node.getElementsByTagName("tspan");
3880             for (i = 0, ii = tspans.length; i < ii; i++) if (i) {
3881                 $(tspans[i], {dy: fontSize * leading, x: a.x});
3882             } else {
3883                 $(tspans[0], {dy: 0});
3884             }
3885         }
3886         $(node, {x: a.x, y: a.y});
3887         el._.dirty = 1;
3888         var bb = el._getBBox(),
3889             dif = a.y - (bb.y + bb.height / 2);
3890         dif && R.is(dif, "finite") && $(tspans[0], {dy: dif});
3891     },
3892     Element = function (node, svg) {
3893         var X = 0,
3894             Y = 0;
3895         
3896         this[0] = this.node = node;
3897         
3898         node.raphael = true;
3899         
3900         this.id = R._oid++;
3901         node.raphaelid = this.id;
3902         this.matrix = R.matrix();
3903         this.realPath = null;
3904         
3905         this.paper = svg;
3906         this.attrs = this.attrs || {};
3907         this._ = {
3908             transform: [],
3909             sx: 1,
3910             sy: 1,
3911             deg: 0,
3912             dx: 0,
3913             dy: 0,
3914             dirty: 1
3915         };
3916         !svg.bottom && (svg.bottom = this);
3917         
3918         this.prev = svg.top;
3919         svg.top && (svg.top.next = this);
3920         svg.top = this;
3921         
3922         this.next = null;
3923     },
3924     elproto = R.el;
3925
3926     Element.prototype = elproto;
3927     elproto.constructor = Element;
3928
3929     R._engine.path = function (pathString, SVG) {
3930         var el = $("path");
3931         SVG.canvas && SVG.canvas.appendChild(el);
3932         var p = new Element(el, SVG);
3933         p.type = "path";
3934         setFillAndStroke(p, {
3935             fill: "none",
3936             stroke: "#000",
3937             path: pathString
3938         });
3939         return p;
3940     };
3941     
3942     elproto.rotate = function (deg, cx, cy) {
3943         if (this.removed) {
3944             return this;
3945         }
3946         deg = Str(deg).split(separator);
3947         if (deg.length - 1) {
3948             cx = toFloat(deg[1]);
3949             cy = toFloat(deg[2]);
3950         }
3951         deg = toFloat(deg[0]);
3952         (cy == null) && (cx = cy);
3953         if (cx == null || cy == null) {
3954             var bbox = this.getBBox(1);
3955             cx = bbox.x + bbox.width / 2;
3956             cy = bbox.y + bbox.height / 2;
3957         }
3958         this.transform(this._.transform.concat([["r", deg, cx, cy]]));
3959         return this;
3960     };
3961     
3962     elproto.scale = function (sx, sy, cx, cy) {
3963         if (this.removed) {
3964             return this;
3965         }
3966         sx = Str(sx).split(separator);
3967         if (sx.length - 1) {
3968             sy = toFloat(sx[1]);
3969             cx = toFloat(sx[2]);
3970             cy = toFloat(sx[3]);
3971         }
3972         sx = toFloat(sx[0]);
3973         (sy == null) && (sy = sx);
3974         (cy == null) && (cx = cy);
3975         if (cx == null || cy == null) {
3976             var bbox = this.getBBox(1);
3977         }
3978         cx = cx == null ? bbox.x + bbox.width / 2 : cx;
3979         cy = cy == null ? bbox.y + bbox.height / 2 : cy;
3980         this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
3981         return this;
3982     };
3983     
3984     elproto.translate = function (dx, dy) {
3985         if (this.removed) {
3986             return this;
3987         }
3988         dx = Str(dx).split(separator);
3989         if (dx.length - 1) {
3990             dy = toFloat(dx[1]);
3991         }
3992         dx = toFloat(dx[0]) || 0;
3993         dy = +dy || 0;
3994         this.transform(this._.transform.concat([["t", dx, dy]]));
3995         return this;
3996     };
3997     
3998     elproto.transform = function (tstr) {
3999         var _ = this._;
4000         if (tstr == null) {
4001             return _.transform;
4002         }
4003         R._extractTransform(this, tstr);
4004
4005         this.clip && $(this.clip, {transform: this.matrix.invert()});
4006         this.pattern && updatePosition(this);
4007         this.node && $(this.node, {transform: this.matrix});
4008     
4009         if (_.sx != 1 || _.sy != 1) {
4010             var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1;
4011             this.attr({"stroke-width": sw});
4012         }
4013
4014         return this;
4015     };
4016     
4017     elproto.hide = function () {
4018         !this.removed && this.paper.safari(this.node.style.display = "none");
4019         return this;
4020     };
4021     
4022     elproto.show = function () {
4023         !this.removed && this.paper.safari(this.node.style.display = "");
4024         return this;
4025     };
4026     
4027     elproto.remove = function () {
4028         if (this.removed) {
4029             return;
4030         }
4031         eve.unbind("*.*." + this.id);
4032         R._tear(this, this.paper);
4033         this.node.parentNode.removeChild(this.node);
4034         for (var i in this) {
4035             delete this[i];
4036         }
4037         this.removed = true;
4038     };
4039     elproto._getBBox = function () {
4040         if (this.node.style.display == "none") {
4041             this.show();
4042             var hide = true;
4043         }
4044         var bbox = {};
4045         try {
4046             bbox = this.node.getBBox();
4047         } catch(e) {
4048             // Firefox 3.0.x plays badly here
4049         } finally {
4050             bbox = bbox || {};
4051         }
4052         hide && this.hide();
4053         return bbox;
4054     };
4055     
4056     elproto.attr = function (name, value) {
4057         if (this.removed) {
4058             return this;
4059         }
4060         if (name == null) {
4061             var res = {};
4062             for (var a in this.attrs) if (this.attrs[has](a)) {
4063                 res[a] = this.attrs[a];
4064             }
4065             res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
4066             res.transform = this._.transform;
4067             return res;
4068         }
4069         if (value == null && R.is(name, "string")) {
4070             if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) {
4071                 return this.attrs.gradient;
4072             }
4073             if (name == "transform") {
4074                 return this._.transform;
4075             }
4076             var names = name.split(separator),
4077                 out = {};
4078             for (var i = 0, ii = names.length; i < ii; i++) {
4079                 name = names[i];
4080                 if (name in this.attrs) {
4081                     out[name] = this.attrs[name];
4082                 } else if (R.is(this.paper.customAttributes[name], "function")) {
4083                     out[name] = this.paper.customAttributes[name].def;
4084                 } else {
4085                     out[name] = R._availableAttrs[name];
4086                 }
4087             }
4088             return ii - 1 ? out : out[names[0]];
4089         }
4090         if (value == null && R.is(name, "array")) {
4091             out = {};
4092             for (i = 0, ii = name.length; i < ii; i++) {
4093                 out[name[i]] = this.attr(name[i]);
4094             }
4095             return out;
4096         }
4097         if (value != null) {
4098             var params = {};
4099             params[name] = value;
4100         } else if (name != null && R.is(name, "object")) {
4101             params = name;
4102         }
4103         for (var key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
4104             var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
4105             this.attrs[key] = params[key];
4106             for (var subkey in par) if (par[has](subkey)) {
4107                 params[subkey] = par[subkey];
4108             }
4109         }
4110         setFillAndStroke(this, params);
4111         return this;
4112     };
4113     
4114     elproto.toFront = function () {
4115         if (this.removed) {
4116             return this;
4117         }
4118         this.node.parentNode.appendChild(this.node);
4119         var svg = this.paper;
4120         svg.top != this && R._tofront(this, svg);
4121         return this;
4122     };
4123     
4124     elproto.toBack = function () {
4125         if (this.removed) {
4126             return this;
4127         }
4128         if (this.node.parentNode.firstChild != this.node) {
4129             this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
4130             R._toback(this, this.paper);
4131             var svg = this.paper;
4132         }
4133         return this;
4134     };
4135     
4136     elproto.insertAfter = function (element) {
4137         if (this.removed) {
4138             return this;
4139         }
4140         var node = element.node || element[element.length - 1].node;
4141         if (node.nextSibling) {
4142             node.parentNode.insertBefore(this.node, node.nextSibling);
4143         } else {
4144             node.parentNode.appendChild(this.node);
4145         }
4146         R._insertafter(this, element, this.paper);
4147         return this;
4148     };
4149     
4150     elproto.insertBefore = function (element) {
4151         if (this.removed) {
4152             return this;
4153         }
4154         var node = element.node || element[0].node;
4155         node.parentNode.insertBefore(this.node, node);
4156         R._insertbefore(this, element, this.paper);
4157         return this;
4158     };
4159     elproto.blur = function (size) {
4160         // Experimental. No Safari support. Use it on your own risk.
4161         var t = this;
4162         if (+size !== 0) {
4163             var fltr = $("filter"),
4164                 blur = $("feGaussianBlur");
4165             t.attrs.blur = size;
4166             fltr.id = R._createUUID();
4167             $(blur, {stdDeviation: +size || 1.5});
4168             fltr.appendChild(blur);
4169             t.paper.defs.appendChild(fltr);
4170             t._blur = fltr;
4171             $(t.node, {filter: "url(#" + fltr.id + ")"});
4172         } else {
4173             if (t._blur) {
4174                 t._blur.parentNode.removeChild(t._blur);
4175                 delete t._blur;
4176                 delete t.attrs.blur;
4177             }
4178             t.node.removeAttribute("filter");
4179         }
4180     };
4181     R._engine.circle = function (svg, x, y, r) {
4182         var el = $("circle");
4183         svg.canvas && svg.canvas.appendChild(el);
4184         var res = new Element(el, svg);
4185         res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"};
4186         res.type = "circle";
4187         $(el, res.attrs);
4188         return res;
4189     };
4190     R._engine.rect = function (svg, x, y, w, h, r) {
4191         var el = $("rect");
4192         svg.canvas && svg.canvas.appendChild(el);
4193         var res = new Element(el, svg);
4194         res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"};
4195         res.type = "rect";
4196         $(el, res.attrs);
4197         return res;
4198     };
4199     R._engine.ellipse = function (svg, x, y, rx, ry) {
4200         var el = $("ellipse");
4201         svg.canvas && svg.canvas.appendChild(el);
4202         var res = new Element(el, svg);
4203         res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"};
4204         res.type = "ellipse";
4205         $(el, res.attrs);
4206         return res;
4207     };
4208     R._engine.image = function (svg, src, x, y, w, h) {
4209         var el = $("image");
4210         $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"});
4211         el.setAttributeNS(xlink, "href", src);
4212         svg.canvas && svg.canvas.appendChild(el);
4213         var res = new Element(el, svg);
4214         res.attrs = {x: x, y: y, width: w, height: h, src: src};
4215         res.type = "image";
4216         return res;
4217     };
4218     R._engine.text = function (svg, x, y, text) {
4219         var el = $("text");
4220         // $(el, {x: x, y: y, "text-anchor": "middle"});
4221         svg.canvas && svg.canvas.appendChild(el);
4222         var res = new Element(el, svg);
4223         res.attrs = {
4224             x: x,
4225             y: y,
4226             "text-anchor": "middle",
4227             text: text,
4228             font: R._availableAttrs.font,
4229             stroke: "none",
4230             fill: "#000"
4231         };
4232         res.type = "text";
4233         setFillAndStroke(res, res.attrs);
4234         return res;
4235     };
4236     R._engine.setSize = function (width, height) {
4237         this.width = width || this.width;
4238         this.height = height || this.height;
4239         this.canvas.setAttribute("width", this.width);
4240         this.canvas.setAttribute("height", this.height);
4241         if (this._viewBox) {
4242             this.setViewBox.apply(this, this._viewBox);
4243         }
4244         return this;
4245     };
4246     R._engine.create = function () {
4247         var con = R._getContainer.apply(0, arguments),
4248             container = con && con.container,
4249             x = con.x,
4250             y = con.y,
4251             width = con.width,
4252             height = con.height;
4253         if (!container) {
4254             throw new Error("SVG container not found.");
4255         }
4256         var cnvs = $("svg"),
4257             css = "overflow:hidden;",
4258             isFloating;
4259         x = x || 0;
4260         y = y || 0;
4261         width = width || 512;
4262         height = height || 342;
4263         $(cnvs, {
4264             height: height,
4265             version: 1.1,
4266             width: width,
4267             xmlns: "http://www.w3.org/2000/svg"
4268         });
4269         if (container == 1) {
4270             cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
4271             R._g.doc.body.appendChild(cnvs);
4272             isFloating = 1;
4273         } else {
4274             cnvs.style.cssText = css + "position:relative";
4275             if (container.firstChild) {
4276                 container.insertBefore(cnvs, container.firstChild);
4277             } else {
4278                 container.appendChild(cnvs);
4279             }
4280         }
4281         container = new R._Paper;
4282         container.width = width;
4283         container.height = height;
4284         container.canvas = cnvs;
4285         // plugins.call(container, container, R.fn);
4286         container.clear();
4287         container._left = container._top = 0;
4288         isFloating && (container.renderfix = function () {});
4289         container.renderfix();
4290         return container;
4291     };
4292     R._engine.setViewBox = function (x, y, w, h, fit) {
4293         eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]);
4294         var size = mmax(w / this.width, h / this.height),
4295             top = this.top,
4296             aspectRatio = fit ? "meet" : "xMinYMin",
4297             vb,
4298             sw;
4299         if (x == null) {
4300             if (this._vbSize) {
4301                 size = 1;
4302             }
4303             delete this._vbSize;
4304             vb = "0 0 " + this.width + S + this.height;
4305         } else {
4306             this._vbSize = size;
4307             vb = x + S + y + S + w + S + h;
4308         }
4309         $(this.canvas, {
4310             viewBox: vb,
4311             preserveAspectRatio: aspectRatio
4312         });
4313         while (size && top) {
4314             sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1;
4315             top.attr({"stroke-width": sw});
4316             top._.dirty = 1;
4317             top._.dirtyT = 1;
4318             top = top.prev;
4319         }
4320         this._viewBox = [x, y, w, h, !!fit];
4321         return this;
4322     };
4323     
4324     R.prototype.renderfix = function () {
4325         var cnvs = this.canvas,
4326             s = cnvs.style,
4327             pos = cnvs.getScreenCTM(),
4328             left = -pos.e % 1,
4329             top = -pos.f % 1;
4330         if (left || top) {
4331             if (left) {
4332                 this._left = (this._left + left) % 1;
4333                 s.left = this._left + "px";
4334             }
4335             if (top) {
4336                 this._top = (this._top + top) % 1;
4337                 s.top = this._top + "px";
4338             }
4339         }
4340     };
4341     
4342     R.prototype.clear = function () {
4343         R.eve("clear", this);
4344         var c = this.canvas;
4345         while (c.firstChild) {
4346             c.removeChild(c.firstChild);
4347         }
4348         this.bottom = this.top = null;
4349         (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version));
4350         c.appendChild(this.desc);
4351         c.appendChild(this.defs = $("defs"));
4352     };
4353     
4354     R.prototype.remove = function () {
4355         eve("remove", this);
4356         this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
4357         for (var i in this) {
4358             this[i] = removed(i);
4359         }
4360     };
4361     var setproto = R.st;
4362     for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
4363         setproto[method] = (function (methodname) {
4364             return function () {
4365                 var arg = arguments;
4366                 return this.forEach(function (el) {
4367                     el[methodname].apply(el, arg);
4368                 });
4369             };
4370         })(method);
4371     }
4372 }(window.Raphael);
4373
4374 // ┌─────────────────────────────────────────────────────────────────────┐ \\
4375 // │ Raphaël 2 - JavaScript Vector Library                               │ \\
4376 // ├─────────────────────────────────────────────────────────────────────┤ \\
4377 // │ VML Module                                                          │ \\
4378 // ├─────────────────────────────────────────────────────────────────────┤ \\
4379 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
4380 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
4381 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
4382 // └─────────────────────────────────────────────────────────────────────┘ \\
4383 window.Raphael.vml && function (R) {
4384     var has = "hasOwnProperty",
4385         Str = String,
4386         toFloat = parseFloat,
4387         math = Math,
4388         round = math.round,
4389         mmax = math.max,
4390         mmin = math.min,
4391         abs = math.abs,
4392         fillString = "fill",
4393         separator = /[, ]+/,
4394         eve = R.eve,
4395         S = " ",
4396         E = "";
4397     // VML
4398     var map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"},
4399         bites = /([clmz]),?([^clmz]*)/gi,
4400         blurregexp = / progid:\S+Blur\([^\)]+\)/g,
4401         val = /-?[^,\s-]+/g,
4402         cssDot = "position:absolute;left:0;top:0;width:1px;height:1px",
4403         zoom = 21600,
4404         pathTypes = {path: 1, rect: 1},
4405         ovalTypes = {circle: 1, ellipse: 1},
4406         path2vml = function (path) {
4407             var total =  /[ahqstv]/ig,
4408                 command = R._pathToAbsolute;
4409             Str(path).match(total) && (command = R._path2curve);
4410             total = /[clmz]/g;
4411             if (command == R._pathToAbsolute && !Str(path).match(total)) {
4412                 var res = Str(path).replace(bites, function (all, command, args) {
4413                     var vals = [],
4414                         isMove = command.toLowerCase() == "m",
4415                         res = map[command];
4416                     args.replace(val, function (value) {
4417                         if (isMove && vals.length == 2) {
4418                             res += vals + map[command == "m" ? "l" : "L"];
4419                             vals = [];
4420                         }
4421                         vals.push(round(value * zoom));
4422                     });
4423                     return res + vals;
4424                 });
4425                 return res;
4426             }
4427             var pa = command(path), p, r;
4428             res = [];
4429             for (var i = 0, ii = pa.length; i < ii; i++) {
4430                 p = pa[i];
4431                 r = pa[i][0].toLowerCase();
4432                 r == "z" && (r = "x");
4433                 for (var j = 1, jj = p.length; j < jj; j++) {
4434                     r += round(p[j] * zoom) + (j != jj - 1 ? "," : E);
4435                 }
4436                 res.push(r);
4437             }
4438             return res.join(S);
4439         },
4440         compensation = function (deg, dx, dy) {
4441             var m = R.matrix();
4442             m.rotate(-deg, .5, .5);
4443             return {
4444                 dx: m.x(dx, dy),
4445                 dy: m.y(dx, dy)
4446             };
4447         },
4448         setCoords = function (p, sx, sy, dx, dy, deg) {
4449             var _ = p._,
4450                 m = p.matrix,
4451                 fillpos = _.fillpos,
4452                 o = p.node,
4453                 s = o.style,
4454                 y = 1,
4455                 flip = "",
4456                 dxdy,
4457                 kx = zoom / sx,
4458                 ky = zoom / sy;
4459             s.visibility = "hidden";
4460             if (!sx || !sy) {
4461                 return;
4462             }
4463             o.coordsize = abs(kx) + S + abs(ky);
4464             s.rotation = deg * (sx * sy < 0 ? -1 : 1);
4465             if (deg) {
4466                 var c = compensation(deg, dx, dy);
4467                 dx = c.dx;
4468                 dy = c.dy;
4469             }
4470             sx < 0 && (flip += "x");
4471             sy < 0 && (flip += " y") && (y = -1);
4472             s.flip = flip;
4473             o.coordorigin = (dx * -kx) + S + (dy * -ky);
4474             if (fillpos || _.fillsize) {
4475                 var fill = o.getElementsByTagName(fillString);
4476                 fill = fill && fill[0];
4477                 o.removeChild(fill);
4478                 if (fillpos) {
4479                     c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1]));
4480                     fill.position = c.dx * y + S + c.dy * y;
4481                 }
4482                 if (_.fillsize) {
4483                     fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy);
4484                 }
4485                 o.appendChild(fill);
4486             }
4487             s.visibility = "visible";
4488         };
4489     R.toString = function () {
4490         return  "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version;
4491     };
4492     addArrow = function (o, value, isEnd) {
4493         var values = Str(value).toLowerCase().split("-"),
4494             se = isEnd ? "end" : "start",
4495             i = values.length,
4496             type = "classic",
4497             w = "medium",
4498             h = "medium";
4499         while (i--) {
4500             switch (values[i]) {
4501                 case "block":
4502                 case "classic":
4503                 case "oval":
4504                 case "diamond":
4505                 case "open":
4506                 case "none":
4507                     type = values[i];
4508                     break;
4509                 case "wide":
4510                 case "narrow": h = values[i]; break;
4511                 case "long":
4512                 case "short": w = values[i]; break;
4513             }
4514         }
4515         var stroke = o.node.getElementsByTagName("stroke")[0];
4516         stroke[se + "arrow"] = type;
4517         stroke[se + "arrowlength"] = w;
4518         stroke[se + "arrowwidth"] = h;
4519     };
4520     setFillAndStroke = function (o, params) {
4521         // o.paper.canvas.style.display = "none";
4522         o.attrs = o.attrs || {};
4523         var node = o.node,
4524             a = o.attrs,
4525             s = node.style,
4526             xy,
4527             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),
4528             isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry),
4529             res = o;
4530
4531
4532         for (var par in params) if (params[has](par)) {
4533             a[par] = params[par];
4534         }
4535         if (newpath) {
4536             a.path = R._getPath[o.type](o);
4537             o._.dirty = 1;
4538         }
4539         params.href && (node.href = params.href);
4540         params.title && (node.title = params.title);
4541         params.target && (node.target = params.target);
4542         params.cursor && (s.cursor = params.cursor);
4543         "blur" in params && o.blur(params.blur);
4544         "transform" in params && o.transform(params.transform);
4545         if (params.path && o.type == "path" || newpath) {
4546             node.path = path2vml(a.path);
4547         }
4548         if (isOval) {
4549             var cx = +a.cx,
4550                 cy = +a.cy,
4551                 rx = +a.rx || +a.r || 0,
4552                 ry = +a.ry || +a.r || 0;
4553             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));
4554         }
4555         if ("clip-rect" in params) {
4556             var rect = Str(params["clip-rect"]).split(separator);
4557             if (rect.length == 4) {
4558                 rect[2] = +rect[2] + (+rect[0]);
4559                 rect[3] = +rect[3] + (+rect[1]);
4560                 var div = node.clipRect || R._g.doc.createElement("div"),
4561                     dstyle = div.style,
4562                     group = node.parentNode;
4563                 dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect);
4564                 if (!node.clipRect) {
4565                     dstyle.position = "absolute";
4566                     dstyle.top = 0;
4567                     dstyle.left = 0;
4568                     dstyle.width = o.paper.width + "px";
4569                     dstyle.height = o.paper.height + "px";
4570                     group.parentNode.insertBefore(div, group);
4571                     div.appendChild(group);
4572                     node.clipRect = div;
4573                 }
4574             }
4575             if (!params["clip-rect"]) {
4576                 node.clipRect && (node.clipRect.style.clip = E);
4577             }
4578         }
4579         if (o.textpath) {
4580             var textpathStyle = o.textpath.style;
4581             params.font && (textpathStyle.font = params.font);
4582             params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"');
4583             params["font-size"] && (textpathStyle.fontSize = params["font-size"]);
4584             params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]);
4585             params["font-style"] && (textpathStyle.fontStyle = params["font-style"]);
4586         }
4587         if ("arrow-start" in params) {
4588             addArrow(res, params["arrow-start"]);
4589         }
4590         if ("arrow-end" in params) {
4591             addArrow(res, params["arrow-end"], 1);
4592         }
4593         if (params.opacity != null || 
4594             params["stroke-width"] != null ||
4595             params.fill != null ||
4596             params.src != null ||
4597             params.stroke != null ||
4598             params["stroke-width"] != null ||
4599             params["stroke-opacity"] != null ||
4600             params["fill-opacity"] != null ||
4601             params["stroke-dasharray"] != null ||
4602             params["stroke-miterlimit"] != null ||
4603             params["stroke-linejoin"] != null ||
4604             params["stroke-linecap"] != null) {
4605             var fill = node.getElementsByTagName(fillString),
4606                 newfill = false;
4607             fill = fill && fill[0];
4608             !fill && (newfill = fill = createNode(fillString));
4609             if (o.type == "image" && params.src) {
4610                 fill.src = params.src;
4611             }
4612             params.fill && (fill.on = true);
4613             if (fill.on == null || params.fill == "none" || params.fill === null) {
4614                 fill.on = false;
4615             }
4616             if (fill.on && params.fill) {
4617                 var isURL = Str(params.fill).match(R._ISURL);
4618                 if (isURL) {
4619                     fill.parentNode == node && node.removeChild(fill);
4620                     fill.rotate = true;
4621                     fill.src = isURL[1];
4622                     fill.type = "tile";
4623                     var bbox = o.getBBox(1);
4624                     fill.position = bbox.x + S + bbox.y;
4625                     o._.fillpos = [bbox.x, bbox.y];
4626
4627                     R._preload(isURL[1], function () {
4628                         o._.fillsize = [this.offsetWidth, this.offsetHeight];
4629                     });
4630                 } else {
4631                     fill.color = R.getRGB(params.fill).hex;
4632                     fill.src = E;
4633                     fill.type = "solid";
4634                     if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) {
4635                         a.fill = "none";
4636                         a.gradient = params.fill;
4637                         fill.rotate = false;
4638                     }
4639                 }
4640             }
4641             if ("fill-opacity" in params || "opacity" in params) {
4642                 var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1);
4643                 opacity = mmin(mmax(opacity, 0), 1);
4644                 fill.opacity = opacity;
4645                 if (fill.src) {
4646                     fill.color = "none";
4647                 }
4648             }
4649             node.appendChild(fill);
4650             var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]),
4651             newstroke = false;
4652             !stroke && (newstroke = stroke = createNode("stroke"));
4653             if ((params.stroke && params.stroke != "none") ||
4654                 params["stroke-width"] ||
4655                 params["stroke-opacity"] != null ||
4656                 params["stroke-dasharray"] ||
4657                 params["stroke-miterlimit"] ||
4658                 params["stroke-linejoin"] ||
4659                 params["stroke-linecap"]) {
4660                 stroke.on = true;
4661             }
4662             (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false);
4663             var strokeColor = R.getRGB(params.stroke);
4664             stroke.on && params.stroke && (stroke.color = strokeColor.hex);
4665             opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1);
4666             var width = (toFloat(params["stroke-width"]) || 1) * .75;
4667             opacity = mmin(mmax(opacity, 0), 1);
4668             params["stroke-width"] == null && (width = a["stroke-width"]);
4669             params["stroke-width"] && (stroke.weight = width);
4670             width && width < 1 && (opacity *= width) && (stroke.weight = 1);
4671             stroke.opacity = opacity;
4672         
4673             params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter");
4674             stroke.miterlimit = params["stroke-miterlimit"] || 8;
4675             params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round");
4676             if (params["stroke-dasharray"]) {
4677                 var dasharray = {
4678                     "-": "shortdash",
4679                     ".": "shortdot",
4680                     "-.": "shortdashdot",
4681                     "-..": "shortdashdotdot",
4682                     ". ": "dot",
4683                     "- ": "dash",
4684                     "--": "longdash",
4685                     "- .": "dashdot",
4686                     "--.": "longdashdot",
4687                     "--..": "longdashdotdot"
4688                 };
4689                 stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E;
4690             }
4691             newstroke && node.appendChild(stroke);
4692         }
4693         if (res.type == "text") {
4694             res.paper.canvas.style.display = E;
4695             var span = res.paper.span,
4696                 m = 100,
4697                 fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/);
4698             s = span.style;
4699             a.font && (s.font = a.font);
4700             a["font-family"] && (s.fontFamily = a["font-family"]);
4701             a["font-weight"] && (s.fontWeight = a["font-weight"]);
4702             a["font-style"] && (s.fontStyle = a["font-style"]);
4703             fontSize = toFloat(fontSize ? fontSize[0] : a["font-size"]);
4704             s.fontSize = fontSize * m + "px";
4705             res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/</g, "&#60;").replace(/&/g, "&#38;").replace(/\n/g, "<br>"));
4706             var brect = span.getBoundingClientRect();
4707             res.W = a.w = (brect.right - brect.left) / m;
4708             res.H = a.h = (brect.bottom - brect.top) / m;
4709             // res.paper.canvas.style.display = "none";
4710             res.X = a.x;
4711             res.Y = a.y + res.H / 2;
4712
4713             ("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));
4714             var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"];
4715             for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) {
4716                 res._.dirty = 1;
4717                 break;
4718             }
4719         
4720             // text-anchor emulation
4721             switch (a["text-anchor"]) {
4722                 case "start":
4723                     res.textpath.style["v-text-align"] = "left";
4724                     res.bbx = res.W / 2;
4725                 break;
4726                 case "end":
4727                     res.textpath.style["v-text-align"] = "right";
4728                     res.bbx = -res.W / 2;
4729                 break;
4730                 default:
4731                     res.textpath.style["v-text-align"] = "center";
4732                     res.bbx = 0;
4733                 break;
4734             }
4735             res.textpath.style["v-text-kern"] = true;
4736         }
4737         // res.paper.canvas.style.display = E;
4738     };
4739     addGradientFill = function (o, gradient, fill) {
4740         o.attrs = o.attrs || {};
4741         var attrs = o.attrs,
4742             opacity,
4743             oindex,
4744             type = "linear",
4745             fxfy = ".5 .5";
4746         o.attrs.gradient = gradient;
4747         gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) {
4748             type = "radial";
4749             if (fx && fy) {
4750                 fx = toFloat(fx);
4751                 fy = toFloat(fy);
4752                 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5);
4753                 fxfy = fx + S + fy;
4754             }
4755             return E;
4756         });
4757         gradient = gradient.split(/\s*\-\s*/);
4758         if (type == "linear") {
4759             var angle = gradient.shift();
4760             angle = -toFloat(angle);
4761             if (isNaN(angle)) {
4762                 return null;
4763             }
4764         }
4765         var dots = R._parseDots(gradient);
4766         if (!dots) {
4767             return null;
4768         }
4769         o = o.shape || o.node;
4770         if (dots.length) {
4771             o.removeChild(fill);
4772             fill.on = true;
4773             fill.method = "none";
4774             fill.color = dots[0].color;
4775             fill.color2 = dots[dots.length - 1].color;
4776             var clrs = [];
4777             for (var i = 0, ii = dots.length; i < ii; i++) {
4778                 dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color);
4779             }
4780             fill.colors = clrs.length ? clrs.join() : "0% " + fill.color;
4781             if (type == "radial") {
4782                 fill.type = "gradientTitle";
4783                 fill.focus = "100%";
4784                 fill.focussize = "0 0";
4785                 fill.focusposition = fxfy;
4786                 fill.angle = 0;
4787             } else {
4788                 // fill.rotate= true;
4789                 fill.type = "gradient";
4790                 fill.angle = (270 - angle) % 360;
4791             }
4792             o.appendChild(fill);
4793         }
4794         return 1;
4795     };
4796     Element = function (node, vml) {
4797         this[0] = this.node = node;
4798         node.raphael = true;
4799         this.id = R._oid++;
4800         node.raphaelid = this.id;
4801         this.X = 0;
4802         this.Y = 0;
4803         this.attrs = {};
4804         this.paper = vml;
4805         this.matrix = R.matrix();
4806         this._ = {
4807             transform: [],
4808             sx: 1,
4809             sy: 1,
4810             dx: 0,
4811             dy: 0,
4812             deg: 0,
4813             dirty: 1,
4814             dirtyT: 1
4815         };
4816         !vml.bottom && (vml.bottom = this);
4817         this.prev = vml.top;
4818         vml.top && (vml.top.next = this);
4819         vml.top = this;
4820         this.next = null;
4821     };
4822     var elproto = R.el;
4823
4824     Element.prototype = elproto;
4825     elproto.constructor = Element;
4826     elproto.transform = function (tstr) {
4827         if (tstr == null) {
4828             return this._.transform;
4829         }
4830         var vbs = this.paper._viewBoxShift,
4831             vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E,
4832             oldt;
4833         if (vbs) {
4834             oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E);
4835         }
4836         R._extractTransform(this, vbt + tstr);
4837         var matrix = this.matrix.clone(),
4838             skew = this.skew,
4839             o = this.node,
4840             split,
4841             isGrad = ~Str(this.attrs.fill).indexOf("-"),
4842             isPatt = !Str(this.attrs.fill).indexOf("url(");
4843         matrix.translate(-.5, -.5);
4844         if (isPatt || isGrad || this.type == "image") {
4845             skew.matrix = "1 0 0 1";
4846             skew.offset = "0 0";
4847             split = matrix.split();
4848             if ((isGrad && split.noRotation) || !split.isSimple) {
4849                 o.style.filter = matrix.toFilter();
4850                 var bb = this.getBBox(),
4851                     bbt = this.getBBox(1),
4852                     dx = bb.x - bbt.x,
4853                     dy = bb.y - bbt.y;
4854                 o.coordorigin = (dx * -zoom) + S + (dy * -zoom);
4855                 setCoords(this, 1, 1, dx, dy, 0);
4856             } else {
4857                 o.style.filter = E;
4858                 setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate);
4859             }
4860         } else {
4861             o.style.filter = E;
4862             skew.matrix = Str(matrix);
4863             skew.offset = matrix.offset();
4864         }
4865         oldt && (this._.transform = oldt);
4866         return this;
4867     };
4868     elproto.rotate = function (deg, cx, cy) {
4869         if (this.removed) {
4870             return this;
4871         }
4872         if (deg == null) {
4873             return;
4874         }
4875         deg = Str(deg).split(separator);
4876         if (deg.length - 1) {
4877             cx = toFloat(deg[1]);
4878             cy = toFloat(deg[2]);
4879         }
4880         deg = toFloat(deg[0]);
4881         (cy == null) && (cx = cy);
4882         if (cx == null || cy == null) {
4883             var bbox = this.getBBox(1);
4884             cx = bbox.x + bbox.width / 2;
4885             cy = bbox.y + bbox.height / 2;
4886         }
4887         this._.dirtyT = 1;
4888         this.transform(this._.transform.concat([["r", deg, cx, cy]]));
4889         return this;
4890     };
4891     elproto.translate = function (dx, dy) {
4892         if (this.removed) {
4893             return this;
4894         }
4895         dx = Str(dx).split(separator);
4896         if (dx.length - 1) {
4897             dy = toFloat(dx[1]);
4898         }
4899         dx = toFloat(dx[0]) || 0;
4900         dy = +dy || 0;
4901         if (this._.bbox) {
4902             this._.bbox.x += dx;
4903             this._.bbox.y += dy;
4904         }
4905         this.transform(this._.transform.concat([["t", dx, dy]]));
4906         return this;
4907     };
4908     elproto.scale = function (sx, sy, cx, cy) {
4909         if (this.removed) {
4910             return this;
4911         }
4912         sx = Str(sx).split(separator);
4913         if (sx.length - 1) {
4914             sy = toFloat(sx[1]);
4915             cx = toFloat(sx[2]);
4916             cy = toFloat(sx[3]);
4917             isNaN(cx) && (cx = null);
4918             isNaN(cy) && (cy = null);
4919         }
4920         sx = toFloat(sx[0]);
4921         (sy == null) && (sy = sx);
4922         (cy == null) && (cx = cy);
4923         if (cx == null || cy == null) {
4924             var bbox = this.getBBox(1);
4925         }
4926         cx = cx == null ? bbox.x + bbox.width / 2 : cx;
4927         cy = cy == null ? bbox.y + bbox.height / 2 : cy;
4928     
4929         this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
4930         this._.dirtyT = 1;
4931         return this;
4932     };
4933     elproto.hide = function () {
4934         !this.removed && (this.node.style.display = "none");
4935         return this;
4936     };
4937     elproto.show = function () {
4938         !this.removed && (this.node.style.display = E);
4939         return this;
4940     };
4941     elproto._getBBox = function () {
4942         if (this.removed) {
4943             return {};
4944         }
4945         if (this.type == "text") {
4946             return {
4947                 x: this.X + (this.bbx || 0) - this.W / 2,
4948                 y: this.Y - this.H,
4949                 width: this.W,
4950                 height: this.H
4951             };
4952         } else {
4953             return pathDimensions(this.attrs.path);
4954         }
4955     };
4956     elproto.remove = function () {
4957         if (this.removed) {
4958             return;
4959         }
4960         R.eve.unbind("*.*." + this.id);
4961         R._tear(this, this.paper);
4962         this.node.parentNode.removeChild(this.node);
4963         this.shape && this.shape.parentNode.removeChild(this.shape);
4964         for (var i in this) {
4965             delete this[i];
4966         }
4967         this.removed = true;
4968     };
4969     elproto.attr = function (name, value) {
4970         if (this.removed) {
4971             return this;
4972         }
4973         if (name == null) {
4974             var res = {};
4975             for (var a in this.attrs) if (this.attrs[has](a)) {
4976                 res[a] = this.attrs[a];
4977             }
4978             res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
4979             res.transform = this._.transform;
4980             return res;
4981         }
4982         if (value == null && R.is(name, "string")) {
4983             if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) {
4984                 return this.attrs.gradient;
4985             }
4986             var names = name.split(separator),
4987                 out = {};
4988             for (var i = 0, ii = names.length; i < ii; i++) {
4989                 name = names[i];
4990                 if (name in this.attrs) {
4991                     out[name] = this.attrs[name];
4992                 } else if (R.is(this.paper.customAttributes[name], "function")) {
4993                     out[name] = this.paper.customAttributes[name].def;
4994                 } else {
4995                     out[name] = R._availableAttrs[name];
4996                 }
4997             }
4998             return ii - 1 ? out : out[names[0]];
4999         }
5000         if (this.attrs && value == null && R.is(name, "array")) {
5001             out = {};
5002             for (i = 0, ii = name.length; i < ii; i++) {
5003                 out[name[i]] = this.attr(name[i]);
5004             }
5005             return out;
5006         }
5007         var params;
5008         if (value != null) {
5009             params = {};
5010             params[name] = value;
5011         }
5012         value == null && R.is(name, "object") && (params = name);
5013         for (var key in params) {
5014             R.eve("attr." + key + "." + this.id, this, params[key]);
5015         }
5016         if (params) {
5017             for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
5018                 var par = this.paper.customAttributes[key].apply(this, [][concat](params[key]));
5019                 this.attrs[key] = params[key];
5020                 for (var subkey in par) if (par[has](subkey)) {
5021                     params[subkey] = par[subkey];
5022                 }
5023             }
5024             // this.paper.canvas.style.display = "none";
5025             if (params.text && this.type == "text") {
5026                 this.textpath.string = params.text;
5027             }
5028             setFillAndStroke(this, params);
5029             // this.paper.canvas.style.display = E;
5030         }
5031         return this;
5032     };
5033     elproto.toFront = function () {
5034         !this.removed && this.node.parentNode.appendChild(this.node);
5035         this.paper && this.paper.top != this && R._tofront(this, this.paper);
5036         return this;
5037     };
5038     elproto.toBack = function () {
5039         if (this.removed) {
5040             return this;
5041         }
5042         if (this.node.parentNode.firstChild != this.node) {
5043             this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
5044             R._toback(this, this.paper);
5045         }
5046         return this;
5047     };
5048     elproto.insertAfter = function (element) {
5049         if (this.removed) {
5050             return this;
5051         }
5052         if (element.constructor == R.st.constructor) {
5053             element = element[element.length - 1];
5054         }
5055         if (element.node.nextSibling) {
5056             element.node.parentNode.insertBefore(this.node, element.node.nextSibling);
5057         } else {
5058             element.node.parentNode.appendChild(this.node);
5059         }
5060         R._insertafter(this, element, this.paper);
5061         return this;
5062     };
5063     elproto.insertBefore = function (element) {
5064         if (this.removed) {
5065             return this;
5066         }
5067         if (element.constructor == R.st.constructor) {
5068             element = element[0];
5069         }
5070         element.node.parentNode.insertBefore(this.node, element.node);
5071         R._insertbefore(this, element, this.paper);
5072         return this;
5073     };
5074     elproto.blur = function (size) {
5075         var s = this.node.runtimeStyle,
5076             f = s.filter;
5077         f = f.replace(blurregexp, E);
5078         if (+size !== 0) {
5079             this.attrs.blur = size;
5080             s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")";
5081             s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5));
5082         } else {
5083             s.filter = f;
5084             s.margin = 0;
5085             delete this.attrs.blur;
5086         }
5087     };
5088
5089     R._engine.path = function (pathString, vml) {
5090         var el = createNode("shape");
5091         el.style.cssText = cssDot;
5092         el.coordsize = zoom + S + zoom;
5093         el.coordorigin = vml.coordorigin;
5094         var p = new Element(el, vml),
5095             attr = {fill: "none", stroke: "#000"};
5096         pathString && (attr.path = pathString);
5097         p.type = "path";
5098         p.path = [];
5099         p.Path = E;
5100         setFillAndStroke(p, attr);
5101         vml.canvas.appendChild(el);
5102         var skew = createNode("skew");
5103         skew.on = true;
5104         el.appendChild(skew);
5105         p.skew = skew;
5106         p.transform(E);
5107         return p;
5108     };
5109     R._engine.rect = function (vml, x, y, w, h, r) {
5110         var path = R._rectPath(x, y, w, h, r),
5111             res = vml.path(path),
5112             a = res.attrs;
5113         res.X = a.x = x;
5114         res.Y = a.y = y;
5115         res.W = a.width = w;
5116         res.H = a.height = h;
5117         a.r = r;
5118         a.path = path;
5119         res.type = "rect";
5120         return res;
5121     };
5122     R._engine.ellipse = function (vml, x, y, rx, ry) {
5123         var res = vml.path(),
5124             a = res.attrs;
5125         res.X = x - rx;
5126         res.Y = y - ry;
5127         res.W = rx * 2;
5128         res.H = ry * 2;
5129         res.type = "ellipse";
5130         setFillAndStroke(res, {
5131             cx: x,
5132             cy: y,
5133             rx: rx,
5134             ry: ry
5135         });
5136         return res;
5137     };
5138     R._engine.circle = function (vml, x, y, r) {
5139         var res = vml.path(),
5140             a = res.attrs;
5141         res.X = x - r;
5142         res.Y = y - r;
5143         res.W = res.H = r * 2;
5144         res.type = "circle";
5145         setFillAndStroke(res, {
5146             cx: x,
5147             cy: y,
5148             r: r
5149         });
5150         return res;
5151     };
5152     R._engine.image = function (vml, src, x, y, w, h) {
5153         var path = R._rectPath(x, y, w, h),
5154             res = vml.path(path).attr({stroke: "none"}),
5155             a = res.attrs,
5156             node = res.node,
5157             fill = node.getElementsByTagName(fillString)[0];
5158         a.src = src;
5159         res.X = a.x = x;
5160         res.Y = a.y = y;
5161         res.W = a.width = w;
5162         res.H = a.height = h;
5163         a.path = path;
5164         res.type = "image";
5165         fill.parentNode == node && node.removeChild(fill);
5166         fill.rotate = true;
5167         fill.src = src;
5168         fill.type = "tile";
5169         res._.fillpos = [x, y];
5170         res._.fillsize = [w, h];
5171         node.appendChild(fill);
5172         setCoords(res, 1, 1, 0, 0, 0);
5173         return res;
5174     };
5175     R._engine.text = function (vml, x, y, text) {
5176         var el = createNode("shape"),
5177             path = createNode("path"),
5178             o = createNode("textpath");
5179         x = x || 0;
5180         y = y || 0;
5181         text = text || "";
5182         path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1);
5183         path.textpathok = true;
5184         o.string = Str(text);
5185         o.on = true;
5186         el.style.cssText = "position:absolute;left:0;top:0;width:1px;height:1px";
5187         el.coordsize = zoom + S + zoom;
5188         el.coordorigin = "0 0";
5189         var p = new Element(el, vml),
5190             attr = {
5191                 fill: "#000",
5192                 stroke: "none",
5193                 font: R._availableAttrs.font,
5194                 text: text
5195             };
5196         p.shape = el;
5197         p.path = path;
5198         p.textpath = o;
5199         p.type = "text";
5200         p.attrs.text = Str(text);
5201         p.attrs.x = x;
5202         p.attrs.y = y;
5203         p.attrs.w = 1;
5204         p.attrs.h = 1;
5205         setFillAndStroke(p, attr);
5206         el.appendChild(o);
5207         el.appendChild(path);
5208         vml.canvas.appendChild(el);
5209         var skew = createNode("skew");
5210         skew.on = true;
5211         el.appendChild(skew);
5212         p.skew = skew;
5213         p.transform(E);
5214         return p;
5215     };
5216     R._engine.setSize = function (width, height) {
5217         var cs = this.canvas.style;
5218         this.width = width;
5219         this.height = height;
5220         width == +width && (width += "px");
5221         height == +height && (height += "px");
5222         cs.width = width;
5223         cs.height = height;
5224         cs.clip = "rect(0 " + width + " " + height + " 0)";
5225         if (this._viewBox) {
5226             setViewBox.apply(this, this._viewBox);
5227         }
5228         return this;
5229     };
5230     R._engine.setViewBox = function (x, y, w, h, fit) {
5231         R.eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]);
5232         var width = this.width,
5233             height = this.height,
5234             size = 1 / mmax(w / width, h / height),
5235             H, W;
5236         if (fit) {
5237             H = height / h;
5238             W = width / w;
5239             if (w * H < width) {
5240                 x -= (width - w * H) / 2 / H;
5241             }
5242             if (h * W < height) {
5243                 y -= (height - h * W) / 2 / W;
5244             }
5245         }
5246         this._viewBox = [x, y, w, h, !!fit];
5247         this._viewBoxShift = {
5248             dx: -x,
5249             dy: -y,
5250             scale: size
5251         };
5252         this.forEach(function (el) {
5253             el.transform("...");
5254         });
5255         return this;
5256     };
5257     var createNode,
5258         initWin = function (win) {
5259             var doc = win.document;
5260             doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
5261             try {
5262                 !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
5263                 createNode = function (tagName) {
5264                     return doc.createElement('<rvml:' + tagName + ' class="rvml">');
5265                 };
5266             } catch (e) {
5267                 createNode = function (tagName) {
5268                     return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
5269                 };
5270             }
5271         };
5272     initWin(R._g.win);
5273     R._engine.create = function () {
5274         var con = R._getContainer.apply(0, arguments),
5275             container = con.container,
5276             height = con.height,
5277             s,
5278             width = con.width,
5279             x = con.x,
5280             y = con.y;
5281         if (!container) {
5282             throw new Error("VML container not found.");
5283         }
5284         var res = new R._Paper,
5285             c = res.canvas = R._g.doc.createElement("div"),
5286             cs = c.style;
5287         x = x || 0;
5288         y = y || 0;
5289         width = width || 512;
5290         height = height || 342;
5291         res.width = width;
5292         res.height = height;
5293         width == +width && (width += "px");
5294         height == +height && (height += "px");
5295         res.coordsize = zoom * 1e3 + S + zoom * 1e3;
5296         res.coordorigin = "0 0";
5297         res.span = R._g.doc.createElement("span");
5298         res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;";
5299         c.appendChild(res.span);
5300         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);
5301         if (container == 1) {
5302             R._g.doc.body.appendChild(c);
5303             cs.left = x + "px";
5304             cs.top = y + "px";
5305             cs.position = "absolute";
5306         } else {
5307             if (container.firstChild) {
5308                 container.insertBefore(c, container.firstChild);
5309             } else {
5310                 container.appendChild(c);
5311             }
5312         }
5313         // plugins.call(res, res, R.fn);
5314         res.renderfix = function () {};
5315         return res;
5316     };
5317     R.prototype.clear = function () {
5318         R.eve("clear", this);
5319         this.canvas.innerHTML = E;
5320         this.span = R._g.doc.createElement("span");
5321         this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";
5322         this.canvas.appendChild(this.span);
5323         this.bottom = this.top = null;
5324     };
5325     R.prototype.remove = function () {
5326         R.eve("remove", this);
5327         this.canvas.parentNode.removeChild(this.canvas);
5328         for (var i in this) {
5329             this[i] = removed(i);
5330         }
5331         return true;
5332     };
5333 }(window.Raphael);