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