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