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