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