2.0.1
[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 // ┌─────────────────────────────────────────────────────────────────────┐ \\
3399 // │ Raphaël - JavaScript Vector Library                                 │ \\
3400 // ├─────────────────────────────────────────────────────────────────────┤ \\
3401 // │ SVG Module                                                          │ \\
3402 // ├─────────────────────────────────────────────────────────────────────┤ \\
3403 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
3404 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
3405 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
3406 // └─────────────────────────────────────────────────────────────────────┘ \\
3407 window.Raphael.svg && function (R) {
3408     var has = "hasOwnProperty",
3409         Str = String,
3410         toFloat = parseFloat,
3411         toInt = parseInt,
3412         math = Math,
3413         mmax = math.max,
3414         abs = math.abs,
3415         pow = math.pow,
3416         separator = /[, ]+/,
3417         eve = R.eve,
3418         E = "",
3419         S = " ";
3420     var xlink = "http://www.w3.org/1999/xlink",
3421         markers = {
3422             block: "M5,0 0,2.5 5,5z",
3423             classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z",
3424             diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z",
3425             open: "M6,1 1,3.5 6,6",
3426             oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"
3427         },
3428         markerCounter = {};
3429     R.toString = function () {
3430         return  "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version;
3431     };
3432     var $ = function (el, attr) {
3433         if (attr) {
3434             if (typeof el == "string") {
3435                 el = $(el);
3436             }
3437             for (var key in attr) if (attr[has](key)) {
3438                 if (key.substring(0, 6) == "xlink:") {
3439                     el.setAttributeNS(xlink, key.substring(6), Str(attr[key]));
3440                 } else {
3441                     el.setAttribute(key, Str(attr[key]));
3442                 }
3443             }
3444         } else {
3445             el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el);
3446             el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)");
3447         }
3448         return el;
3449     },
3450     addGradientFill = function (element, gradient) {
3451         var type = "linear",
3452             id = element.id + gradient,
3453             fx = .5, fy = .5,
3454             o = element.node,
3455             SVG = element.paper,
3456             s = o.style,
3457             el = R._g.doc.getElementById(id);
3458         if (!el) {
3459             gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) {
3460                 type = "radial";
3461                 if (_fx && _fy) {
3462                     fx = toFloat(_fx);
3463                     fy = toFloat(_fy);
3464                     var dir = ((fy > .5) * 2 - 1);
3465                     pow(fx - .5, 2) + pow(fy - .5, 2) > .25 &&
3466                         (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) &&
3467                         fy != .5 &&
3468                         (fy = fy.toFixed(5) - 1e-5 * dir);
3469                 }
3470                 return E;
3471             });
3472             gradient = gradient.split(/\s*\-\s*/);
3473             if (type == "linear") {
3474                 var angle = gradient.shift();
3475                 angle = -toFloat(angle);
3476                 if (isNaN(angle)) {
3477                     return null;
3478                 }
3479                 var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))],
3480                     max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1);
3481                 vector[2] *= max;
3482                 vector[3] *= max;
3483                 if (vector[2] < 0) {
3484                     vector[0] = -vector[2];
3485                     vector[2] = 0;
3486                 }
3487                 if (vector[3] < 0) {
3488                     vector[1] = -vector[3];
3489                     vector[3] = 0;
3490                 }
3491             }
3492             var dots = R._parseDots(gradient);
3493             if (!dots) {
3494                 return null;
3495             }
3496             id = id.replace(/[\(\)\s,\xb0#]/g, "_");
3497             
3498             if (element.gradient && id != element.gradient.id) {
3499                 SVG.defs.removeChild(element.gradient);
3500                 delete element.gradient;
3501             }
3502
3503             if (!element.gradient) {
3504                 el = $(type + "Gradient", {id: id});
3505                 element.gradient = el;
3506                 $(el, type == "radial" ? {
3507                     fx: fx,
3508                     fy: fy
3509                 } : {
3510                     x1: vector[0],
3511                     y1: vector[1],
3512                     x2: vector[2],
3513                     y2: vector[3],
3514                     gradientTransform: element.matrix.invert()
3515                 });
3516                 SVG.defs.appendChild(el);
3517                 for (var i = 0, ii = dots.length; i < ii; i++) {
3518                     el.appendChild($("stop", {
3519                         offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
3520                         "stop-color": dots[i].color || "#fff"
3521                     }));
3522                 }
3523             }
3524         }
3525         $(o, {
3526             fill: "url(#" + id + ")",
3527             opacity: 1,
3528             "fill-opacity": 1
3529         });
3530         s.fill = E;
3531         s.opacity = 1;
3532         s.fillOpacity = 1;
3533         return 1;
3534     },
3535     updatePosition = function (o) {
3536         var bbox = o.getBBox(1);
3537         $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"});
3538     },
3539     addArrow = function (o, value, isEnd) {
3540         if (o.type == "path") {
3541             var values = Str(value).toLowerCase().split("-"),
3542                 p = o.paper,
3543                 se = isEnd ? "end" : "start",
3544                 node = o.node,
3545                 attrs = o.attrs,
3546                 stroke = attrs["stroke-width"],
3547                 i = values.length,
3548                 type = "classic",
3549                 from,
3550                 to,
3551                 dx,
3552                 refX,
3553                 attr,
3554                 w = 3,
3555                 h = 3,
3556                 t = 5;
3557             while (i--) {
3558                 switch (values[i]) {
3559                     case "block":
3560                     case "classic":
3561                     case "oval":
3562                     case "diamond":
3563                     case "open":
3564                     case "none":
3565                         type = values[i];
3566                         break;
3567                     case "wide": h = 5; break;
3568                     case "narrow": h = 2; break;
3569                     case "long": w = 5; break;
3570                     case "short": w = 2; break;
3571                 }
3572             }
3573             if (type == "open") {
3574                 w += 2;
3575                 h += 2;
3576                 t += 2;
3577                 dx = 1;
3578                 refX = isEnd ? 4 : 1;
3579                 attr = {
3580                     fill: "none",
3581                     stroke: attrs.stroke
3582                 };
3583             } else {
3584                 refX = dx = w / 2;
3585                 attr = {
3586                     fill: attrs.stroke,
3587                     stroke: "none"
3588                 };
3589             }
3590             if (o._.arrows) {
3591                 if (isEnd) {
3592                     o._.arrows.endPath && markerCounter[o._.arrows.endPath]--;
3593                     o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--;
3594                 } else {
3595                     o._.arrows.startPath && markerCounter[o._.arrows.startPath]--;
3596                     o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--;
3597                 }
3598             } else {
3599                 o._.arrows = {};
3600             }
3601             if (type != "none") {
3602                 var pathId = "raphael-marker-" + type,
3603                     markerId = "raphael-marker-" + se + type + w + h;
3604                 if (!R._g.doc.getElementById(pathId)) {
3605                     p.defs.appendChild($($("path"), {
3606                         "stroke-linecap": "round",
3607                         d: markers[type],
3608                         id: pathId
3609                     }));
3610                     markerCounter[pathId] = 1;
3611                 } else {
3612                     markerCounter[pathId]++;
3613                 }
3614                 var marker = R._g.doc.getElementById(markerId),
3615                     use;
3616                 if (!marker) {
3617                     marker = $($("marker"), {
3618                         id: markerId,
3619                         markerHeight: h,
3620                         markerWidth: w,
3621                         orient: "auto",
3622                         refX: refX,
3623                         refY: h / 2
3624                     });
3625                     use = $($("use"), {
3626                         "xlink:href": "#" + pathId,
3627                         transform: (isEnd ? " rotate(180 " + w / 2 + " " + h / 2 + ") " : S) + "scale(" + w / t + "," + h / t + ")",
3628                         "stroke-width": 1 / ((w / t + h / t) / 2)
3629                     });
3630                     marker.appendChild(use);
3631                     p.defs.appendChild(marker);
3632                     markerCounter[markerId] = 1;
3633                 } else {
3634                     markerCounter[markerId]++;
3635                     use = marker.getElementsByTagName("use")[0];
3636                 }
3637                 $(use, attr);
3638                 var delta = dx * (type != "diamond" && type != "oval");
3639                 if (isEnd) {
3640                     from = o._.arrows.startdx * stroke || 0;
3641                     to = R.getTotalLength(attrs.path) - delta * stroke;
3642                 } else {
3643                     from = delta * stroke;
3644                     to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
3645                 }
3646                 attr = {};
3647                 attr["marker-" + se] = "url(#" + markerId + ")";
3648                 if (to || from) {
3649                     attr.d = Raphael.getSubpath(attrs.path, from, to);
3650                 }
3651                 $(node, attr);
3652                 o._.arrows[se + "Path"] = pathId;
3653                 o._.arrows[se + "Marker"] = markerId;
3654                 o._.arrows[se + "dx"] = delta;
3655                 o._.arrows[se + "Type"] = type;
3656                 o._.arrows[se + "String"] = value;
3657             } else {
3658                 if (isEnd) {
3659                     from = o._.arrows.startdx * stroke || 0;
3660                     to = R.getTotalLength(attrs.path) - from;
3661                 } else {
3662                     from = 0;
3663                     to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
3664                 }
3665                 o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)});
3666                 delete o._.arrows[se + "Path"];
3667                 delete o._.arrows[se + "Marker"];
3668                 delete o._.arrows[se + "dx"];
3669                 delete o._.arrows[se + "Type"];
3670                 delete o._.arrows[se + "String"];
3671             }
3672             for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) {
3673                 var item = R._g.doc.getElementById(attr);
3674                 item && item.parentNode.removeChild(item);
3675             }
3676         }
3677     },
3678     dasharray = {
3679         "": [0],
3680         "none": [0],
3681         "-": [3, 1],
3682         ".": [1, 1],
3683         "-.": [3, 1, 1, 1],
3684         "-..": [3, 1, 1, 1, 1, 1],
3685         ". ": [1, 3],
3686         "- ": [4, 3],
3687         "--": [8, 3],
3688         "- .": [4, 3, 1, 3],
3689         "--.": [8, 3, 1, 3],
3690         "--..": [8, 3, 1, 3, 1, 3]
3691     },
3692     addDashes = function (o, value, params) {
3693         value = dasharray[Str(value).toLowerCase()];
3694         if (value) {
3695             var width = o.attrs["stroke-width"] || "1",
3696                 butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
3697                 dashes = [],
3698                 i = value.length;
3699             while (i--) {
3700                 dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
3701             }
3702             $(o.node, {"stroke-dasharray": dashes.join(",")});
3703         }
3704     },
3705     setFillAndStroke = function (o, params) {
3706         var node = o.node,
3707             attrs = o.attrs,
3708             vis = node.style.visibility;
3709         node.style.visibility = "hidden";
3710         for (var att in params) {
3711             if (params[has](att)) {
3712                 if (!R._availableAttrs[has](att)) {
3713                     continue;
3714                 }
3715                 var value = params[att];
3716                 attrs[att] = value;
3717                 switch (att) {
3718                     case "blur":
3719                         o.blur(value);
3720                         break;
3721                     case "href":
3722                     case "title":
3723                     case "target":
3724                         var pn = node.parentNode;
3725                         if (pn.tagName.toLowerCase() != "a") {
3726                             var hl = $("a");
3727                             pn.insertBefore(hl, node);
3728                             hl.appendChild(node);
3729                             pn = hl;
3730                         }
3731                         if (att == "target" && value == "blank") {
3732                             pn.setAttributeNS(xlink, "show", "new");
3733                         } else {
3734                             pn.setAttributeNS(xlink, att, value);
3735                         }
3736                         break;
3737                     case "cursor":
3738                         node.style.cursor = value;
3739                         break;
3740                     case "transform":
3741                         o.transform(value);
3742                         break;
3743                     case "arrow-start":
3744                         addArrow(o, value);
3745                         break;
3746                     case "arrow-end":
3747                         addArrow(o, value, 1);
3748                         break;
3749                     case "clip-rect":
3750                         var rect = Str(value).split(separator);
3751                         if (rect.length == 4) {
3752                             o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
3753                             var el = $("clipPath"),
3754                                 rc = $("rect");
3755                             el.id = R.createUUID();
3756                             $(rc, {
3757                                 x: rect[0],
3758                                 y: rect[1],
3759                                 width: rect[2],
3760                                 height: rect[3]
3761                             });
3762                             el.appendChild(rc);
3763                             o.paper.defs.appendChild(el);
3764                             $(node, {"clip-path": "url(#" + el.id + ")"});
3765                             o.clip = rc;
3766                         }
3767                         if (!value) {
3768                             var path = node.getAttribute("clip-path");
3769                             if (path) {
3770                                 var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E));
3771                                 clip && clip.parentNode.removeChild(clip);
3772                                 $(node, {"clip-path": E});
3773                                 delete o.clip;
3774                             }
3775                         }
3776                     break;
3777                     case "path":
3778                         if (o.type == "path") {
3779                             $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"});
3780                             o._.dirty = 1;
3781                             if (o._.arrows) {
3782                                 "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3783                                 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3784                             }
3785                         }
3786                         break;
3787                     case "width":
3788                         node.setAttribute(att, value);
3789                         o._.dirty = 1;
3790                         if (attrs.fx) {
3791                             att = "x";
3792                             value = attrs.x;
3793                         } else {
3794                             break;
3795                         }
3796                     case "x":
3797                         if (attrs.fx) {
3798                             value = -attrs.x - (attrs.width || 0);
3799                         }
3800                     case "rx":
3801                         if (att == "rx" && o.type == "rect") {
3802                             break;
3803                         }
3804                     case "cx":
3805                         node.setAttribute(att, value);
3806                         o.pattern && updatePosition(o);
3807                         o._.dirty = 1;
3808                         break;
3809                     case "height":
3810                         node.setAttribute(att, value);
3811                         o._.dirty = 1;
3812                         if (attrs.fy) {
3813                             att = "y";
3814                             value = attrs.y;
3815                         } else {
3816                             break;
3817                         }
3818                     case "y":
3819                         if (attrs.fy) {
3820                             value = -attrs.y - (attrs.height || 0);
3821                         }
3822                     case "ry":
3823                         if (att == "ry" && o.type == "rect") {
3824                             break;
3825                         }
3826                     case "cy":
3827                         node.setAttribute(att, value);
3828                         o.pattern && updatePosition(o);
3829                         o._.dirty = 1;
3830                         break;
3831                     case "r":
3832                         if (o.type == "rect") {
3833                             $(node, {rx: value, ry: value});
3834                         } else {
3835                             node.setAttribute(att, value);
3836                         }
3837                         o._.dirty = 1;
3838                         break;
3839                     case "src":
3840                         if (o.type == "image") {
3841                             node.setAttributeNS(xlink, "href", value);
3842                         }
3843                         break;
3844                     case "stroke-width":
3845                         if (o._.sx != 1 || o._.sy != 1) {
3846                             value /= mmax(abs(o._.sx), abs(o._.sy)) || 1;
3847                         }
3848                         if (o.paper._vbSize) {
3849                             value *= o.paper._vbSize;
3850                         }
3851                         node.setAttribute(att, value);
3852                         if (attrs["stroke-dasharray"]) {
3853                             addDashes(o, attrs["stroke-dasharray"], params);
3854                         }
3855                         if (o._.arrows) {
3856                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3857                             "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3858                         }
3859                         break;
3860                     case "stroke-dasharray":
3861                         addDashes(o, value, params);
3862                         break;
3863                     case "fill":
3864                         var isURL = Str(value).match(R._ISURL);
3865                         if (isURL) {
3866                             el = $("pattern");
3867                             var ig = $("image");
3868                             el.id = R.createUUID();
3869                             $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1});
3870                             $(ig, {x: 0, y: 0, "xlink:href": isURL[1]});
3871                             el.appendChild(ig);
3872
3873                             (function (el) {
3874                                 R._preload(isURL[1], function () {
3875                                     var w = this.offsetWidth,
3876                                         h = this.offsetHeight;
3877                                     $(el, {width: w, height: h});
3878                                     $(ig, {width: w, height: h});
3879                                     o.paper.safari();
3880                                 });
3881                             })(el);
3882                             o.paper.defs.appendChild(el);
3883                             node.style.fill = "url(#" + el.id + ")";
3884                             $(node, {fill: "url(#" + el.id + ")"});
3885                             o.pattern = el;
3886                             o.pattern && updatePosition(o);
3887                             break;
3888                         }
3889                         var clr = R.getRGB(value);
3890                         if (!clr.error) {
3891                             delete params.gradient;
3892                             delete attrs.gradient;
3893                             !R.is(attrs.opacity, "undefined") &&
3894                                 R.is(params.opacity, "undefined") &&
3895                                 $(node, {opacity: attrs.opacity});
3896                             !R.is(attrs["fill-opacity"], "undefined") &&
3897                                 R.is(params["fill-opacity"], "undefined") &&
3898                                 $(node, {"fill-opacity": attrs["fill-opacity"]});
3899                         } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) {
3900                             if ("opacity" in attrs || "fill-opacity" in attrs) {
3901                                 var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
3902                                 if (gradient) {
3903                                     var stops = gradient.getElementsByTagName("stop");
3904                                     $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)});
3905                                 }
3906                             }
3907                             attrs.gradient = value;
3908                             attrs.fill = "none";
3909                             break;
3910                         }
3911                         clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
3912                     case "stroke":
3913                         clr = R.getRGB(value);
3914                         node.setAttribute(att, clr.hex);
3915                         att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
3916                         if (att == "stroke" && o._.arrows) {
3917                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3918                             "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3919                         }
3920                         break;
3921                     case "gradient":
3922                         (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value);
3923                         break;
3924                     case "opacity":
3925                         if (attrs.gradient && !attrs[has]("stroke-opacity")) {
3926                             $(node, {"stroke-opacity": value > 1 ? value / 100 : value});
3927                         }
3928                         // fall
3929                     case "fill-opacity":
3930                         if (attrs.gradient) {
3931                             gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
3932                             if (gradient) {
3933                                 stops = gradient.getElementsByTagName("stop");
3934                                 $(stops[stops.length - 1], {"stop-opacity": value});
3935                             }
3936                             break;
3937                         }
3938                     default:
3939                         att == "font-size" && (value = toInt(value, 10) + "px");
3940                         var cssrule = att.replace(/(\-.)/g, function (w) {
3941                             return w.substring(1).toUpperCase();
3942                         });
3943                         node.style[cssrule] = value;
3944                         o._.dirty = 1;
3945                         node.setAttribute(att, value);
3946                         break;
3947                 }
3948             }
3949         }
3950
3951         tuneText(o, params);
3952         node.style.visibility = vis;
3953     },
3954     leading = 1.2,
3955     tuneText = function (el, params) {
3956         if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) {
3957             return;
3958         }
3959         var a = el.attrs,
3960             node = el.node,
3961             fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10;
3962
3963         if (params[has]("text")) {
3964             a.text = params.text;
3965             while (node.firstChild) {
3966                 node.removeChild(node.firstChild);
3967             }
3968             var texts = Str(params.text).split("\n"),
3969                 tspans = [],
3970                 tspan;
3971             for (var i = 0, ii = texts.length; i < ii; i++) {
3972                 tspan = $("tspan");
3973                 i && $(tspan, {dy: fontSize * leading, x: a.x});
3974                 tspan.appendChild(R._g.doc.createTextNode(texts[i]));
3975                 node.appendChild(tspan);
3976                 tspans[i] = tspan;
3977             }
3978         } else {
3979             tspans = node.getElementsByTagName("tspan");
3980             for (i = 0, ii = tspans.length; i < ii; i++) if (i) {
3981                 $(tspans[i], {dy: fontSize * leading, x: a.x});
3982             } else {
3983                 $(tspans[0], {dy: 0});
3984             }
3985         }
3986         $(node, {x: a.x, y: a.y});
3987         el._.dirty = 1;
3988         var bb = el._getBBox(),
3989             dif = a.y - (bb.y + bb.height / 2);
3990         dif && R.is(dif, "finite") && $(tspans[0], {dy: dif});
3991     },
3992     Element = function (node, svg) {
3993         var X = 0,
3994             Y = 0;
3995         
3996         this[0] = this.node = node;
3997         
3998         node.raphael = true;
3999         
4000         this.id = R._oid++;
4001         node.raphaelid = this.id;
4002         this.matrix = R.matrix();
4003         this.realPath = null;
4004         
4005         this.paper = svg;
4006         this.attrs = this.attrs || {};
4007         this._ = {
4008             transform: [],
4009             sx: 1,
4010             sy: 1,
4011             deg: 0,
4012             dx: 0,
4013             dy: 0,
4014             dirty: 1
4015         };
4016         !svg.bottom && (svg.bottom = this);
4017         
4018         this.prev = svg.top;
4019         svg.top && (svg.top.next = this);
4020         svg.top = this;
4021         
4022         this.next = null;
4023     },
4024     elproto = R.el;
4025
4026     Element.prototype = elproto;
4027     elproto.constructor = Element;
4028
4029     R._engine.path = function (pathString, SVG) {
4030         var el = $("path");
4031         SVG.canvas && SVG.canvas.appendChild(el);
4032         var p = new Element(el, SVG);
4033         p.type = "path";
4034         setFillAndStroke(p, {
4035             fill: "none",
4036             stroke: "#000",
4037             path: pathString
4038         });
4039         return p;
4040     };
4041     
4042     elproto.rotate = function (deg, cx, cy) {
4043         if (this.removed) {
4044             return this;
4045         }
4046         deg = Str(deg).split(separator);
4047         if (deg.length - 1) {
4048             cx = toFloat(deg[1]);
4049             cy = toFloat(deg[2]);
4050         }
4051         deg = toFloat(deg[0]);
4052         (cy == null) && (cx = cy);
4053         if (cx == null || cy == null) {
4054             var bbox = this.getBBox(1);
4055             cx = bbox.x + bbox.width / 2;
4056             cy = bbox.y + bbox.height / 2;
4057         }
4058         this.transform(this._.transform.concat([["r", deg, cx, cy]]));
4059         return this;
4060     };
4061     
4062     elproto.scale = function (sx, sy, cx, cy) {
4063         if (this.removed) {
4064             return this;
4065         }
4066         sx = Str(sx).split(separator);
4067         if (sx.length - 1) {
4068             sy = toFloat(sx[1]);
4069             cx = toFloat(sx[2]);
4070             cy = toFloat(sx[3]);
4071         }
4072         sx = toFloat(sx[0]);
4073         (sy == null) && (sy = sx);
4074         (cy == null) && (cx = cy);
4075         if (cx == null || cy == null) {
4076             var bbox = this.getBBox(1);
4077         }
4078         cx = cx == null ? bbox.x + bbox.width / 2 : cx;
4079         cy = cy == null ? bbox.y + bbox.height / 2 : cy;
4080         this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
4081         return this;
4082     };
4083     
4084     elproto.translate = function (dx, dy) {
4085         if (this.removed) {
4086             return this;
4087         }
4088         dx = Str(dx).split(separator);
4089         if (dx.length - 1) {
4090             dy = toFloat(dx[1]);
4091         }
4092         dx = toFloat(dx[0]) || 0;
4093         dy = +dy || 0;
4094         this.transform(this._.transform.concat([["t", dx, dy]]));
4095         return this;
4096     };
4097     
4098     elproto.transform = function (tstr) {
4099         var _ = this._;
4100         if (tstr == null) {
4101             return _.transform;
4102         }
4103         R._extractTransform(this, tstr);
4104
4105         this.clip && $(this.clip, {transform: this.matrix.invert()});
4106         this.pattern && updatePosition(this);
4107         this.node && $(this.node, {transform: this.matrix});
4108     
4109         if (_.sx != 1 || _.sy != 1) {
4110             var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1;
4111             this.attr({"stroke-width": sw});
4112         }
4113
4114         return this;
4115     };
4116     
4117     elproto.hide = function () {
4118         !this.removed && this.paper.safari(this.node.style.display = "none");
4119         return this;
4120     };
4121     
4122     elproto.show = function () {
4123         !this.removed && this.paper.safari(this.node.style.display = "");
4124         return this;
4125     };
4126     
4127     elproto.remove = function () {
4128         if (this.removed) {
4129             return;
4130         }
4131         var paper = this.paper;
4132         paper.__set__ && paper.__set__.exclude(this);
4133         eve.unbind("*.*." + this.id);
4134         if (this.gradient) {
4135             paper.defs.removeChild(this.gradient);
4136         }
4137         R._tear(this, paper);
4138         this.node.parentNode.removeChild(this.node);
4139         for (var i in this) {
4140             this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
4141         }
4142         this.removed = true;
4143     };
4144     elproto._getBBox = function () {
4145         if (this.node.style.display == "none") {
4146             this.show();
4147             var hide = true;
4148         }
4149         var bbox = {};
4150         try {
4151             bbox = this.node.getBBox();
4152         } catch(e) {
4153             // Firefox 3.0.x plays badly here
4154         } finally {
4155             bbox = bbox || {};
4156         }
4157         hide && this.hide();
4158         return bbox;
4159     };
4160     
4161     elproto.attr = function (name, value) {
4162         if (this.removed) {
4163             return this;
4164         }
4165         if (name == null) {
4166             var res = {};
4167             for (var a in this.attrs) if (this.attrs[has](a)) {
4168                 res[a] = this.attrs[a];
4169             }
4170             res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
4171             res.transform = this._.transform;
4172             return res;
4173         }
4174         if (value == null && R.is(name, "string")) {
4175             if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) {
4176                 return this.attrs.gradient;
4177             }
4178             if (name == "transform") {
4179                 return this._.transform;
4180             }
4181             var names = name.split(separator),
4182                 out = {};
4183             for (var i = 0, ii = names.length; i < ii; i++) {
4184                 name = names[i];
4185                 if (name in this.attrs) {
4186                     out[name] = this.attrs[name];
4187                 } else if (R.is(this.paper.customAttributes[name], "function")) {
4188                     out[name] = this.paper.customAttributes[name].def;
4189                 } else {
4190                     out[name] = R._availableAttrs[name];
4191                 }
4192             }
4193             return ii - 1 ? out : out[names[0]];
4194         }
4195         if (value == null && R.is(name, "array")) {
4196             out = {};
4197             for (i = 0, ii = name.length; i < ii; i++) {
4198                 out[name[i]] = this.attr(name[i]);
4199             }
4200             return out;
4201         }
4202         if (value != null) {
4203             var params = {};
4204             params[name] = value;
4205         } else if (name != null && R.is(name, "object")) {
4206             params = name;
4207         }
4208         for (var key in params) {
4209             eve("attr." + key + "." + this.id, this, params[key]);
4210         }
4211         for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
4212             var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
4213             this.attrs[key] = params[key];
4214             for (var subkey in par) if (par[has](subkey)) {
4215                 params[subkey] = par[subkey];
4216             }
4217         }
4218         setFillAndStroke(this, params);
4219         return this;
4220     };
4221     
4222     elproto.toFront = function () {
4223         if (this.removed) {
4224             return this;
4225         }
4226         if (this.node.parentNode.tagName.toLowerCase() == "a") {
4227             this.node.parentNode.parentNode.appendChild(this.node.parentNode);
4228         } else {
4229             this.node.parentNode.appendChild(this.node);
4230         }
4231         var svg = this.paper;
4232         svg.top != this && R._tofront(this, svg);
4233         return this;
4234     };
4235     
4236     elproto.toBack = function () {
4237         if (this.removed) {
4238             return this;
4239         }
4240         var parent = this.node.parentNode;
4241         if (parent.tagName.toLowerCase() == "a") {
4242             parent.parentNode.insertBefore(this.node.parentNode, this.node.parentNode.parentNode.firstChild); 
4243         } else if (parent.firstChild != this.node) {
4244             parent.insertBefore(this.node, this.node.parentNode.firstChild);
4245         }
4246         R._toback(this, this.paper);
4247         var svg = this.paper;
4248         return this;
4249     };
4250     
4251     elproto.insertAfter = function (element) {
4252         if (this.removed) {
4253             return this;
4254         }
4255         var node = element.node || element[element.length - 1].node;
4256         if (node.nextSibling) {
4257             node.parentNode.insertBefore(this.node, node.nextSibling);
4258         } else {
4259             node.parentNode.appendChild(this.node);
4260         }
4261         R._insertafter(this, element, this.paper);
4262         return this;
4263     };
4264     
4265     elproto.insertBefore = function (element) {
4266         if (this.removed) {
4267             return this;
4268         }
4269         var node = element.node || element[0].node;
4270         node.parentNode.insertBefore(this.node, node);
4271         R._insertbefore(this, element, this.paper);
4272         return this;
4273     };
4274     elproto.blur = function (size) {
4275         // Experimental. No Safari support. Use it on your own risk.
4276         var t = this;
4277         if (+size !== 0) {
4278             var fltr = $("filter"),
4279                 blur = $("feGaussianBlur");
4280             t.attrs.blur = size;
4281             fltr.id = R.createUUID();
4282             $(blur, {stdDeviation: +size || 1.5});
4283             fltr.appendChild(blur);
4284             t.paper.defs.appendChild(fltr);
4285             t._blur = fltr;
4286             $(t.node, {filter: "url(#" + fltr.id + ")"});
4287         } else {
4288             if (t._blur) {
4289                 t._blur.parentNode.removeChild(t._blur);
4290                 delete t._blur;
4291                 delete t.attrs.blur;
4292             }
4293             t.node.removeAttribute("filter");
4294         }
4295     };
4296     R._engine.circle = function (svg, x, y, r) {
4297         var el = $("circle");
4298         svg.canvas && svg.canvas.appendChild(el);
4299         var res = new Element(el, svg);
4300         res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"};
4301         res.type = "circle";
4302         $(el, res.attrs);
4303         return res;
4304     };
4305     R._engine.rect = function (svg, x, y, w, h, r) {
4306         var el = $("rect");
4307         svg.canvas && svg.canvas.appendChild(el);
4308         var res = new Element(el, svg);
4309         res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"};
4310         res.type = "rect";
4311         $(el, res.attrs);
4312         return res;
4313     };
4314     R._engine.ellipse = function (svg, x, y, rx, ry) {
4315         var el = $("ellipse");
4316         svg.canvas && svg.canvas.appendChild(el);
4317         var res = new Element(el, svg);
4318         res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"};
4319         res.type = "ellipse";
4320         $(el, res.attrs);
4321         return res;
4322     };
4323     R._engine.image = function (svg, src, x, y, w, h) {
4324         var el = $("image");
4325         $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"});
4326         el.setAttributeNS(xlink, "href", src);
4327         svg.canvas && svg.canvas.appendChild(el);
4328         var res = new Element(el, svg);
4329         res.attrs = {x: x, y: y, width: w, height: h, src: src};
4330         res.type = "image";
4331         return res;
4332     };
4333     R._engine.text = function (svg, x, y, text) {
4334         var el = $("text");
4335         // $(el, {x: x, y: y, "text-anchor": "middle"});
4336         svg.canvas && svg.canvas.appendChild(el);
4337         var res = new Element(el, svg);
4338         res.attrs = {
4339             x: x,
4340             y: y,
4341             "text-anchor": "middle",
4342             text: text,
4343             font: R._availableAttrs.font,
4344             stroke: "none",
4345             fill: "#000"
4346         };
4347         res.type = "text";
4348         setFillAndStroke(res, res.attrs);
4349         return res;
4350     };
4351     R._engine.setSize = function (width, height) {
4352         this.width = width || this.width;
4353         this.height = height || this.height;
4354         this.canvas.setAttribute("width", this.width);
4355         this.canvas.setAttribute("height", this.height);
4356         if (this._viewBox) {
4357             this.setViewBox.apply(this, this._viewBox);
4358         }
4359         return this;
4360     };
4361     R._engine.create = function () {
4362         var con = R._getContainer.apply(0, arguments),
4363             container = con && con.container,
4364             x = con.x,
4365             y = con.y,
4366             width = con.width,
4367             height = con.height;
4368         if (!container) {
4369             throw new Error("SVG container not found.");
4370         }
4371         var cnvs = $("svg"),
4372             css = "overflow:hidden;",
4373             isFloating;
4374         x = x || 0;
4375         y = y || 0;
4376         width = width || 512;
4377         height = height || 342;
4378         $(cnvs, {
4379             height: height,
4380             version: 1.1,
4381             width: width,
4382             xmlns: "http://www.w3.org/2000/svg"
4383         });
4384         if (container == 1) {
4385             cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
4386             R._g.doc.body.appendChild(cnvs);
4387             isFloating = 1;
4388         } else {
4389             cnvs.style.cssText = css + "position:relative";
4390             if (container.firstChild) {
4391                 container.insertBefore(cnvs, container.firstChild);
4392             } else {
4393                 container.appendChild(cnvs);
4394             }
4395         }
4396         container = new R._Paper;
4397         container.width = width;
4398         container.height = height;
4399         container.canvas = cnvs;
4400         // plugins.call(container, container, R.fn);
4401         container.clear();
4402         container._left = container._top = 0;
4403         isFloating && (container.renderfix = function () {});
4404         container.renderfix();
4405         return container;
4406     };
4407     R._engine.setViewBox = function (x, y, w, h, fit) {
4408         eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]);
4409         var size = mmax(w / this.width, h / this.height),
4410             top = this.top,
4411             aspectRatio = fit ? "meet" : "xMinYMin",
4412             vb,
4413             sw;
4414         if (x == null) {
4415             if (this._vbSize) {
4416                 size = 1;
4417             }
4418             delete this._vbSize;
4419             vb = "0 0 " + this.width + S + this.height;
4420         } else {
4421             this._vbSize = size;
4422             vb = x + S + y + S + w + S + h;
4423         }
4424         $(this.canvas, {
4425             viewBox: vb,
4426             preserveAspectRatio: aspectRatio
4427         });
4428         while (size && top) {
4429             sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1;
4430             top.attr({"stroke-width": sw});
4431             top._.dirty = 1;
4432             top._.dirtyT = 1;
4433             top = top.prev;
4434         }
4435         this._viewBox = [x, y, w, h, !!fit];
4436         return this;
4437     };
4438     
4439     R.prototype.renderfix = function () {
4440         var cnvs = this.canvas,
4441             s = cnvs.style,
4442             pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(),
4443             left = -pos.e % 1,
4444             top = -pos.f % 1;
4445         if (left || top) {
4446             if (left) {
4447                 this._left = (this._left + left) % 1;
4448                 s.left = this._left + "px";
4449             }
4450             if (top) {
4451                 this._top = (this._top + top) % 1;
4452                 s.top = this._top + "px";
4453             }
4454         }
4455     };
4456     
4457     R.prototype.clear = function () {
4458         R.eve("clear", this);
4459         var c = this.canvas;
4460         while (c.firstChild) {
4461             c.removeChild(c.firstChild);
4462         }
4463         this.bottom = this.top = null;
4464         (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version));
4465         c.appendChild(this.desc);
4466         c.appendChild(this.defs = $("defs"));
4467     };
4468     
4469     R.prototype.remove = function () {
4470         eve("remove", this);
4471         this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
4472         for (var i in this) {
4473             this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
4474         }
4475     };
4476     var setproto = R.st;
4477     for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
4478         setproto[method] = (function (methodname) {
4479             return function () {
4480                 var arg = arguments;
4481                 return this.forEach(function (el) {
4482                     el[methodname].apply(el, arg);
4483                 });
4484             };
4485         })(method);
4486     }
4487 }(window.Raphael);
4488
4489 // ┌─────────────────────────────────────────────────────────────────────┐ \\
4490 // │ Raphaël - JavaScript Vector Library                                 │ \\
4491 // ├─────────────────────────────────────────────────────────────────────┤ \\
4492 // │ VML Module                                                          │ \\
4493 // ├─────────────────────────────────────────────────────────────────────┤ \\
4494 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
4495 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
4496 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
4497 // └─────────────────────────────────────────────────────────────────────┘ \\
4498 window.Raphael.vml && function (R) {
4499     var has = "hasOwnProperty",
4500         Str = String,
4501         toFloat = parseFloat,
4502         math = Math,
4503         round = math.round,
4504         mmax = math.max,
4505         mmin = math.min,
4506         abs = math.abs,
4507         fillString = "fill",
4508         separator = /[, ]+/,
4509         eve = R.eve,
4510         ms = " progid:DXImageTransform.Microsoft",
4511         S = " ",
4512         E = "",
4513         map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"},
4514         bites = /([clmz]),?([^clmz]*)/gi,
4515         blurregexp = / progid:\S+Blur\([^\)]+\)/g,
4516         val = /-?[^,\s-]+/g,
4517         cssDot = "position:absolute;left:0;top:0;width:1px;height:1px",
4518         zoom = 21600,
4519         pathTypes = {path: 1, rect: 1, image: 1},
4520         ovalTypes = {circle: 1, ellipse: 1},
4521         path2vml = function (path) {
4522             var total =  /[ahqstv]/ig,
4523                 command = R._pathToAbsolute;
4524             Str(path).match(total) && (command = R._path2curve);
4525             total = /[clmz]/g;
4526             if (command == R._pathToAbsolute && !Str(path).match(total)) {
4527                 var res = Str(path).replace(bites, function (all, command, args) {
4528                     var vals = [],
4529                         isMove = command.toLowerCase() == "m",
4530                         res = map[command];
4531                     args.replace(val, function (value) {
4532                         if (isMove && vals.length == 2) {
4533                             res += vals + map[command == "m" ? "l" : "L"];
4534                             vals = [];
4535                         }
4536                         vals.push(round(value * zoom));
4537                     });
4538                     return res + vals;
4539                 });
4540                 return res;
4541             }
4542             var pa = command(path), p, r;
4543             res = [];
4544             for (var i = 0, ii = pa.length; i < ii; i++) {
4545                 p = pa[i];
4546                 r = pa[i][0].toLowerCase();
4547                 r == "z" && (r = "x");
4548                 for (var j = 1, jj = p.length; j < jj; j++) {
4549                     r += round(p[j] * zoom) + (j != jj - 1 ? "," : E);
4550                 }
4551                 res.push(r);
4552             }
4553             return res.join(S);
4554         },
4555         compensation = function (deg, dx, dy) {
4556             var m = R.matrix();
4557             m.rotate(-deg, .5, .5);
4558             return {
4559                 dx: m.x(dx, dy),
4560                 dy: m.y(dx, dy)
4561             };
4562         },
4563         setCoords = function (p, sx, sy, dx, dy, deg) {
4564             var _ = p._,
4565                 m = p.matrix,
4566                 fillpos = _.fillpos,
4567                 o = p.node,
4568                 s = o.style,
4569                 y = 1,
4570                 flip = "",
4571                 dxdy,
4572                 kx = zoom / sx,
4573                 ky = zoom / sy;
4574             s.visibility = "hidden";
4575             if (!sx || !sy) {
4576                 return;
4577             }
4578             o.coordsize = abs(kx) + S + abs(ky);
4579             s.rotation = deg * (sx * sy < 0 ? -1 : 1);
4580             if (deg) {
4581                 var c = compensation(deg, dx, dy);
4582                 dx = c.dx;
4583                 dy = c.dy;
4584             }
4585             sx < 0 && (flip += "x");
4586             sy < 0 && (flip += " y") && (y = -1);
4587             s.flip = flip;
4588             o.coordorigin = (dx * -kx) + S + (dy * -ky);
4589             if (fillpos || _.fillsize) {
4590                 var fill = o.getElementsByTagName(fillString);
4591                 fill = fill && fill[0];
4592                 o.removeChild(fill);
4593                 if (fillpos) {
4594                     c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1]));
4595                     fill.position = c.dx * y + S + c.dy * y;
4596                 }
4597                 if (_.fillsize) {
4598                     fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy);
4599                 }
4600                 o.appendChild(fill);
4601             }
4602             s.visibility = "visible";
4603         };
4604     R.toString = function () {
4605         return  "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version;
4606     };
4607     var addArrow = function (o, value, isEnd) {
4608         var values = Str(value).toLowerCase().split("-"),
4609             se = isEnd ? "end" : "start",
4610             i = values.length,
4611             type = "classic",
4612             w = "medium",
4613             h = "medium";
4614         while (i--) {
4615             switch (values[i]) {
4616                 case "block":
4617                 case "classic":
4618                 case "oval":
4619                 case "diamond":
4620                 case "open":
4621                 case "none":
4622                     type = values[i];
4623                     break;
4624                 case "wide":
4625                 case "narrow": h = values[i]; break;
4626                 case "long":
4627                 case "short": w = values[i]; break;
4628             }
4629         }
4630         var stroke = o.node.getElementsByTagName("stroke")[0];
4631         stroke[se + "arrow"] = type;
4632         stroke[se + "arrowlength"] = w;
4633         stroke[se + "arrowwidth"] = h;
4634     },
4635     setFillAndStroke = function (o, params) {
4636         // o.paper.canvas.style.display = "none";
4637         o.attrs = o.attrs || {};
4638         var node = o.node,
4639             a = o.attrs,
4640             s = node.style,
4641             xy,
4642             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),
4643             isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry),
4644             res = o;
4645
4646
4647         for (var par in params) if (params[has](par)) {
4648             a[par] = params[par];
4649         }
4650         if (newpath) {
4651             a.path = R._getPath[o.type](o);
4652             o._.dirty = 1;
4653         }
4654         params.href && (node.href = params.href);
4655         params.title && (node.title = params.title);
4656         params.target && (node.target = params.target);
4657         params.cursor && (s.cursor = params.cursor);
4658         "blur" in params && o.blur(params.blur);
4659         if (params.path && o.type == "path" || newpath) {
4660             node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path);
4661             if (o.type == "image") {
4662                 o._.fillpos = [a.x, a.y];
4663                 o._.fillsize = [a.width, a.height];
4664                 setCoords(o, 1, 1, 0, 0, 0);
4665             }
4666         }
4667         "transform" in params && o.transform(params.transform);
4668         if (isOval) {
4669             var cx = +a.cx,
4670                 cy = +a.cy,
4671                 rx = +a.rx || +a.r || 0,
4672                 ry = +a.ry || +a.r || 0;
4673             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));
4674         }
4675         if ("clip-rect" in params) {
4676             var rect = Str(params["clip-rect"]).split(separator);
4677             if (rect.length == 4) {
4678                 rect[2] = +rect[2] + (+rect[0]);
4679                 rect[3] = +rect[3] + (+rect[1]);
4680                 var div = node.clipRect || R._g.doc.createElement("div"),
4681                     dstyle = div.style;
4682                 dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect);
4683                 if (!node.clipRect) {
4684                     dstyle.position = "absolute";
4685                     dstyle.top = 0;
4686                     dstyle.left = 0;
4687                     dstyle.width = o.paper.width + "px";
4688                     dstyle.height = o.paper.height + "px";
4689                     node.parentNode.insertBefore(div, node);
4690                     div.appendChild(node);
4691                     node.clipRect = div;
4692                 }
4693             }
4694             if (!params["clip-rect"]) {
4695                 node.clipRect && (node.clipRect.style.clip = "auto");
4696             }
4697         }
4698         if (o.textpath) {
4699             var textpathStyle = o.textpath.style;
4700             params.font && (textpathStyle.font = params.font);
4701             params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"');
4702             params["font-size"] && (textpathStyle.fontSize = params["font-size"]);
4703             params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]);
4704             params["font-style"] && (textpathStyle.fontStyle = params["font-style"]);
4705         }
4706         if ("arrow-start" in params) {
4707             addArrow(res, params["arrow-start"]);
4708         }
4709         if ("arrow-end" in params) {
4710             addArrow(res, params["arrow-end"], 1);
4711         }
4712         if (params.opacity != null || 
4713             params["stroke-width"] != null ||
4714             params.fill != null ||
4715             params.src != null ||
4716             params.stroke != null ||
4717             params["stroke-width"] != null ||
4718             params["stroke-opacity"] != null ||
4719             params["fill-opacity"] != null ||
4720             params["stroke-dasharray"] != null ||
4721             params["stroke-miterlimit"] != null ||
4722             params["stroke-linejoin"] != null ||
4723             params["stroke-linecap"] != null) {
4724             var fill = node.getElementsByTagName(fillString),
4725                 newfill = false;
4726             fill = fill && fill[0];
4727             !fill && (newfill = fill = createNode(fillString));
4728             if (o.type == "image" && params.src) {
4729                 fill.src = params.src;
4730             }
4731             params.fill && (fill.on = true);
4732             if (fill.on == null || params.fill == "none" || params.fill === null) {
4733                 fill.on = false;
4734             }
4735             if (fill.on && params.fill) {
4736                 var isURL = Str(params.fill).match(R._ISURL);
4737                 if (isURL) {
4738                     fill.parentNode == node && node.removeChild(fill);
4739                     fill.rotate = true;
4740                     fill.src = isURL[1];
4741                     fill.type = "tile";
4742                     var bbox = o.getBBox(1);
4743                     fill.position = bbox.x + S + bbox.y;
4744                     o._.fillpos = [bbox.x, bbox.y];
4745
4746                     R._preload(isURL[1], function () {
4747                         o._.fillsize = [this.offsetWidth, this.offsetHeight];
4748                     });
4749                 } else {
4750                     fill.color = R.getRGB(params.fill).hex;
4751                     fill.src = E;
4752                     fill.type = "solid";
4753                     if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) {
4754                         a.fill = "none";
4755                         a.gradient = params.fill;
4756                         fill.rotate = false;
4757                     }
4758                 }
4759             }
4760             if ("fill-opacity" in params || "opacity" in params) {
4761                 var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1);
4762                 opacity = mmin(mmax(opacity, 0), 1);
4763                 fill.opacity = opacity;
4764                 if (fill.src) {
4765                     fill.color = "none";
4766                 }
4767             }
4768             node.appendChild(fill);
4769             var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]),
4770             newstroke = false;
4771             !stroke && (newstroke = stroke = createNode("stroke"));
4772             if ((params.stroke && params.stroke != "none") ||
4773                 params["stroke-width"] ||
4774                 params["stroke-opacity"] != null ||
4775                 params["stroke-dasharray"] ||
4776                 params["stroke-miterlimit"] ||
4777                 params["stroke-linejoin"] ||
4778                 params["stroke-linecap"]) {
4779                 stroke.on = true;
4780             }
4781             (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false);
4782             var strokeColor = R.getRGB(params.stroke);
4783             stroke.on && params.stroke && (stroke.color = strokeColor.hex);
4784             opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1);
4785             var width = (toFloat(params["stroke-width"]) || 1) * .75;
4786             opacity = mmin(mmax(opacity, 0), 1);
4787             params["stroke-width"] == null && (width = a["stroke-width"]);
4788             params["stroke-width"] && (stroke.weight = width);
4789             width && width < 1 && (opacity *= width) && (stroke.weight = 1);
4790             stroke.opacity = opacity;
4791         
4792             params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter");
4793             stroke.miterlimit = params["stroke-miterlimit"] || 8;
4794             params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round");
4795             if (params["stroke-dasharray"]) {
4796                 var dasharray = {
4797                     "-": "shortdash",
4798                     ".": "shortdot",
4799                     "-.": "shortdashdot",
4800                     "-..": "shortdashdotdot",
4801                     ". ": "dot",
4802                     "- ": "dash",
4803                     "--": "longdash",
4804                     "- .": "dashdot",
4805                     "--.": "longdashdot",
4806                     "--..": "longdashdotdot"
4807                 };
4808                 stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E;
4809             }
4810             newstroke && node.appendChild(stroke);
4811         }
4812         if (res.type == "text") {
4813             res.paper.canvas.style.display = E;
4814             var span = res.paper.span,
4815                 m = 100,
4816                 fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/);
4817             s = span.style;
4818             a.font && (s.font = a.font);
4819             a["font-family"] && (s.fontFamily = a["font-family"]);
4820             a["font-weight"] && (s.fontWeight = a["font-weight"]);
4821             a["font-style"] && (s.fontStyle = a["font-style"]);
4822             fontSize = toFloat(a["font-size"] || fontSize && fontSize[0]) || 10;
4823             s.fontSize = fontSize * m + "px";
4824             res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/</g, "&#60;").replace(/&/g, "&#38;").replace(/\n/g, "<br>"));
4825             var brect = span.getBoundingClientRect();
4826             res.W = a.w = (brect.right - brect.left) / m;
4827             res.H = a.h = (brect.bottom - brect.top) / m;
4828             // res.paper.canvas.style.display = "none";
4829             res.X = a.x;
4830             res.Y = a.y + res.H / 2;
4831
4832             ("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));
4833             var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"];
4834             for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) {
4835                 res._.dirty = 1;
4836                 break;
4837             }
4838         
4839             // text-anchor emulation
4840             switch (a["text-anchor"]) {
4841                 case "start":
4842                     res.textpath.style["v-text-align"] = "left";
4843                     res.bbx = res.W / 2;
4844                 break;
4845                 case "end":
4846                     res.textpath.style["v-text-align"] = "right";
4847                     res.bbx = -res.W / 2;
4848                 break;
4849                 default:
4850                     res.textpath.style["v-text-align"] = "center";
4851                     res.bbx = 0;
4852                 break;
4853             }
4854             res.textpath.style["v-text-kern"] = true;
4855         }
4856         // res.paper.canvas.style.display = E;
4857     },
4858     addGradientFill = function (o, gradient, fill) {
4859         o.attrs = o.attrs || {};
4860         var attrs = o.attrs,
4861             pow = Math.pow,
4862             opacity,
4863             oindex,
4864             type = "linear",
4865             fxfy = ".5 .5";
4866         o.attrs.gradient = gradient;
4867         gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) {
4868             type = "radial";
4869             if (fx && fy) {
4870                 fx = toFloat(fx);
4871                 fy = toFloat(fy);
4872                 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5);
4873                 fxfy = fx + S + fy;
4874             }
4875             return E;
4876         });
4877         gradient = gradient.split(/\s*\-\s*/);
4878         if (type == "linear") {
4879             var angle = gradient.shift();
4880             angle = -toFloat(angle);
4881             if (isNaN(angle)) {
4882                 return null;
4883             }
4884         }
4885         var dots = R._parseDots(gradient);
4886         if (!dots) {
4887             return null;
4888         }
4889         o = o.shape || o.node;
4890         if (dots.length) {
4891             o.removeChild(fill);
4892             fill.on = true;
4893             fill.method = "none";
4894             fill.color = dots[0].color;
4895             fill.color2 = dots[dots.length - 1].color;
4896             var clrs = [];
4897             for (var i = 0, ii = dots.length; i < ii; i++) {
4898                 dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color);
4899             }
4900             fill.colors = clrs.length ? clrs.join() : "0% " + fill.color;
4901             if (type == "radial") {
4902                 fill.type = "gradientTitle";
4903                 fill.focus = "100%";
4904                 fill.focussize = "0 0";
4905                 fill.focusposition = fxfy;
4906                 fill.angle = 0;
4907             } else {
4908                 // fill.rotate= true;
4909                 fill.type = "gradient";
4910                 fill.angle = (270 - angle) % 360;
4911             }
4912             o.appendChild(fill);
4913         }
4914         return 1;
4915     },
4916     Element = function (node, vml) {
4917         this[0] = this.node = node;
4918         node.raphael = true;
4919         this.id = R._oid++;
4920         node.raphaelid = this.id;
4921         this.X = 0;
4922         this.Y = 0;
4923         this.attrs = {};
4924         this.paper = vml;
4925         this.matrix = R.matrix();
4926         this._ = {
4927             transform: [],
4928             sx: 1,
4929             sy: 1,
4930             dx: 0,
4931             dy: 0,
4932             deg: 0,
4933             dirty: 1,
4934             dirtyT: 1
4935         };
4936         !vml.bottom && (vml.bottom = this);
4937         this.prev = vml.top;
4938         vml.top && (vml.top.next = this);
4939         vml.top = this;
4940         this.next = null;
4941     };
4942     var elproto = R.el;
4943
4944     Element.prototype = elproto;
4945     elproto.constructor = Element;
4946     elproto.transform = function (tstr) {
4947         if (tstr == null) {
4948             return this._.transform;
4949         }
4950         var vbs = this.paper._viewBoxShift,
4951             vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E,
4952             oldt;
4953         if (vbs) {
4954             oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E);
4955         }
4956         R._extractTransform(this, vbt + tstr);
4957         var matrix = this.matrix.clone(),
4958             skew = this.skew,
4959             o = this.node,
4960             split,
4961             isGrad = ~Str(this.attrs.fill).indexOf("-"),
4962             isPatt = !Str(this.attrs.fill).indexOf("url(");
4963         matrix.translate(-.5, -.5);
4964         if (isPatt || isGrad || this.type == "image") {
4965             skew.matrix = "1 0 0 1";
4966             skew.offset = "0 0";
4967             split = matrix.split();
4968             if ((isGrad && split.noRotation) || !split.isSimple) {
4969                 o.style.filter = matrix.toFilter();
4970                 var bb = this.getBBox(),
4971                     bbt = this.getBBox(1),
4972                     dx = bb.x - bbt.x,
4973                     dy = bb.y - bbt.y;
4974                 o.coordorigin = (dx * -zoom) + S + (dy * -zoom);
4975                 setCoords(this, 1, 1, dx, dy, 0);
4976             } else {
4977                 o.style.filter = E;
4978                 setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate);
4979             }
4980         } else {
4981             o.style.filter = E;
4982             skew.matrix = Str(matrix);
4983             skew.offset = matrix.offset();
4984         }
4985         oldt && (this._.transform = oldt);
4986         return this;
4987     };
4988     elproto.rotate = function (deg, cx, cy) {
4989         if (this.removed) {
4990             return this;
4991         }
4992         if (deg == null) {
4993             return;
4994         }
4995         deg = Str(deg).split(separator);
4996         if (deg.length - 1) {
4997             cx = toFloat(deg[1]);
4998             cy = toFloat(deg[2]);
4999         }
5000         deg = toFloat(deg[0]);
5001         (cy == null) && (cx = cy);
5002         if (cx == null || cy == null) {
5003             var bbox = this.getBBox(1);
5004             cx = bbox.x + bbox.width / 2;
5005             cy = bbox.y + bbox.height / 2;
5006         }
5007         this._.dirtyT = 1;
5008         this.transform(this._.transform.concat([["r", deg, cx, cy]]));
5009         return this;
5010     };
5011     elproto.translate = function (dx, dy) {
5012         if (this.removed) {
5013             return this;
5014         }
5015         dx = Str(dx).split(separator);
5016         if (dx.length - 1) {
5017             dy = toFloat(dx[1]);
5018         }
5019         dx = toFloat(dx[0]) || 0;
5020         dy = +dy || 0;
5021         if (this._.bbox) {
5022             this._.bbox.x += dx;
5023             this._.bbox.y += dy;
5024         }
5025         this.transform(this._.transform.concat([["t", dx, dy]]));
5026         return this;
5027     };
5028     elproto.scale = function (sx, sy, cx, cy) {
5029         if (this.removed) {
5030             return this;
5031         }
5032         sx = Str(sx).split(separator);
5033         if (sx.length - 1) {
5034             sy = toFloat(sx[1]);
5035             cx = toFloat(sx[2]);
5036             cy = toFloat(sx[3]);
5037             isNaN(cx) && (cx = null);
5038             isNaN(cy) && (cy = null);
5039         }
5040         sx = toFloat(sx[0]);
5041         (sy == null) && (sy = sx);
5042         (cy == null) && (cx = cy);
5043         if (cx == null || cy == null) {
5044             var bbox = this.getBBox(1);
5045         }
5046         cx = cx == null ? bbox.x + bbox.width / 2 : cx;
5047         cy = cy == null ? bbox.y + bbox.height / 2 : cy;
5048     
5049         this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
5050         this._.dirtyT = 1;
5051         return this;
5052     };
5053     elproto.hide = function () {
5054         !this.removed && (this.node.style.display = "none");
5055         return this;
5056     };
5057     elproto.show = function () {
5058         !this.removed && (this.node.style.display = E);
5059         return this;
5060     };
5061     elproto._getBBox = function () {
5062         if (this.removed) {
5063             return {};
5064         }
5065         return {
5066             x: this.X + (this.bbx || 0) - this.W / 2,
5067             y: this.Y - this.H,
5068             width: this.W,
5069             height: this.H
5070         };
5071     };
5072     elproto.remove = function () {
5073         if (this.removed) {
5074             return;
5075         }
5076         this.paper.__set__ && this.paper.__set__.exclude(this);
5077         R.eve.unbind("*.*." + this.id);
5078         R._tear(this, this.paper);
5079         this.node.parentNode.removeChild(this.node);
5080         this.shape && this.shape.parentNode.removeChild(this.shape);
5081         for (var i in this) {
5082             this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
5083         }
5084         this.removed = true;
5085     };
5086     elproto.attr = function (name, value) {
5087         if (this.removed) {
5088             return this;
5089         }
5090         if (name == null) {
5091             var res = {};
5092             for (var a in this.attrs) if (this.attrs[has](a)) {
5093                 res[a] = this.attrs[a];
5094             }
5095             res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
5096             res.transform = this._.transform;
5097             return res;
5098         }
5099         if (value == null && R.is(name, "string")) {
5100             if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) {
5101                 return this.attrs.gradient;
5102             }
5103             var names = name.split(separator),
5104                 out = {};
5105             for (var i = 0, ii = names.length; i < ii; i++) {
5106                 name = names[i];
5107                 if (name in this.attrs) {
5108                     out[name] = this.attrs[name];
5109                 } else if (R.is(this.paper.customAttributes[name], "function")) {
5110                     out[name] = this.paper.customAttributes[name].def;
5111                 } else {
5112                     out[name] = R._availableAttrs[name];
5113                 }
5114             }
5115             return ii - 1 ? out : out[names[0]];
5116         }
5117         if (this.attrs && value == null && R.is(name, "array")) {
5118             out = {};
5119             for (i = 0, ii = name.length; i < ii; i++) {
5120                 out[name[i]] = this.attr(name[i]);
5121             }
5122             return out;
5123         }
5124         var params;
5125         if (value != null) {
5126             params = {};
5127             params[name] = value;
5128         }
5129         value == null && R.is(name, "object") && (params = name);
5130         for (var key in params) {
5131             eve("attr." + key + "." + this.id, this, params[key]);
5132         }
5133         if (params) {
5134             for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
5135                 var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
5136                 this.attrs[key] = params[key];
5137                 for (var subkey in par) if (par[has](subkey)) {
5138                     params[subkey] = par[subkey];
5139                 }
5140             }
5141             // this.paper.canvas.style.display = "none";
5142             if (params.text && this.type == "text") {
5143                 this.textpath.string = params.text;
5144             }
5145             setFillAndStroke(this, params);
5146             // this.paper.canvas.style.display = E;
5147         }
5148         return this;
5149     };
5150     elproto.toFront = function () {
5151         !this.removed && this.node.parentNode.appendChild(this.node);
5152         this.paper && this.paper.top != this && R._tofront(this, this.paper);
5153         return this;
5154     };
5155     elproto.toBack = function () {
5156         if (this.removed) {
5157             return this;
5158         }
5159         if (this.node.parentNode.firstChild != this.node) {
5160             this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
5161             R._toback(this, this.paper);
5162         }
5163         return this;
5164     };
5165     elproto.insertAfter = function (element) {
5166         if (this.removed) {
5167             return this;
5168         }
5169         if (element.constructor == R.st.constructor) {
5170             element = element[element.length - 1];
5171         }
5172         if (element.node.nextSibling) {
5173             element.node.parentNode.insertBefore(this.node, element.node.nextSibling);
5174         } else {
5175             element.node.parentNode.appendChild(this.node);
5176         }
5177         R._insertafter(this, element, this.paper);
5178         return this;
5179     };
5180     elproto.insertBefore = function (element) {
5181         if (this.removed) {
5182             return this;
5183         }
5184         if (element.constructor == R.st.constructor) {
5185             element = element[0];
5186         }
5187         element.node.parentNode.insertBefore(this.node, element.node);
5188         R._insertbefore(this, element, this.paper);
5189         return this;
5190     };
5191     elproto.blur = function (size) {
5192         var s = this.node.runtimeStyle,
5193             f = s.filter;
5194         f = f.replace(blurregexp, E);
5195         if (+size !== 0) {
5196             this.attrs.blur = size;
5197             s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")";
5198             s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5));
5199         } else {
5200             s.filter = f;
5201             s.margin = 0;
5202             delete this.attrs.blur;
5203         }
5204     };
5205
5206     R._engine.path = function (pathString, vml) {
5207         var el = createNode("shape");
5208         el.style.cssText = cssDot;
5209         el.coordsize = zoom + S + zoom;
5210         el.coordorigin = vml.coordorigin;
5211         var p = new Element(el, vml),
5212             attr = {fill: "none", stroke: "#000"};
5213         pathString && (attr.path = pathString);
5214         p.type = "path";
5215         p.path = [];
5216         p.Path = E;
5217         setFillAndStroke(p, attr);
5218         vml.canvas.appendChild(el);
5219         var skew = createNode("skew");
5220         skew.on = true;
5221         el.appendChild(skew);
5222         p.skew = skew;
5223         p.transform(E);
5224         return p;
5225     };
5226     R._engine.rect = function (vml, x, y, w, h, r) {
5227         var path = R._rectPath(x, y, w, h, r),
5228             res = vml.path(path),
5229             a = res.attrs;
5230         res.X = a.x = x;
5231         res.Y = a.y = y;
5232         res.W = a.width = w;
5233         res.H = a.height = h;
5234         a.r = r;
5235         a.path = path;
5236         res.type = "rect";
5237         return res;
5238     };
5239     R._engine.ellipse = function (vml, x, y, rx, ry) {
5240         var res = vml.path(),
5241             a = res.attrs;
5242         res.X = x - rx;
5243         res.Y = y - ry;
5244         res.W = rx * 2;
5245         res.H = ry * 2;
5246         res.type = "ellipse";
5247         setFillAndStroke(res, {
5248             cx: x,
5249             cy: y,
5250             rx: rx,
5251             ry: ry
5252         });
5253         return res;
5254     };
5255     R._engine.circle = function (vml, x, y, r) {
5256         var res = vml.path(),
5257             a = res.attrs;
5258         res.X = x - r;
5259         res.Y = y - r;
5260         res.W = res.H = r * 2;
5261         res.type = "circle";
5262         setFillAndStroke(res, {
5263             cx: x,
5264             cy: y,
5265             r: r
5266         });
5267         return res;
5268     };
5269     R._engine.image = function (vml, src, x, y, w, h) {
5270         var path = R._rectPath(x, y, w, h),
5271             res = vml.path(path).attr({stroke: "none"}),
5272             a = res.attrs,
5273             node = res.node,
5274             fill = node.getElementsByTagName(fillString)[0];
5275         a.src = src;
5276         res.X = a.x = x;
5277         res.Y = a.y = y;
5278         res.W = a.width = w;
5279         res.H = a.height = h;
5280         a.path = path;
5281         res.type = "image";
5282         fill.parentNode == node && node.removeChild(fill);
5283         fill.rotate = true;
5284         fill.src = src;
5285         fill.type = "tile";
5286         res._.fillpos = [x, y];
5287         res._.fillsize = [w, h];
5288         node.appendChild(fill);
5289         setCoords(res, 1, 1, 0, 0, 0);
5290         return res;
5291     };
5292     R._engine.text = function (vml, x, y, text) {
5293         var el = createNode("shape"),
5294             path = createNode("path"),
5295             o = createNode("textpath");
5296         x = x || 0;
5297         y = y || 0;
5298         text = text || "";
5299         path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1);
5300         path.textpathok = true;
5301         o.string = Str(text);
5302         o.on = true;
5303         el.style.cssText = cssDot;
5304         el.coordsize = zoom + S + zoom;
5305         el.coordorigin = "0 0";
5306         var p = new Element(el, vml),
5307             attr = {
5308                 fill: "#000",
5309                 stroke: "none",
5310                 font: R._availableAttrs.font,
5311                 text: text
5312             };
5313         p.shape = el;
5314         p.path = path;
5315         p.textpath = o;
5316         p.type = "text";
5317         p.attrs.text = Str(text);
5318         p.attrs.x = x;
5319         p.attrs.y = y;
5320         p.attrs.w = 1;
5321         p.attrs.h = 1;
5322         setFillAndStroke(p, attr);
5323         el.appendChild(o);
5324         el.appendChild(path);
5325         vml.canvas.appendChild(el);
5326         var skew = createNode("skew");
5327         skew.on = true;
5328         el.appendChild(skew);
5329         p.skew = skew;
5330         p.transform(E);
5331         return p;
5332     };
5333     R._engine.setSize = function (width, height) {
5334         var cs = this.canvas.style;
5335         this.width = width;
5336         this.height = height;
5337         width == +width && (width += "px");
5338         height == +height && (height += "px");
5339         cs.width = width;
5340         cs.height = height;
5341         cs.clip = "rect(0 " + width + " " + height + " 0)";
5342         if (this._viewBox) {
5343             R._engine.setViewBox.apply(this, this._viewBox);
5344         }
5345         return this;
5346     };
5347     R._engine.setViewBox = function (x, y, w, h, fit) {
5348         R.eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]);
5349         var width = this.width,
5350             height = this.height,
5351             size = 1 / mmax(w / width, h / height),
5352             H, W;
5353         if (fit) {
5354             H = height / h;
5355             W = width / w;
5356             if (w * H < width) {
5357                 x -= (width - w * H) / 2 / H;
5358             }
5359             if (h * W < height) {
5360                 y -= (height - h * W) / 2 / W;
5361             }
5362         }
5363         this._viewBox = [x, y, w, h, !!fit];
5364         this._viewBoxShift = {
5365             dx: -x,
5366             dy: -y,
5367             scale: size
5368         };
5369         this.forEach(function (el) {
5370             el.transform("...");
5371         });
5372         return this;
5373     };
5374     var createNode;
5375     R._engine.initWin = function (win) {
5376             var doc = win.document;
5377             doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
5378             try {
5379                 !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
5380                 createNode = function (tagName) {
5381                     return doc.createElement('<rvml:' + tagName + ' class="rvml">');
5382                 };
5383             } catch (e) {
5384                 createNode = function (tagName) {
5385                     return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
5386                 };
5387             }
5388         };
5389     R._engine.initWin(R._g.win);
5390     R._engine.create = function () {
5391         var con = R._getContainer.apply(0, arguments),
5392             container = con.container,
5393             height = con.height,
5394             s,
5395             width = con.width,
5396             x = con.x,
5397             y = con.y;
5398         if (!container) {
5399             throw new Error("VML container not found.");
5400         }
5401         var res = new R._Paper,
5402             c = res.canvas = R._g.doc.createElement("div"),
5403             cs = c.style;
5404         x = x || 0;
5405         y = y || 0;
5406         width = width || 512;
5407         height = height || 342;
5408         res.width = width;
5409         res.height = height;
5410         width == +width && (width += "px");
5411         height == +height && (height += "px");
5412         res.coordsize = zoom * 1e3 + S + zoom * 1e3;
5413         res.coordorigin = "0 0";
5414         res.span = R._g.doc.createElement("span");
5415         res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;";
5416         c.appendChild(res.span);
5417         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);
5418         if (container == 1) {
5419             R._g.doc.body.appendChild(c);
5420             cs.left = x + "px";
5421             cs.top = y + "px";
5422             cs.position = "absolute";
5423         } else {
5424             if (container.firstChild) {
5425                 container.insertBefore(c, container.firstChild);
5426             } else {
5427                 container.appendChild(c);
5428             }
5429         }
5430         // plugins.call(res, res, R.fn);
5431         res.renderfix = function () {};
5432         return res;
5433     };
5434     R.prototype.clear = function () {
5435         R.eve("clear", this);
5436         this.canvas.innerHTML = E;
5437         this.span = R._g.doc.createElement("span");
5438         this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";
5439         this.canvas.appendChild(this.span);
5440         this.bottom = this.top = null;
5441     };
5442     R.prototype.remove = function () {
5443         R.eve("remove", this);
5444         this.canvas.parentNode.removeChild(this.canvas);
5445         for (var i in this) {
5446             this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
5447         }
5448         return true;
5449     };
5450
5451     var setproto = R.st;
5452     for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
5453         setproto[method] = (function (methodname) {
5454             return function () {
5455                 var arg = arguments;
5456                 return this.forEach(function (el) {
5457                     el[methodname].apply(el, arg);
5458                 });
5459             };
5460         })(method);
5461     }
5462 }(window.Raphael);