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