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