a26213f84182c70fdc532f0d30c93f01e123ce88
[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     for (var i = events.length; i--;) {
2024         (function (eventName) {
2025             R[eventName] = elproto[eventName] = function (fn, scope) {
2026                 if (R.is(fn, "function")) {
2027                     this.events = this.events || [];
2028                     this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)});
2029                 }
2030                 return this;
2031             };
2032             R["un" + eventName] = elproto["un" + eventName] = function (fn) {
2033                 var events = this.events,
2034                     l = events.length;
2035                 while (l--) if (events[l].name == eventName && events[l].f == fn) {
2036                     events[l].unbind();
2037                     events.splice(l, 1);
2038                     !events.length && delete this.events;
2039                     return this;
2040                 }
2041                 return this;
2042             };
2043         })(events[i]);
2044     }
2045     
2046     
2047     elproto.data = function (key, value) {
2048         var data = eldata[this.id] = eldata[this.id] || {};
2049         if (arguments.length == 1) {
2050             if (R.is(key, "object")) {
2051                 for (var i in key) if (key[has](i)) {
2052                     this.data(i, key[i]);
2053                 }
2054                 return this;
2055             }
2056             eve("data.get." + this.id, this, data[key], key);
2057             return data[key];
2058         }
2059         data[key] = value;
2060         eve("data.set." + this.id, this, value, key);
2061         return this;
2062     };
2063     
2064     elproto.removeData = function (key) {
2065         if (key == null) {
2066             eldata[this.id] = {};
2067         } else {
2068             eldata[this.id] && delete eldata[this.id][key];
2069         }
2070         return this;
2071     };
2072     
2073     elproto.hover = function (f_in, f_out, scope_in, scope_out) {
2074         return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
2075     };
2076     
2077     elproto.unhover = function (f_in, f_out) {
2078         return this.unmouseover(f_in).unmouseout(f_out);
2079     };
2080     var draggable = [];
2081     
2082     elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
2083         function start(e) {
2084             (e.originalEvent || e).preventDefault();
2085             var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop,
2086                 scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft;
2087             this._drag.x = e.clientX + scrollX;
2088             this._drag.y = e.clientY + scrollY;
2089             this._drag.id = e.identifier;
2090             !drag.length && R.mousemove(dragMove).mouseup(dragUp);
2091             drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope});
2092             onstart && eve.on("drag.start." + this.id, onstart);
2093             onmove && eve.on("drag.move." + this.id, onmove);
2094             onend && eve.on("drag.end." + this.id, onend);
2095             eve("drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e);
2096         }
2097         this._drag = {};
2098         draggable.push({el: this, start: start});
2099         this.mousedown(start);
2100         return this;
2101     };
2102     
2103     elproto.onDragOver = function (f) {
2104         f ? eve.on("drag.over." + this.id, f) : eve.unbind("drag.over." + this.id);
2105     };
2106     
2107     elproto.undrag = function () {
2108         var i = draggable.length;
2109         while (i--) if (draggable[i].el == this) {
2110             this.unmousedown(draggable[i].start);
2111             draggable.splice(i, 1);
2112             eve.unbind("drag.*." + this.id);
2113         }
2114         !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp);
2115     };
2116     
2117     paperproto.circle = function (x, y, r) {
2118         var out = R._engine.circle(this, x || 0, y || 0, r || 0);
2119         this.__set__ && this.__set__.push(out);
2120         return out;
2121     };
2122     
2123     paperproto.rect = function (x, y, w, h, r) {
2124         var out = R._engine.rect(this, x || 0, y || 0, w || 0, h || 0, r || 0);
2125         this.__set__ && this.__set__.push(out);
2126         return out;
2127     };
2128     
2129     paperproto.ellipse = function (x, y, rx, ry) {
2130         var out = R._engine.ellipse(this, x || 0, y || 0, rx || 0, ry || 0);
2131         this.__set__ && this.__set__.push(out);
2132         return out;
2133     };
2134     
2135     paperproto.path = function (pathString) {
2136         pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E);
2137         var out = R._engine.path(R.format[apply](R, arguments), this);
2138         this.__set__ && this.__set__.push(out);
2139         return out;
2140     };
2141     
2142     paperproto.image = function (src, x, y, w, h) {
2143         var out = R._engine.image(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0);
2144         this.__set__ && this.__set__.push(out);
2145         return out;
2146     };
2147     
2148     paperproto.text = function (x, y, text) {
2149         var out = R._engine.text(this, x || 0, y || 0, Str(text));
2150         this.__set__ && this.__set__.push(out);
2151         return out;
2152     };
2153     
2154     paperproto.set = function (itemsArray) {
2155         !R.is(itemsArray, "array") && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length));
2156         var out = new Set(itemsArray);
2157         this.__set__ && this.__set__.push(out);
2158         return out;
2159     };
2160     
2161     paperproto.setStart = function (set) {
2162         this.__set__ = set || this.set();
2163     };
2164     
2165     paperproto.setFinish = function (set) {
2166         var out = this.__set__;
2167         delete this.__set__;
2168         return out;
2169     };
2170     
2171     paperproto.setSize = function (width, height) {
2172         return R._engine.setSize.call(this, width, height);
2173     };
2174     
2175     paperproto.setViewBox = function (x, y, w, h, fit) {
2176         return R._engine.setViewBox.call(this, x, y, w, h, fit);
2177     };
2178     
2179     
2180     paperproto.top = paperproto.bottom = null;
2181     
2182     paperproto.raphael = R;
2183     var getOffset = function (elem) {
2184         var box = elem.getBoundingClientRect(),
2185             doc = elem.ownerDocument,
2186             body = doc.body,
2187             docElem = doc.documentElement,
2188             clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
2189             top  = box.top  + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop,
2190             left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
2191         return {
2192             y: top,
2193             x: left
2194         };
2195     };
2196     
2197     paperproto.getElementByPoint = function (x, y) {
2198         var paper = this,
2199             svg = paper.canvas,
2200             target = g.doc.elementFromPoint(x, y);
2201         if (g.win.opera && target.tagName == "svg") {
2202             var so = getOffset(svg),
2203                 sr = svg.createSVGRect();
2204             sr.x = x - so.x;
2205             sr.y = y - so.y;
2206             sr.width = sr.height = 1;
2207             var hits = svg.getIntersectionList(sr, null);
2208             if (hits.length) {
2209                 target = hits[hits.length - 1];
2210             }
2211         }
2212         if (!target) {
2213             return null;
2214         }
2215         while (target.parentNode && target != svg.parentNode && !target.raphael) {
2216             target = target.parentNode;
2217         }
2218         target == paper.canvas.parentNode && (target = svg);
2219         target = target && target.raphael ? paper.getById(target.raphaelid) : null;
2220         return target;
2221     };
2222     
2223     paperproto.getById = function (id) {
2224         var bot = this.bottom;
2225         while (bot) {
2226             if (bot.id == id) {
2227                 return bot;
2228             }
2229             bot = bot.next;
2230         }
2231         return null;
2232     };
2233     
2234     paperproto.forEach = function (callback, thisArg) {
2235         var bot = this.bottom;
2236         while (bot) {
2237             if (callback.call(thisArg, bot) === false) {
2238                 return this;
2239             }
2240             bot = bot.next;
2241         }
2242         return this;
2243     };
2244     function x_y() {
2245         return this.x + S + this.y;
2246     }
2247     function x_y_w_h() {
2248         return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
2249     }
2250     
2251     elproto.getBBox = function (isWithoutTransform) {
2252         if (this.removed) {
2253             return {};
2254         }
2255         var _ = this._;
2256         if (isWithoutTransform) {
2257             if (_.dirty || !_.bboxwt) {
2258                 this.realPath = getPath[this.type](this);
2259                 _.bboxwt = pathDimensions(this.realPath);
2260                 _.bboxwt.toString = x_y_w_h;
2261                 _.dirty = 0;
2262             }
2263             return _.bboxwt;
2264         }
2265         if (_.dirty || _.dirtyT || !_.bbox) {
2266             if (_.dirty || !this.realPath) {
2267                 _.bboxwt = 0;
2268                 this.realPath = getPath[this.type](this);
2269             }
2270             _.bbox = pathDimensions(mapPath(this.realPath, this.matrix));
2271             _.bbox.toString = x_y_w_h;
2272             _.dirty = _.dirtyT = 0;
2273         }
2274         return _.bbox;
2275     };
2276     
2277     elproto.clone = function () {
2278         if (this.removed) {
2279             return null;
2280         }
2281         var out = this.paper[this.type]().attr(this.attr());
2282         this.__set__ && this.__set__.push(out);
2283         return out;
2284     };
2285     
2286     elproto.glow = function (glow) {
2287         if (this.type == "text") {
2288             return null;
2289         }
2290         glow = glow || {};
2291         var s = {
2292             width: (glow.width || 10) + (+this.attr("stroke-width") || 1),
2293             fill: glow.fill || false,
2294             opacity: glow.opacity || .5,
2295             offsetx: glow.offsetx || 0,
2296             offsety: glow.offsety || 0,
2297             color: glow.color || "#000"
2298         },
2299             c = s.width / 2,
2300             r = this.paper,
2301             out = r.set(),
2302             path = this.realPath || getPath[this.type](this);
2303         path = this.matrix ? mapPath(path, this.matrix) : path;
2304         for (var i = 1; i < c + 1; i++) {
2305             out.push(r.path(path).attr({
2306                 stroke: s.color,
2307                 fill: s.fill ? s.color : "none",
2308                 "stroke-linejoin": "round",
2309                 "stroke-linecap": "round",
2310                 "stroke-width": +(s.width / c * i).toFixed(3),
2311                 opacity: +(s.opacity / c).toFixed(3)
2312             }));
2313         }
2314         return out.insertBefore(this).translate(s.offsetx, s.offsety);
2315     };
2316     var curveslengths = {},
2317     getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {
2318         var len = 0,
2319             precision = 100,
2320             name = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y].join(),
2321             cache = curveslengths[name],
2322             old, dot;
2323         !cache && (curveslengths[name] = cache = {data: []});
2324         cache.timer && clearTimeout(cache.timer);
2325         cache.timer = setTimeout(function () {delete curveslengths[name];}, 2e3);
2326         if (length != null && !cache.precision) {
2327             var total = getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
2328             cache.precision = ~~total * 10;
2329             cache.data = [];
2330         }
2331         precision = cache.precision || precision;
2332         for (var i = 0; i < precision + 1; i++) {
2333             if (cache.data[i * precision]) {
2334                 dot = cache.data[i * precision];
2335             } else {
2336                 dot = R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i / precision);
2337                 cache.data[i * precision] = dot;
2338             }
2339             i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5));
2340             if (length != null && len >= length) {
2341                 return dot;
2342             }
2343             old = dot;
2344         }
2345         if (length == null) {
2346             return len;
2347         }
2348     },
2349     getLengthFactory = function (istotal, subpath) {
2350         return function (path, length, onlystart) {
2351             path = path2curve(path);
2352             var x, y, p, l, sp = "", subpaths = {}, point,
2353                 len = 0;
2354             for (var i = 0, ii = path.length; i < ii; i++) {
2355                 p = path[i];
2356                 if (p[0] == "M") {
2357                     x = +p[1];
2358                     y = +p[2];
2359                 } else {
2360                     l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
2361                     if (len + l > length) {
2362                         if (subpath && !subpaths.start) {
2363                             point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
2364                             sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y];
2365                             if (onlystart) {return sp;}
2366                             subpaths.start = sp;
2367                             sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join();
2368                             len += l;
2369                             x = +p[5];
2370                             y = +p[6];
2371                             continue;
2372                         }
2373                         if (!istotal && !subpath) {
2374                             point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
2375                             return {x: point.x, y: point.y, alpha: point.alpha};
2376                         }
2377                     }
2378                     len += l;
2379                     x = +p[5];
2380                     y = +p[6];
2381                 }
2382                 sp += p.shift() + p;
2383             }
2384             subpaths.end = sp;
2385             point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
2386             point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha});
2387             return point;
2388         };
2389     };
2390     var getTotalLength = getLengthFactory(1),
2391         getPointAtLength = getLengthFactory(),
2392         getSubpathsAtLength = getLengthFactory(0, 1);
2393     
2394     R.getTotalLength = getTotalLength;
2395     
2396     R.getPointAtLength = getPointAtLength;
2397     
2398     R.getSubpath = function (path, from, to) {
2399         if (this.getTotalLength(path) - to < 1e-6) {
2400             return getSubpathsAtLength(path, from).end;
2401         }
2402         var a = getSubpathsAtLength(path, to, 1);
2403         return from ? getSubpathsAtLength(a, from).end : a;
2404     };
2405     
2406     elproto.getTotalLength = function () {
2407         if (this.type != "path") {return;}
2408         if (this.node.getTotalLength) {
2409             return this.node.getTotalLength();
2410         }
2411         return getTotalLength(this.attrs.path);
2412     };
2413     
2414     elproto.getPointAtLength = function (length) {
2415         if (this.type != "path") {return;}
2416         return getPointAtLength(this.attrs.path, length);
2417     };
2418     
2419     elproto.getSubpath = function (from, to) {
2420         if (this.type != "path") {return;}
2421         return R.getSubpath(this.attrs.path, from, to);
2422     };
2423     
2424     var ef = R.easing_formulas = {
2425         linear: function (n) {
2426             return n;
2427         },
2428         "<": function (n) {
2429             return pow(n, 1.7);
2430         },
2431         ">": function (n) {
2432             return pow(n, .48);
2433         },
2434         "<>": function (n) {
2435             var q = .48 - n / 1.04,
2436                 Q = math.sqrt(.1734 + q * q),
2437                 x = Q - q,
2438                 X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1),
2439                 y = -Q - q,
2440                 Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1),
2441                 t = X + Y + .5;
2442             return (1 - t) * 3 * t * t + t * t * t;
2443         },
2444         backIn: function (n) {
2445             var s = 1.70158;
2446             return n * n * ((s + 1) * n - s);
2447         },
2448         backOut: function (n) {
2449             n = n - 1;
2450             var s = 1.70158;
2451             return n * n * ((s + 1) * n + s) + 1;
2452         },
2453         elastic: function (n) {
2454             if (n == !!n) {
2455                 return n;
2456             }
2457             return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1;
2458         },
2459         bounce: function (n) {
2460             var s = 7.5625,
2461                 p = 2.75,
2462                 l;
2463             if (n < (1 / p)) {
2464                 l = s * n * n;
2465             } else {
2466                 if (n < (2 / p)) {
2467                     n -= (1.5 / p);
2468                     l = s * n * n + .75;
2469                 } else {
2470                     if (n < (2.5 / p)) {
2471                         n -= (2.25 / p);
2472                         l = s * n * n + .9375;
2473                     } else {
2474                         n -= (2.625 / p);
2475                         l = s * n * n + .984375;
2476                     }
2477                 }
2478             }
2479             return l;
2480         }
2481     };
2482     ef.easeIn = ef["ease-in"] = ef["<"];
2483     ef.easeOut = ef["ease-out"] = ef[">"];
2484     ef.easeInOut = ef["ease-in-out"] = ef["<>"];
2485     ef["back-in"] = ef.backIn;
2486     ef["back-out"] = ef.backOut;
2487
2488     var animationElements = [],
2489         requestAnimFrame = window.requestAnimationFrame       ||
2490                            window.webkitRequestAnimationFrame ||
2491                            window.mozRequestAnimationFrame    ||
2492                            window.oRequestAnimationFrame      ||
2493                            window.msRequestAnimationFrame     ||
2494                            function (callback) {
2495                                setTimeout(callback, 16);
2496                            },
2497         animation = function () {
2498             var Now = +new Date,
2499                 l = 0;
2500             for (; l < animationElements.length; l++) {
2501                 var e = animationElements[l];
2502                 if (e.el.removed || e.paused) {
2503                     continue;
2504                 }
2505                 var time = Now - e.start,
2506                     ms = e.ms,
2507                     easing = e.easing,
2508                     from = e.from,
2509                     diff = e.diff,
2510                     to = e.to,
2511                     t = e.t,
2512                     that = e.el,
2513                     set = {},
2514                     now,
2515                     init = {},
2516                     key;
2517                 if (e.initstatus) {
2518                     time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms;
2519                     e.status = e.initstatus;
2520                     delete e.initstatus;
2521                     e.stop && animationElements.splice(l--, 1);
2522                 } else {
2523                     e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top;
2524                 }
2525                 if (time < 0) {
2526                     continue;
2527                 }
2528                 if (time < ms) {
2529                     var pos = easing(time / ms);
2530                     for (var attr in from) if (from[has](attr)) {
2531                         switch (availableAnimAttrs[attr]) {
2532                             case nu:
2533                                 now = +from[attr] + pos * ms * diff[attr];
2534                                 break;
2535                             case "colour":
2536                                 now = "rgb(" + [
2537                                     upto255(round(from[attr].r + pos * ms * diff[attr].r)),
2538                                     upto255(round(from[attr].g + pos * ms * diff[attr].g)),
2539                                     upto255(round(from[attr].b + pos * ms * diff[attr].b))
2540                                 ].join(",") + ")";
2541                                 break;
2542                             case "path":
2543                                 now = [];
2544                                 for (var i = 0, ii = from[attr].length; i < ii; i++) {
2545                                     now[i] = [from[attr][i][0]];
2546                                     for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
2547                                         now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j];
2548                                     }
2549                                     now[i] = now[i].join(S);
2550                                 }
2551                                 now = now.join(S);
2552                                 break;
2553                             case "transform":
2554                                 if (diff[attr].real) {
2555                                     now = [];
2556                                     for (i = 0, ii = from[attr].length; i < ii; i++) {
2557                                         now[i] = [from[attr][i][0]];
2558                                         for (j = 1, jj = from[attr][i].length; j < jj; j++) {
2559                                             now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j];
2560                                         }
2561                                     }
2562                                 } else {
2563                                     var get = function (i) {
2564                                         return +from[attr][i] + pos * ms * diff[attr][i];
2565                                     };
2566                                     // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]];
2567                                     now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]];
2568                                 }
2569                                 break;
2570                             case "csv":
2571                                 if (attr == "clip-rect") {
2572                                     now = [];
2573                                     i = 4;
2574                                     while (i--) {
2575                                         now[i] = +from[attr][i] + pos * ms * diff[attr][i];
2576                                     }
2577                                 }
2578                                 break;
2579                             default:
2580                                 var from2 = [][concat](from[attr]);
2581                                 now = [];
2582                                 i = that.paper.customAttributes[attr].length;
2583                                 while (i--) {
2584                                     now[i] = +from2[i] + pos * ms * diff[attr][i];
2585                                 }
2586                                 break;
2587                         }
2588                         set[attr] = now;
2589                     }
2590                     that.attr(set);
2591                     (function (id, that, anim) {
2592                         setTimeout(function () {
2593                             eve("anim.frame." + id, that, anim);
2594                         });
2595                     })(that.id, that, e.anim);
2596                 } else {
2597                     (function(f, el, a) {
2598                         setTimeout(function() {
2599                             eve("anim.frame." + el.id, el, a);
2600                             eve("anim.finish." + el.id, el, a);
2601                             R.is(f, "function") && f.call(el);
2602                         });
2603                     })(e.callback, that, e.anim);
2604                     that.attr(to);
2605                     animationElements.splice(l--, 1);
2606                     if (e.repeat > 1 && !e.next) {
2607                         for (key in to) if (to[has](key)) {
2608                             init[key] = e.totalOrigin[key];
2609                         }
2610                         e.el.attr(init);
2611                         runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1);
2612                     }
2613                     if (e.next && !e.stop) {
2614                         runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat);
2615                     }
2616                 }
2617             }
2618             R.svg && that && that.paper && that.paper.safari();
2619             animationElements.length && requestAnimFrame(animation);
2620         },
2621         upto255 = function (color) {
2622             return color > 255 ? 255 : color < 0 ? 0 : color;
2623         };
2624     
2625     elproto.animateWith = function (element, anim, params, ms, easing, callback) {
2626         var a = params ? R.animation(params, ms, easing, callback) : anim,
2627             status = element.status(anim);
2628         return this.animate(a).status(a, status * anim.ms / a.ms);
2629     };
2630     function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) {
2631         var cx = 3 * p1x,
2632             bx = 3 * (p2x - p1x) - cx,
2633             ax = 1 - cx - bx,
2634             cy = 3 * p1y,
2635             by = 3 * (p2y - p1y) - cy,
2636             ay = 1 - cy - by;
2637         function sampleCurveX(t) {
2638             return ((ax * t + bx) * t + cx) * t;
2639         }
2640         function solve(x, epsilon) {
2641             var t = solveCurveX(x, epsilon);
2642             return ((ay * t + by) * t + cy) * t;
2643         }
2644         function solveCurveX(x, epsilon) {
2645             var t0, t1, t2, x2, d2, i;
2646             for(t2 = x, i = 0; i < 8; i++) {
2647                 x2 = sampleCurveX(t2) - x;
2648                 if (abs(x2) < epsilon) {
2649                     return t2;
2650                 }
2651                 d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
2652                 if (abs(d2) < 1e-6) {
2653                     break;
2654                 }
2655                 t2 = t2 - x2 / d2;
2656             }
2657             t0 = 0;
2658             t1 = 1;
2659             t2 = x;
2660             if (t2 < t0) {
2661                 return t0;
2662             }
2663             if (t2 > t1) {
2664                 return t1;
2665             }
2666             while (t0 < t1) {
2667                 x2 = sampleCurveX(t2);
2668                 if (abs(x2 - x) < epsilon) {
2669                     return t2;
2670                 }
2671                 if (x > x2) {
2672                     t0 = t2;
2673                 } else {
2674                     t1 = t2;
2675                 }
2676                 t2 = (t1 - t0) / 2 + t0;
2677             }
2678             return t2;
2679         }
2680         return solve(t, 1 / (200 * duration));
2681     }
2682     elproto.onAnimation = function (f) {
2683         f ? eve.on("anim.frame." + this.id, f) : eve.unbind("anim.frame." + this.id);
2684         return this;
2685     };
2686     function Animation(anim, ms) {
2687         var percents = [],
2688             newAnim = {};
2689         this.ms = ms;
2690         this.times = 1;
2691         if (anim) {
2692             for (var attr in anim) if (anim[has](attr)) {
2693                 newAnim[toFloat(attr)] = anim[attr];
2694                 percents.push(toFloat(attr));
2695             }
2696             percents.sort(sortByNumber);
2697         }
2698         this.anim = newAnim;
2699         this.top = percents[percents.length - 1];
2700         this.percents = percents;
2701     }
2702     
2703     Animation.prototype.delay = function (delay) {
2704         var a = new Animation(this.anim, this.ms);
2705         a.times = this.times;
2706         a.del = +delay || 0;
2707         return a;
2708     };
2709     
2710     Animation.prototype.repeat = function (times) { 
2711         var a = new Animation(this.anim, this.ms);
2712         a.del = this.del;
2713         a.times = math.floor(mmax(times, 0)) || 1;
2714         return a;
2715     };
2716     function runAnimation(anim, element, percent, status, totalOrigin, times) {
2717         percent = toFloat(percent);
2718         var params,
2719             isInAnim,
2720             isInAnimSet,
2721             percents = [],
2722             next,
2723             prev,
2724             timestamp,
2725             ms = anim.ms,
2726             from = {},
2727             to = {},
2728             diff = {};
2729         if (status) {
2730             for (i = 0, ii = animationElements.length; i < ii; i++) {
2731                 var e = animationElements[i];
2732                 if (e.el.id == element.id && e.anim == anim) {
2733                     if (e.percent != percent) {
2734                         animationElements.splice(i, 1);
2735                         isInAnimSet = 1;
2736                     } else {
2737                         isInAnim = e;
2738                     }
2739                     element.attr(e.totalOrigin);
2740                     break;
2741                 }
2742             }
2743         } else {
2744             status = +to; // NaN
2745         }
2746         for (var i = 0, ii = anim.percents.length; i < ii; i++) {
2747             if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) {
2748                 percent = anim.percents[i];
2749                 prev = anim.percents[i - 1] || 0;
2750                 ms = ms / anim.top * (percent - prev);
2751                 next = anim.percents[i + 1];
2752                 params = anim.anim[percent];
2753                 break;
2754             } else if (status) {
2755                 element.attr(anim.anim[anim.percents[i]]);
2756             }
2757         }
2758         if (!params) {
2759             return;
2760         }
2761         if (!isInAnim) {
2762             for (var attr in params) if (params[has](attr)) {
2763                 if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) {
2764                     from[attr] = element.attr(attr);
2765                     (from[attr] == null) && (from[attr] = availableAttrs[attr]);
2766                     to[attr] = params[attr];
2767                     switch (availableAnimAttrs[attr]) {
2768                         case nu:
2769                             diff[attr] = (to[attr] - from[attr]) / ms;
2770                             break;
2771                         case "colour":
2772                             from[attr] = R.getRGB(from[attr]);
2773                             var toColour = R.getRGB(to[attr]);
2774                             diff[attr] = {
2775                                 r: (toColour.r - from[attr].r) / ms,
2776                                 g: (toColour.g - from[attr].g) / ms,
2777                                 b: (toColour.b - from[attr].b) / ms
2778                             };
2779                             break;
2780                         case "path":
2781                             var pathes = path2curve(from[attr], to[attr]),
2782                                 toPath = pathes[1];
2783                             from[attr] = pathes[0];
2784                             diff[attr] = [];
2785                             for (i = 0, ii = from[attr].length; i < ii; i++) {
2786                                 diff[attr][i] = [0];
2787                                 for (var j = 1, jj = from[attr][i].length; j < jj; j++) {
2788                                     diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms;
2789                                 }
2790                             }
2791                             break;
2792                         case "transform":
2793                             var _ = element._,
2794                                 eq = equaliseTransform(_[attr], to[attr]);
2795                             if (eq) {
2796                                 from[attr] = eq.from;
2797                                 to[attr] = eq.to;
2798                                 diff[attr] = [];
2799                                 diff[attr].real = true;
2800                                 for (i = 0, ii = from[attr].length; i < ii; i++) {
2801                                     diff[attr][i] = [from[attr][i][0]];
2802                                     for (j = 1, jj = from[attr][i].length; j < jj; j++) {
2803                                         diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms;
2804                                     }
2805                                 }
2806                             } else {
2807                                 var m = (element.matrix || new Matrix),
2808                                     to2 = {
2809                                         _: {transform: _.transform},
2810                                         getBBox: function () {
2811                                             return element.getBBox(1);
2812                                         }
2813                                     };
2814                                 from[attr] = [
2815                                     m.a,
2816                                     m.b,
2817                                     m.c,
2818                                     m.d,
2819                                     m.e,
2820                                     m.f
2821                                 ];
2822                                 extractTransform(to2, to[attr]);
2823                                 to[attr] = to2._.transform;
2824                                 diff[attr] = [
2825                                     (to2.matrix.a - m.a) / ms,
2826                                     (to2.matrix.b - m.b) / ms,
2827                                     (to2.matrix.c - m.c) / ms,
2828                                     (to2.matrix.d - m.d) / ms,
2829                                     (to2.matrix.e - m.e) / ms,
2830                                     (to2.matrix.e - m.f) / ms
2831                                 ];
2832                                 // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy];
2833                                 // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }};
2834                                 // extractTransform(to2, to[attr]);
2835                                 // diff[attr] = [
2836                                 //     (to2._.sx - _.sx) / ms,
2837                                 //     (to2._.sy - _.sy) / ms,
2838                                 //     (to2._.deg - _.deg) / ms,
2839                                 //     (to2._.dx - _.dx) / ms,
2840                                 //     (to2._.dy - _.dy) / ms
2841                                 // ];
2842                             }
2843                             break;
2844                         case "csv":
2845                             var values = Str(params[attr])[split](separator),
2846                                 from2 = Str(from[attr])[split](separator);
2847                             if (attr == "clip-rect") {
2848                                 from[attr] = from2;
2849                                 diff[attr] = [];
2850                                 i = from2.length;
2851                                 while (i--) {
2852                                     diff[attr][i] = (values[i] - from[attr][i]) / ms;
2853                                 }
2854                             }
2855                             to[attr] = values;
2856                             break;
2857                         default:
2858                             values = [][concat](params[attr]);
2859                             from2 = [][concat](from[attr]);
2860                             diff[attr] = [];
2861                             i = element.paper.customAttributes[attr].length;
2862                             while (i--) {
2863                                 diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms;
2864                             }
2865                             break;
2866                     }
2867                 }
2868             }
2869             var easing = params.easing,
2870                 easyeasy = R.easing_formulas[easing];
2871             if (!easyeasy) {
2872                 easyeasy = Str(easing).match(bezierrg);
2873                 if (easyeasy && easyeasy.length == 5) {
2874                     var curve = easyeasy;
2875                     easyeasy = function (t) {
2876                         return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms);
2877                     };
2878                 } else {
2879                     easyeasy = pipe;
2880                 }
2881             }
2882             timestamp = params.start || anim.start || +new Date;
2883             e = {
2884                 anim: anim,
2885                 percent: percent,
2886                 timestamp: timestamp,
2887                 start: timestamp + (anim.del || 0),
2888                 status: 0,
2889                 initstatus: status || 0,
2890                 stop: false,
2891                 ms: ms,
2892                 easing: easyeasy,
2893                 from: from,
2894                 diff: diff,
2895                 to: to,
2896                 el: element,
2897                 callback: params.callback,
2898                 prev: prev,
2899                 next: next,
2900                 repeat: times || anim.times,
2901                 origin: element.attr(),
2902                 totalOrigin: totalOrigin
2903             };
2904             animationElements.push(e);
2905             if (status && !isInAnim && !isInAnimSet) {
2906                 e.stop = true;
2907                 e.start = new Date - ms * status;
2908                 if (animationElements.length == 1) {
2909                     return animation();
2910                 }
2911             }
2912             if (isInAnimSet) {
2913                 e.start = new Date - e.ms * status;
2914             }
2915             animationElements.length == 1 && requestAnimFrame(animation);
2916         } else {
2917             isInAnim.initstatus = status;
2918             isInAnim.start = new Date - isInAnim.ms * status;
2919         }
2920         eve("anim.start." + element.id, element, anim);
2921     }
2922     
2923     R.animation = function (params, ms, easing, callback) {
2924         if (params instanceof Animation) {
2925             return params;
2926         }
2927         if (R.is(easing, "function") || !easing) {
2928             callback = callback || easing || null;
2929             easing = null;
2930         }
2931         params = Object(params);
2932         ms = +ms || 0;
2933         var p = {},
2934             json,
2935             attr;
2936         for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) {
2937             json = true;
2938             p[attr] = params[attr];
2939         }
2940         if (!json) {
2941             return new Animation(params, ms);
2942         } else {
2943             easing && (p.easing = easing);
2944             callback && (p.callback = callback);
2945             return new Animation({100: p}, ms);
2946         }
2947     };
2948     
2949     elproto.animate = function (params, ms, easing, callback) {
2950         var element = this;
2951         if (element.removed) {
2952             callback && callback.call(element);
2953             return element;
2954         }
2955         var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback);
2956         runAnimation(anim, element, anim.percents[0], null, element.attr());
2957         return element;
2958     };
2959     
2960     elproto.setTime = function (anim, value) {
2961         if (anim && value != null) {
2962             this.status(anim, mmin(value, anim.ms) / anim.ms);
2963         }
2964         return this;
2965     };
2966     
2967     elproto.status = function (anim, value) {
2968         var out = [],
2969             i = 0,
2970             len,
2971             e;
2972         if (value != null) {
2973             runAnimation(anim, this, -1, mmin(value, 1));
2974             return this;
2975         } else {
2976             len = animationElements.length;
2977             for (; i < len; i++) {
2978                 e = animationElements[i];
2979                 if (e.el.id == this.id && (!anim || e.anim == anim)) {
2980                     if (anim) {
2981                         return e.status;
2982                     }
2983                     out.push({
2984                         anim: e.anim,
2985                         status: e.status
2986                     });
2987                 }
2988             }
2989             if (anim) {
2990                 return 0;
2991             }
2992             return out;
2993         }
2994     };
2995     
2996     elproto.pause = function (anim) {
2997         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
2998             if (eve("anim.pause." + this.id, this, animationElements[i].anim) !== false) {
2999                 animationElements[i].paused = true;
3000             }
3001         }
3002         return this;
3003     };
3004     
3005     elproto.resume = function (anim) {
3006         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
3007             var e = animationElements[i];
3008             if (eve("anim.resume." + this.id, this, e.anim) !== false) {
3009                 delete e.paused;
3010                 this.status(e.anim, e.status);
3011             }
3012         }
3013         return this;
3014     };
3015     
3016     elproto.stop = function (anim) {
3017         for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) {
3018             if (eve("anim.stop." + this.id, this, animationElements[i].anim) !== false) {
3019                 animationElements.splice(i--, 1);
3020             }
3021         }
3022         return this;
3023     };
3024     elproto.toString = function () {
3025         return "Rapha\xebl\u2019s object";
3026     };
3027
3028     // Set
3029     var Set = function (items) {
3030         this.items = [];
3031         this.length = 0;
3032         this.type = "set";
3033         if (items) {
3034             for (var i = 0, ii = items.length; i < ii; i++) {
3035                 if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) {
3036                     this[this.items.length] = this.items[this.items.length] = items[i];
3037                     this.length++;
3038                 }
3039             }
3040         }
3041     },
3042     setproto = Set.prototype;
3043     
3044     setproto.push = function () {
3045         var item,
3046             len;
3047         for (var i = 0, ii = arguments.length; i < ii; i++) {
3048             item = arguments[i];
3049             if (item && (item.constructor == elproto.constructor || item.constructor == Set)) {
3050                 len = this.items.length;
3051                 this[len] = this.items[len] = item;
3052                 this.length++;
3053             }
3054         }
3055         return this;
3056     };
3057     
3058     setproto.pop = function () {
3059         this.length && delete this[this.length--];
3060         return this.items.pop();
3061     };
3062     
3063     setproto.forEach = function (callback, thisArg) {
3064         for (var i = 0, ii = this.items.length; i < ii; i++) {
3065             if (callback.call(thisArg, this.items[i], i) === false) {
3066                 return this;
3067             }
3068         }
3069         return this;
3070     };
3071     for (var method in elproto) if (elproto[has](method)) {
3072         setproto[method] = (function (methodname) {
3073             return function () {
3074                 var arg = arguments;
3075                 return this.forEach(function (el) {
3076                     el[methodname][apply](el, arg);
3077                 });
3078             };
3079         })(method);
3080     }
3081     setproto.attr = function (name, value) {
3082         if (name && R.is(name, array) && R.is(name[0], "object")) {
3083             for (var j = 0, jj = name.length; j < jj; j++) {
3084                 this.items[j].attr(name[j]);
3085             }
3086         } else {
3087             for (var i = 0, ii = this.items.length; i < ii; i++) {
3088                 this.items[i].attr(name, value);
3089             }
3090         }
3091         return this;
3092     };
3093     
3094     setproto.clear = function () {
3095         while (this.length) {
3096             this.pop();
3097         }
3098     };
3099     
3100     setproto.splice = function (index, count, insertion) {
3101         index = index < 0 ? mmax(this.length + index, 0) : index;
3102         count = mmax(0, mmin(this.length - index, count));
3103         var tail = [],
3104             todel = [],
3105             args = [],
3106             i;
3107         for (i = 2; i < arguments.length; i++) {
3108             args.push(arguments[i]);
3109         }
3110         for (i = 0; i < count; i++) {
3111             todel.push(this[index + i]);
3112         }
3113         for (; i < this.length - index; i++) {
3114             tail.push(this[index + i]);
3115         }
3116         var arglen = args.length;
3117         for (i = 0; i < arglen + tail.length; i++) {
3118             this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen];
3119         }
3120         i = this.items.length = this.length -= count - arglen;
3121         while (this[i]) {
3122             delete this[i++];
3123         }
3124         return new Set(todel);
3125     };
3126     
3127     setproto.exclude = function (el) {
3128         for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) {
3129             this.splice(i, 1);
3130             return true;
3131         }
3132     };
3133     setproto.animate = function (params, ms, easing, callback) {
3134         (R.is(easing, "function") || !easing) && (callback = easing || null);
3135         var len = this.items.length,
3136             i = len,
3137             item,
3138             set = this,
3139             collector;
3140         if (!len) {
3141             return this;
3142         }
3143         callback && (collector = function () {
3144             !--len && callback.call(set);
3145         });
3146         easing = R.is(easing, string) ? easing : collector;
3147         var anim = R.animation(params, ms, easing, collector);
3148         item = this.items[--i].animate(anim);
3149         while (i--) {
3150             this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim);
3151         }
3152         return this;
3153     };
3154     setproto.insertAfter = function (el) {
3155         var i = this.items.length;
3156         while (i--) {
3157             this.items[i].insertAfter(el);
3158         }
3159         return this;
3160     };
3161     setproto.getBBox = function () {
3162         var x = [],
3163             y = [],
3164             w = [],
3165             h = [];
3166         for (var i = this.items.length; i--;) if (!this.items[i].removed) {
3167             var box = this.items[i].getBBox();
3168             x.push(box.x);
3169             y.push(box.y);
3170             w.push(box.x + box.width);
3171             h.push(box.y + box.height);
3172         }
3173         x = mmin[apply](0, x);
3174         y = mmin[apply](0, y);
3175         return {
3176             x: x,
3177             y: y,
3178             width: mmax[apply](0, w) - x,
3179             height: mmax[apply](0, h) - y
3180         };
3181     };
3182     setproto.clone = function (s) {
3183         s = new Set;
3184         for (var i = 0, ii = this.items.length; i < ii; i++) {
3185             s.push(this.items[i].clone());
3186         }
3187         return s;
3188     };
3189     setproto.toString = function () {
3190         return "Rapha\xebl\u2018s set";
3191     };
3192
3193     
3194     R.registerFont = function (font) {
3195         if (!font.face) {
3196             return font;
3197         }
3198         this.fonts = this.fonts || {};
3199         var fontcopy = {
3200                 w: font.w,
3201                 face: {},
3202                 glyphs: {}
3203             },
3204             family = font.face["font-family"];
3205         for (var prop in font.face) if (font.face[has](prop)) {
3206             fontcopy.face[prop] = font.face[prop];
3207         }
3208         if (this.fonts[family]) {
3209             this.fonts[family].push(fontcopy);
3210         } else {
3211             this.fonts[family] = [fontcopy];
3212         }
3213         if (!font.svg) {
3214             fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10);
3215             for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) {
3216                 var path = font.glyphs[glyph];
3217                 fontcopy.glyphs[glyph] = {
3218                     w: path.w,
3219                     k: {},
3220                     d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) {
3221                             return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M";
3222                         }) + "z"
3223                 };
3224                 if (path.k) {
3225                     for (var k in path.k) if (path[has](k)) {
3226                         fontcopy.glyphs[glyph].k[k] = path.k[k];
3227                     }
3228                 }
3229             }
3230         }
3231         return font;
3232     };
3233     
3234     paperproto.getFont = function (family, weight, style, stretch) {
3235         stretch = stretch || "normal";
3236         style = style || "normal";
3237         weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400;
3238         if (!R.fonts) {
3239             return;
3240         }
3241         var font = R.fonts[family];
3242         if (!font) {
3243             var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i");
3244             for (var fontName in R.fonts) if (R.fonts[has](fontName)) {
3245                 if (name.test(fontName)) {
3246                     font = R.fonts[fontName];
3247                     break;
3248                 }
3249             }
3250         }
3251         var thefont;
3252         if (font) {
3253             for (var i = 0, ii = font.length; i < ii; i++) {
3254                 thefont = font[i];
3255                 if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) {
3256                     break;
3257                 }
3258             }
3259         }
3260         return thefont;
3261     };
3262     
3263     paperproto.print = function (x, y, string, font, size, origin, letter_spacing) {
3264         origin = origin || "middle"; // baseline|middle
3265         letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1);
3266         var out = this.set(),
3267             letters = Str(string)[split](E),
3268             shift = 0,
3269             path = E,
3270             scale;
3271         R.is(font, string) && (font = this.getFont(font));
3272         if (font) {
3273             scale = (size || 16) / font.face["units-per-em"];
3274             var bb = font.face.bbox[split](separator),
3275                 top = +bb[0],
3276                 height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2);
3277             for (var i = 0, ii = letters.length; i < ii; i++) {
3278                 var prev = i && font.glyphs[letters[i - 1]] || {},
3279                     curr = font.glyphs[letters[i]];
3280                 shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0;
3281                 curr && curr.d && out.push(this.path(curr.d).attr({
3282                     fill: "#000",
3283                     stroke: "none",
3284                     transform: [["t", shift * scale, 0]]
3285                 }));
3286             }
3287             out.transform(["...s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]);
3288         }
3289         return out;
3290     };
3291
3292     
3293     paperproto.add = function (json) {
3294         if (R.is(json, "array")) {
3295             var res = this.set(),
3296                 i = 0,
3297                 ii = json.length,
3298                 j;
3299             for (; i < ii; i++) {
3300                 j = json[i] || {};
3301                 elements[has](j.type) && res.push(this[j.type]().attr(j));
3302             }
3303         }
3304         return res;
3305     };
3306
3307     
3308     R.format = function (token, params) {
3309         var args = R.is(params, array) ? [0][concat](params) : arguments;
3310         token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) {
3311             return args[++i] == null ? E : args[i];
3312         }));
3313         return token || E;
3314     };
3315     
3316     R.fullfill = (function () {
3317         var tokenRegex = /\{([^\}]+)\}/g,
3318             objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
3319             replacer = function (all, key, obj) {
3320                 var res = obj;
3321                 key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
3322                     name = name || quotedName;
3323                     if (res) {
3324                         if (name in res) {
3325                             res = res[name];
3326                         }
3327                         typeof res == "function" && isFunc && (res = res());
3328                     }
3329                 });
3330                 res = (res == null || res == obj ? all : res) + "";
3331                 return res;
3332             };
3333         return function (str, obj) {
3334             return String(str).replace(tokenRegex, function (all, key) {
3335                 return replacer(all, key, obj);
3336             });
3337         };
3338     })();
3339     
3340     R.ninja = function () {
3341         oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael;
3342         return R;
3343     };
3344     
3345     R.st = setproto;
3346     // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
3347     (function (doc, loaded, f) {
3348         if (doc.readyState == null && doc.addEventListener){
3349             doc.addEventListener(loaded, f = function () {
3350                 doc.removeEventListener(loaded, f, false);
3351                 doc.readyState = "complete";
3352             }, false);
3353             doc.readyState = "loading";
3354         }
3355         function isLoaded() {
3356             (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("DOMload");
3357         }
3358         isLoaded();
3359     })(document, "DOMContentLoaded");
3360
3361     oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R);
3362     
3363     eve.on("DOMload", function () {
3364         loaded = true;
3365     });
3366 })();
3367
3368
3369 // ┌─────────────────────────────────────────────────────────────────────┐ \\
3370 // │ Raphaël - JavaScript Vector Library                                 │ \\
3371 // ├─────────────────────────────────────────────────────────────────────┤ \\
3372 // │ SVG Module                                                          │ \\
3373 // ├─────────────────────────────────────────────────────────────────────┤ \\
3374 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
3375 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
3376 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
3377 // └─────────────────────────────────────────────────────────────────────┘ \\
3378 window.Raphael.svg && function (R) {
3379     var has = "hasOwnProperty",
3380         Str = String,
3381         toFloat = parseFloat,
3382         toInt = parseInt,
3383         math = Math,
3384         mmax = math.max,
3385         abs = math.abs,
3386         pow = math.pow,
3387         separator = /[, ]+/,
3388         eve = R.eve,
3389         E = "",
3390         S = " ";
3391     var xlink = "http://www.w3.org/1999/xlink",
3392         markers = {
3393             block: "M5,0 0,2.5 5,5z",
3394             classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z",
3395             diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z",
3396             open: "M6,1 1,3.5 6,6",
3397             oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"
3398         },
3399         markerCounter = {};
3400     R.toString = function () {
3401         return  "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version;
3402     };
3403     var $ = function (el, attr) {
3404         if (attr) {
3405             if (typeof el == "string") {
3406                 el = $(el);
3407             }
3408             for (var key in attr) if (attr[has](key)) {
3409                 if (key.substring(0, 6) == "xlink:") {
3410                     el.setAttributeNS(xlink, key.substring(6), Str(attr[key]));
3411                 } else {
3412                     el.setAttribute(key, Str(attr[key]));
3413                 }
3414             }
3415         } else {
3416             el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el);
3417             el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)");
3418         }
3419         return el;
3420     },
3421     addGradientFill = function (element, gradient) {
3422         var type = "linear",
3423             id = element.id + gradient,
3424             fx = .5, fy = .5,
3425             o = element.node,
3426             SVG = element.paper,
3427             s = o.style,
3428             el = R._g.doc.getElementById(id);
3429         if (!el) {
3430             gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) {
3431                 type = "radial";
3432                 if (_fx && _fy) {
3433                     fx = toFloat(_fx);
3434                     fy = toFloat(_fy);
3435                     var dir = ((fy > .5) * 2 - 1);
3436                     pow(fx - .5, 2) + pow(fy - .5, 2) > .25 &&
3437                         (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) &&
3438                         fy != .5 &&
3439                         (fy = fy.toFixed(5) - 1e-5 * dir);
3440                 }
3441                 return E;
3442             });
3443             gradient = gradient.split(/\s*\-\s*/);
3444             if (type == "linear") {
3445                 var angle = gradient.shift();
3446                 angle = -toFloat(angle);
3447                 if (isNaN(angle)) {
3448                     return null;
3449                 }
3450                 var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))],
3451                     max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1);
3452                 vector[2] *= max;
3453                 vector[3] *= max;
3454                 if (vector[2] < 0) {
3455                     vector[0] = -vector[2];
3456                     vector[2] = 0;
3457                 }
3458                 if (vector[3] < 0) {
3459                     vector[1] = -vector[3];
3460                     vector[3] = 0;
3461                 }
3462             }
3463             var dots = R._parseDots(gradient);
3464             if (!dots) {
3465                 return null;
3466             }
3467             id = id.replace(/[\(\)\s,\xb0#]/g, "_");
3468             
3469             if (element.gradient && id != element.gradient.id) {
3470                 SVG.defs.removeChild(element.gradient);
3471                 delete element.gradient;
3472             }
3473
3474             if (!element.gradient) {
3475                 el = $(type + "Gradient", {id: id});
3476                 element.gradient = el;
3477                 $(el, type == "radial" ? {
3478                     fx: fx,
3479                     fy: fy
3480                 } : {
3481                     x1: vector[0],
3482                     y1: vector[1],
3483                     x2: vector[2],
3484                     y2: vector[3],
3485                     gradientTransform: element.matrix.invert()
3486                 });
3487                 SVG.defs.appendChild(el);
3488                 for (var i = 0, ii = dots.length; i < ii; i++) {
3489                     el.appendChild($("stop", {
3490                         offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
3491                         "stop-color": dots[i].color || "#fff"
3492                     }));
3493                 }
3494             }
3495         }
3496         $(o, {
3497             fill: "url(#" + id + ")",
3498             opacity: 1,
3499             "fill-opacity": 1
3500         });
3501         s.fill = E;
3502         s.opacity = 1;
3503         s.fillOpacity = 1;
3504         return 1;
3505     },
3506     updatePosition = function (o) {
3507         var bbox = o.getBBox(1);
3508         $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"});
3509     },
3510     addArrow = function (o, value, isEnd) {
3511         if (o.type == "path") {
3512             var values = Str(value).toLowerCase().split("-"),
3513                 p = o.paper,
3514                 se = isEnd ? "end" : "start",
3515                 node = o.node,
3516                 attrs = o.attrs,
3517                 stroke = attrs["stroke-width"],
3518                 i = values.length,
3519                 type = "classic",
3520                 from,
3521                 to,
3522                 dx,
3523                 refX,
3524                 attr,
3525                 w = 3,
3526                 h = 3,
3527                 t = 5;
3528             while (i--) {
3529                 switch (values[i]) {
3530                     case "block":
3531                     case "classic":
3532                     case "oval":
3533                     case "diamond":
3534                     case "open":
3535                     case "none":
3536                         type = values[i];
3537                         break;
3538                     case "wide": h = 5; break;
3539                     case "narrow": h = 2; break;
3540                     case "long": w = 5; break;
3541                     case "short": w = 2; break;
3542                 }
3543             }
3544             if (type == "open") {
3545                 w += 2;
3546                 h += 2;
3547                 t += 2;
3548                 dx = 1;
3549                 refX = isEnd ? 4 : 1;
3550                 attr = {
3551                     fill: "none",
3552                     stroke: attrs.stroke
3553                 };
3554             } else {
3555                 refX = dx = w / 2;
3556                 attr = {
3557                     fill: attrs.stroke,
3558                     stroke: "none"
3559                 };
3560             }
3561             if (o._.arrows) {
3562                 if (isEnd) {
3563                     o._.arrows.endPath && markerCounter[o._.arrows.endPath]--;
3564                     o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--;
3565                 } else {
3566                     o._.arrows.startPath && markerCounter[o._.arrows.startPath]--;
3567                     o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--;
3568                 }
3569             } else {
3570                 o._.arrows = {};
3571             }
3572             if (type != "none") {
3573                 var pathId = "raphael-marker-" + type,
3574                     markerId = "raphael-marker-" + se + type + w + h;
3575                 if (!R._g.doc.getElementById(pathId)) {
3576                     p.defs.appendChild($($("path"), {
3577                         "stroke-linecap": "round",
3578                         d: markers[type],
3579                         id: pathId
3580                     }));
3581                     markerCounter[pathId] = 1;
3582                 } else {
3583                     markerCounter[pathId]++;
3584                 }
3585                 var marker = R._g.doc.getElementById(markerId),
3586                     use;
3587                 if (!marker) {
3588                     marker = $($("marker"), {
3589                         id: markerId,
3590                         markerHeight: h,
3591                         markerWidth: w,
3592                         orient: "auto",
3593                         refX: refX,
3594                         refY: h / 2
3595                     });
3596                     use = $($("use"), {
3597                         "xlink:href": "#" + pathId,
3598                         transform: (isEnd ? " rotate(180 " + w / 2 + " " + h / 2 + ") " : S) + "scale(" + w / t + "," + h / t + ")",
3599                         "stroke-width": 1 / ((w / t + h / t) / 2)
3600                     });
3601                     marker.appendChild(use);
3602                     p.defs.appendChild(marker);
3603                     markerCounter[markerId] = 1;
3604                 } else {
3605                     markerCounter[markerId]++;
3606                     use = marker.getElementsByTagName("use")[0];
3607                 }
3608                 $(use, attr);
3609                 var delta = dx * (type != "diamond" && type != "oval");
3610                 if (isEnd) {
3611                     from = o._.arrows.startdx * stroke || 0;
3612                     to = R.getTotalLength(attrs.path) - delta * stroke;
3613                 } else {
3614                     from = delta * stroke;
3615                     to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
3616                 }
3617                 attr = {};
3618                 attr["marker-" + se] = "url(#" + markerId + ")";
3619                 if (to || from) {
3620                     attr.d = Raphael.getSubpath(attrs.path, from, to);
3621                 }
3622                 $(node, attr);
3623                 o._.arrows[se + "Path"] = pathId;
3624                 o._.arrows[se + "Marker"] = markerId;
3625                 o._.arrows[se + "dx"] = delta;
3626                 o._.arrows[se + "Type"] = type;
3627                 o._.arrows[se + "String"] = value;
3628             } else {
3629                 if (isEnd) {
3630                     from = o._.arrows.startdx * stroke || 0;
3631                     to = R.getTotalLength(attrs.path) - from;
3632                 } else {
3633                     from = 0;
3634                     to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
3635                 }
3636                 o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)});
3637                 delete o._.arrows[se + "Path"];
3638                 delete o._.arrows[se + "Marker"];
3639                 delete o._.arrows[se + "dx"];
3640                 delete o._.arrows[se + "Type"];
3641                 delete o._.arrows[se + "String"];
3642             }
3643             for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) {
3644                 var item = R._g.doc.getElementById(attr);
3645                 item && item.parentNode.removeChild(item);
3646             }
3647         }
3648     },
3649     dasharray = {
3650         "": [0],
3651         "none": [0],
3652         "-": [3, 1],
3653         ".": [1, 1],
3654         "-.": [3, 1, 1, 1],
3655         "-..": [3, 1, 1, 1, 1, 1],
3656         ". ": [1, 3],
3657         "- ": [4, 3],
3658         "--": [8, 3],
3659         "- .": [4, 3, 1, 3],
3660         "--.": [8, 3, 1, 3],
3661         "--..": [8, 3, 1, 3, 1, 3]
3662     },
3663     addDashes = function (o, value, params) {
3664         value = dasharray[Str(value).toLowerCase()];
3665         if (value) {
3666             var width = o.attrs["stroke-width"] || "1",
3667                 butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
3668                 dashes = [],
3669                 i = value.length;
3670             while (i--) {
3671                 dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
3672             }
3673             $(o.node, {"stroke-dasharray": dashes.join(",")});
3674         }
3675     },
3676     setFillAndStroke = function (o, params) {
3677         var node = o.node,
3678             attrs = o.attrs,
3679             vis = node.style.visibility;
3680         node.style.visibility = "hidden";
3681         for (var att in params) {
3682             if (params[has](att)) {
3683                 if (!R._availableAttrs[has](att)) {
3684                     continue;
3685                 }
3686                 var value = params[att];
3687                 attrs[att] = value;
3688                 switch (att) {
3689                     case "blur":
3690                         o.blur(value);
3691                         break;
3692                     case "href":
3693                     case "title":
3694                     case "target":
3695                         var pn = node.parentNode;
3696                         if (pn.tagName.toLowerCase() != "a") {
3697                             var hl = $("a");
3698                             pn.insertBefore(hl, node);
3699                             hl.appendChild(node);
3700                             pn = hl;
3701                         }
3702                         if (att == "target" && value == "blank") {
3703                             pn.setAttributeNS(xlink, "show", "new");
3704                         } else {
3705                             pn.setAttributeNS(xlink, att, value);
3706                         }
3707                         break;
3708                     case "cursor":
3709                         node.style.cursor = value;
3710                         break;
3711                     case "transform":
3712                         o.transform(value);
3713                         break;
3714                     case "arrow-start":
3715                         addArrow(o, value);
3716                         break;
3717                     case "arrow-end":
3718                         addArrow(o, value, 1);
3719                         break;
3720                     case "clip-rect":
3721                         var rect = Str(value).split(separator);
3722                         if (rect.length == 4) {
3723                             o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
3724                             var el = $("clipPath"),
3725                                 rc = $("rect");
3726                             el.id = R.createUUID();
3727                             $(rc, {
3728                                 x: rect[0],
3729                                 y: rect[1],
3730                                 width: rect[2],
3731                                 height: rect[3]
3732                             });
3733                             el.appendChild(rc);
3734                             o.paper.defs.appendChild(el);
3735                             $(node, {"clip-path": "url(#" + el.id + ")"});
3736                             o.clip = rc;
3737                         }
3738                         if (!value) {
3739                             var path = node.getAttribute("clip-path");
3740                             if (path) {
3741                                 var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E));
3742                                 clip && clip.parentNode.removeChild(clip);
3743                                 $(node, {"clip-path": E});
3744                                 delete o.clip;
3745                             }
3746                         }
3747                     break;
3748                     case "path":
3749                         if (o.type == "path") {
3750                             $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"});
3751                             o._.dirty = 1;
3752                             if (o._.arrows) {
3753                                 "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3754                                 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3755                             }
3756                         }
3757                         break;
3758                     case "width":
3759                         node.setAttribute(att, value);
3760                         o._.dirty = 1;
3761                         if (attrs.fx) {
3762                             att = "x";
3763                             value = attrs.x;
3764                         } else {
3765                             break;
3766                         }
3767                     case "x":
3768                         if (attrs.fx) {
3769                             value = -attrs.x - (attrs.width || 0);
3770                         }
3771                     case "rx":
3772                         if (att == "rx" && o.type == "rect") {
3773                             break;
3774                         }
3775                     case "cx":
3776                         node.setAttribute(att, value);
3777                         o.pattern && updatePosition(o);
3778                         o._.dirty = 1;
3779                         break;
3780                     case "height":
3781                         node.setAttribute(att, value);
3782                         o._.dirty = 1;
3783                         if (attrs.fy) {
3784                             att = "y";
3785                             value = attrs.y;
3786                         } else {
3787                             break;
3788                         }
3789                     case "y":
3790                         if (attrs.fy) {
3791                             value = -attrs.y - (attrs.height || 0);
3792                         }
3793                     case "ry":
3794                         if (att == "ry" && o.type == "rect") {
3795                             break;
3796                         }
3797                     case "cy":
3798                         node.setAttribute(att, value);
3799                         o.pattern && updatePosition(o);
3800                         o._.dirty = 1;
3801                         break;
3802                     case "r":
3803                         if (o.type == "rect") {
3804                             $(node, {rx: value, ry: value});
3805                         } else {
3806                             node.setAttribute(att, value);
3807                         }
3808                         o._.dirty = 1;
3809                         break;
3810                     case "src":
3811                         if (o.type == "image") {
3812                             node.setAttributeNS(xlink, "href", value);
3813                         }
3814                         break;
3815                     case "stroke-width":
3816                         if (o._.sx != 1 || o._.sy != 1) {
3817                             value /= mmax(abs(o._.sx), abs(o._.sy)) || 1;
3818                         }
3819                         if (o.paper._vbSize) {
3820                             value *= o.paper._vbSize;
3821                         }
3822                         node.setAttribute(att, value);
3823                         if (attrs["stroke-dasharray"]) {
3824                             addDashes(o, attrs["stroke-dasharray"], params);
3825                         }
3826                         if (o._.arrows) {
3827                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3828                             "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3829                         }
3830                         break;
3831                     case "stroke-dasharray":
3832                         addDashes(o, value, params);
3833                         break;
3834                     case "fill":
3835                         var isURL = Str(value).match(R._ISURL);
3836                         if (isURL) {
3837                             el = $("pattern");
3838                             var ig = $("image");
3839                             el.id = R.createUUID();
3840                             $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1});
3841                             $(ig, {x: 0, y: 0, "xlink:href": isURL[1]});
3842                             el.appendChild(ig);
3843
3844                             (function (el) {
3845                                 R._preload(isURL[1], function () {
3846                                     var w = this.offsetWidth,
3847                                         h = this.offsetHeight;
3848                                     $(el, {width: w, height: h});
3849                                     $(ig, {width: w, height: h});
3850                                     o.paper.safari();
3851                                 });
3852                             })(el);
3853                             o.paper.defs.appendChild(el);
3854                             node.style.fill = "url(#" + el.id + ")";
3855                             $(node, {fill: "url(#" + el.id + ")"});
3856                             o.pattern = el;
3857                             o.pattern && updatePosition(o);
3858                             break;
3859                         }
3860                         var clr = R.getRGB(value);
3861                         if (!clr.error) {
3862                             delete params.gradient;
3863                             delete attrs.gradient;
3864                             !R.is(attrs.opacity, "undefined") &&
3865                                 R.is(params.opacity, "undefined") &&
3866                                 $(node, {opacity: attrs.opacity});
3867                             !R.is(attrs["fill-opacity"], "undefined") &&
3868                                 R.is(params["fill-opacity"], "undefined") &&
3869                                 $(node, {"fill-opacity": attrs["fill-opacity"]});
3870                         } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) {
3871                             if ("opacity" in attrs || "fill-opacity" in attrs) {
3872                                 var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
3873                                 if (gradient) {
3874                                     var stops = gradient.getElementsByTagName("stop");
3875                                     $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)});
3876                                 }
3877                             }
3878                             attrs.gradient = value;
3879                             attrs.fill = "none";
3880                             break;
3881                         }
3882                         clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
3883                     case "stroke":
3884                         clr = R.getRGB(value);
3885                         node.setAttribute(att, clr.hex);
3886                         att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
3887                         if (att == "stroke" && o._.arrows) {
3888                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
3889                             "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
3890                         }
3891                         break;
3892                     case "gradient":
3893                         (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value);
3894                         break;
3895                     case "opacity":
3896                         if (attrs.gradient && !attrs[has]("stroke-opacity")) {
3897                             $(node, {"stroke-opacity": value > 1 ? value / 100 : value});
3898                         }
3899                         // fall
3900                     case "fill-opacity":
3901                         if (attrs.gradient) {
3902                             gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
3903                             if (gradient) {
3904                                 stops = gradient.getElementsByTagName("stop");
3905                                 $(stops[stops.length - 1], {"stop-opacity": value});
3906                             }
3907                             break;
3908                         }
3909                     default:
3910                         att == "font-size" && (value = toInt(value, 10) + "px");
3911                         var cssrule = att.replace(/(\-.)/g, function (w) {
3912                             return w.substring(1).toUpperCase();
3913                         });
3914                         node.style[cssrule] = value;
3915                         o._.dirty = 1;
3916                         node.setAttribute(att, value);
3917                         break;
3918                 }
3919             }
3920         }
3921
3922         tuneText(o, params);
3923         node.style.visibility = vis;
3924     },
3925     leading = 1.2,
3926     tuneText = function (el, params) {
3927         if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) {
3928             return;
3929         }
3930         var a = el.attrs,
3931             node = el.node,
3932             fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10;
3933
3934         if (params[has]("text")) {
3935             a.text = params.text;
3936             while (node.firstChild) {
3937                 node.removeChild(node.firstChild);
3938             }
3939             var texts = Str(params.text).split("\n"),
3940                 tspans = [],
3941                 tspan;
3942             for (var i = 0, ii = texts.length; i < ii; i++) {
3943                 tspan = $("tspan");
3944                 i && $(tspan, {dy: fontSize * leading, x: a.x});
3945                 tspan.appendChild(R._g.doc.createTextNode(texts[i]));
3946                 node.appendChild(tspan);
3947                 tspans[i] = tspan;
3948             }
3949         } else {
3950             tspans = node.getElementsByTagName("tspan");
3951             for (i = 0, ii = tspans.length; i < ii; i++) if (i) {
3952                 $(tspans[i], {dy: fontSize * leading, x: a.x});
3953             } else {
3954                 $(tspans[0], {dy: 0});
3955             }
3956         }
3957         $(node, {x: a.x, y: a.y});
3958         el._.dirty = 1;
3959         var bb = el._getBBox(),
3960             dif = a.y - (bb.y + bb.height / 2);
3961         dif && R.is(dif, "finite") && $(tspans[0], {dy: dif});
3962     },
3963     Element = function (node, svg) {
3964         var X = 0,
3965             Y = 0;
3966         
3967         this[0] = this.node = node;
3968         
3969         node.raphael = true;
3970         
3971         this.id = R._oid++;
3972         node.raphaelid = this.id;
3973         this.matrix = R.matrix();
3974         this.realPath = null;
3975         
3976         this.paper = svg;
3977         this.attrs = this.attrs || {};
3978         this._ = {
3979             transform: [],
3980             sx: 1,
3981             sy: 1,
3982             deg: 0,
3983             dx: 0,
3984             dy: 0,
3985             dirty: 1
3986         };
3987         !svg.bottom && (svg.bottom = this);
3988         
3989         this.prev = svg.top;
3990         svg.top && (svg.top.next = this);
3991         svg.top = this;
3992         
3993         this.next = null;
3994     },
3995     elproto = R.el;
3996
3997     Element.prototype = elproto;
3998     elproto.constructor = Element;
3999
4000     R._engine.path = function (pathString, SVG) {
4001         var el = $("path");
4002         SVG.canvas && SVG.canvas.appendChild(el);
4003         var p = new Element(el, SVG);
4004         p.type = "path";
4005         setFillAndStroke(p, {
4006             fill: "none",
4007             stroke: "#000",
4008             path: pathString
4009         });
4010         return p;
4011     };
4012     
4013     elproto.rotate = function (deg, cx, cy) {
4014         if (this.removed) {
4015             return this;
4016         }
4017         deg = Str(deg).split(separator);
4018         if (deg.length - 1) {
4019             cx = toFloat(deg[1]);
4020             cy = toFloat(deg[2]);
4021         }
4022         deg = toFloat(deg[0]);
4023         (cy == null) && (cx = cy);
4024         if (cx == null || cy == null) {
4025             var bbox = this.getBBox(1);
4026             cx = bbox.x + bbox.width / 2;
4027             cy = bbox.y + bbox.height / 2;
4028         }
4029         this.transform(this._.transform.concat([["r", deg, cx, cy]]));
4030         return this;
4031     };
4032     
4033     elproto.scale = function (sx, sy, cx, cy) {
4034         if (this.removed) {
4035             return this;
4036         }
4037         sx = Str(sx).split(separator);
4038         if (sx.length - 1) {
4039             sy = toFloat(sx[1]);
4040             cx = toFloat(sx[2]);
4041             cy = toFloat(sx[3]);
4042         }
4043         sx = toFloat(sx[0]);
4044         (sy == null) && (sy = sx);
4045         (cy == null) && (cx = cy);
4046         if (cx == null || cy == null) {
4047             var bbox = this.getBBox(1);
4048         }
4049         cx = cx == null ? bbox.x + bbox.width / 2 : cx;
4050         cy = cy == null ? bbox.y + bbox.height / 2 : cy;
4051         this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
4052         return this;
4053     };
4054     
4055     elproto.translate = function (dx, dy) {
4056         if (this.removed) {
4057             return this;
4058         }
4059         dx = Str(dx).split(separator);
4060         if (dx.length - 1) {
4061             dy = toFloat(dx[1]);
4062         }
4063         dx = toFloat(dx[0]) || 0;
4064         dy = +dy || 0;
4065         this.transform(this._.transform.concat([["t", dx, dy]]));
4066         return this;
4067     };
4068     
4069     elproto.transform = function (tstr) {
4070         var _ = this._;
4071         if (tstr == null) {
4072             return _.transform;
4073         }
4074         R._extractTransform(this, tstr);
4075
4076         this.clip && $(this.clip, {transform: this.matrix.invert()});
4077         this.pattern && updatePosition(this);
4078         this.node && $(this.node, {transform: this.matrix});
4079     
4080         if (_.sx != 1 || _.sy != 1) {
4081             var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1;
4082             this.attr({"stroke-width": sw});
4083         }
4084
4085         return this;
4086     };
4087     
4088     elproto.hide = function () {
4089         !this.removed && this.paper.safari(this.node.style.display = "none");
4090         return this;
4091     };
4092     
4093     elproto.show = function () {
4094         !this.removed && this.paper.safari(this.node.style.display = "");
4095         return this;
4096     };
4097     
4098     elproto.remove = function () {
4099         if (this.removed) {
4100             return;
4101         }
4102         var paper = this.paper;
4103         paper.__set__ && paper.__set__.exclude(this);
4104         eve.unbind("*.*." + this.id);
4105         if (this.gradient) {
4106             paper.defs.removeChild(this.gradient);
4107         }
4108         R._tear(this, paper);
4109         this.node.parentNode.removeChild(this.node);
4110         for (var i in this) {
4111             this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
4112         }
4113         this.removed = true;
4114     };
4115     elproto._getBBox = function () {
4116         if (this.node.style.display == "none") {
4117             this.show();
4118             var hide = true;
4119         }
4120         var bbox = {};
4121         try {
4122             bbox = this.node.getBBox();
4123         } catch(e) {
4124             // Firefox 3.0.x plays badly here
4125         } finally {
4126             bbox = bbox || {};
4127         }
4128         hide && this.hide();
4129         return bbox;
4130     };
4131     
4132     elproto.attr = function (name, value) {
4133         if (this.removed) {
4134             return this;
4135         }
4136         if (name == null) {
4137             var res = {};
4138             for (var a in this.attrs) if (this.attrs[has](a)) {
4139                 res[a] = this.attrs[a];
4140             }
4141             res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
4142             res.transform = this._.transform;
4143             return res;
4144         }
4145         if (value == null && R.is(name, "string")) {
4146             if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) {
4147                 return this.attrs.gradient;
4148             }
4149             if (name == "transform") {
4150                 return this._.transform;
4151             }
4152             var names = name.split(separator),
4153                 out = {};
4154             for (var i = 0, ii = names.length; i < ii; i++) {
4155                 name = names[i];
4156                 if (name in this.attrs) {
4157                     out[name] = this.attrs[name];
4158                 } else if (R.is(this.paper.customAttributes[name], "function")) {
4159                     out[name] = this.paper.customAttributes[name].def;
4160                 } else {
4161                     out[name] = R._availableAttrs[name];
4162                 }
4163             }
4164             return ii - 1 ? out : out[names[0]];
4165         }
4166         if (value == null && R.is(name, "array")) {
4167             out = {};
4168             for (i = 0, ii = name.length; i < ii; i++) {
4169                 out[name[i]] = this.attr(name[i]);
4170             }
4171             return out;
4172         }
4173         if (value != null) {
4174             var params = {};
4175             params[name] = value;
4176         } else if (name != null && R.is(name, "object")) {
4177             params = name;
4178         }
4179         for (var key in params) {
4180             eve("attr." + key + "." + this.id, this, params[key]);
4181         }
4182         for (key in this.paper.customAttributes) {
4183             if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
4184                 var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
4185                 this.attrs[key] = params[key];
4186                 for (var subkey in par) if (par[has](subkey)) {
4187                     params[subkey] = par[subkey];
4188                 }
4189             }
4190         }
4191         setFillAndStroke(this, params);
4192         return this;
4193     };
4194     
4195     elproto.toFront = function () {
4196         if (this.removed) {
4197             return this;
4198         }
4199         if (this.node.parentNode.tagName.toLowerCase() == "a") {
4200             this.node.parentNode.parentNode.appendChild(this.node.parentNode);
4201         } else {
4202             this.node.parentNode.appendChild(this.node);
4203         }
4204         var svg = this.paper;
4205         svg.top != this && R._tofront(this, svg);
4206         return this;
4207     };
4208     
4209     elproto.toBack = function () {
4210         if (this.removed) {
4211             return this;
4212         }
4213         var parent = this.node.parentNode;
4214         if (parent.tagName.toLowerCase() == "a") {
4215             parent.parentNode.insertBefore(this.node.parentNode, this.node.parentNode.parentNode.firstChild); 
4216         } else if (parent.firstChild != this.node) {
4217             parent.insertBefore(this.node, this.node.parentNode.firstChild);
4218         }
4219         R._toback(this, this.paper);
4220         var svg = this.paper;
4221         return this;
4222     };
4223     
4224     elproto.insertAfter = function (element) {
4225         if (this.removed) {
4226             return this;
4227         }
4228         var node = element.node || element[element.length - 1].node;
4229         if (node.nextSibling) {
4230             node.parentNode.insertBefore(this.node, node.nextSibling);
4231         } else {
4232             node.parentNode.appendChild(this.node);
4233         }
4234         R._insertafter(this, element, this.paper);
4235         return this;
4236     };
4237     
4238     elproto.insertBefore = function (element) {
4239         if (this.removed) {
4240             return this;
4241         }
4242         var node = element.node || element[0].node;
4243         node.parentNode.insertBefore(this.node, node);
4244         R._insertbefore(this, element, this.paper);
4245         return this;
4246     };
4247     elproto.blur = function (size) {
4248         // Experimental. No Safari support. Use it on your own risk.
4249         var t = this;
4250         if (+size !== 0) {
4251             var fltr = $("filter"),
4252                 blur = $("feGaussianBlur");
4253             t.attrs.blur = size;
4254             fltr.id = R.createUUID();
4255             $(blur, {stdDeviation: +size || 1.5});
4256             fltr.appendChild(blur);
4257             t.paper.defs.appendChild(fltr);
4258             t._blur = fltr;
4259             $(t.node, {filter: "url(#" + fltr.id + ")"});
4260         } else {
4261             if (t._blur) {
4262                 t._blur.parentNode.removeChild(t._blur);
4263                 delete t._blur;
4264                 delete t.attrs.blur;
4265             }
4266             t.node.removeAttribute("filter");
4267         }
4268     };
4269     R._engine.circle = function (svg, x, y, r) {
4270         var el = $("circle");
4271         svg.canvas && svg.canvas.appendChild(el);
4272         var res = new Element(el, svg);
4273         res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"};
4274         res.type = "circle";
4275         $(el, res.attrs);
4276         return res;
4277     };
4278     R._engine.rect = function (svg, x, y, w, h, r) {
4279         var el = $("rect");
4280         svg.canvas && svg.canvas.appendChild(el);
4281         var res = new Element(el, svg);
4282         res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"};
4283         res.type = "rect";
4284         $(el, res.attrs);
4285         return res;
4286     };
4287     R._engine.ellipse = function (svg, x, y, rx, ry) {
4288         var el = $("ellipse");
4289         svg.canvas && svg.canvas.appendChild(el);
4290         var res = new Element(el, svg);
4291         res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"};
4292         res.type = "ellipse";
4293         $(el, res.attrs);
4294         return res;
4295     };
4296     R._engine.image = function (svg, src, x, y, w, h) {
4297         var el = $("image");
4298         $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"});
4299         el.setAttributeNS(xlink, "href", src);
4300         svg.canvas && svg.canvas.appendChild(el);
4301         var res = new Element(el, svg);
4302         res.attrs = {x: x, y: y, width: w, height: h, src: src};
4303         res.type = "image";
4304         return res;
4305     };
4306     R._engine.text = function (svg, x, y, text) {
4307         var el = $("text");
4308         // $(el, {x: x, y: y, "text-anchor": "middle"});
4309         svg.canvas && svg.canvas.appendChild(el);
4310         var res = new Element(el, svg);
4311         res.attrs = {
4312             x: x,
4313             y: y,
4314             "text-anchor": "middle",
4315             text: text,
4316             font: R._availableAttrs.font,
4317             stroke: "none",
4318             fill: "#000"
4319         };
4320         res.type = "text";
4321         setFillAndStroke(res, res.attrs);
4322         return res;
4323     };
4324     R._engine.setSize = function (width, height) {
4325         this.width = width || this.width;
4326         this.height = height || this.height;
4327         this.canvas.setAttribute("width", this.width);
4328         this.canvas.setAttribute("height", this.height);
4329         if (this._viewBox) {
4330             this.setViewBox.apply(this, this._viewBox);
4331         }
4332         return this;
4333     };
4334     R._engine.create = function () {
4335         var con = R._getContainer.apply(0, arguments),
4336             container = con && con.container,
4337             x = con.x,
4338             y = con.y,
4339             width = con.width,
4340             height = con.height;
4341         if (!container) {
4342             throw new Error("SVG container not found.");
4343         }
4344         var cnvs = $("svg"),
4345             css = "overflow:hidden;",
4346             isFloating;
4347         x = x || 0;
4348         y = y || 0;
4349         width = width || 512;
4350         height = height || 342;
4351         $(cnvs, {
4352             height: height,
4353             version: 1.1,
4354             width: width,
4355             xmlns: "http://www.w3.org/2000/svg"
4356         });
4357         if (container == 1) {
4358             cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
4359             R._g.doc.body.appendChild(cnvs);
4360             isFloating = 1;
4361         } else {
4362             cnvs.style.cssText = css + "position:relative";
4363             if (container.firstChild) {
4364                 container.insertBefore(cnvs, container.firstChild);
4365             } else {
4366                 container.appendChild(cnvs);
4367             }
4368         }
4369         container = new R._Paper;
4370         container.width = width;
4371         container.height = height;
4372         container.canvas = cnvs;
4373         // plugins.call(container, container, R.fn);
4374         container.clear();
4375         container._left = container._top = 0;
4376         isFloating && (container.renderfix = function () {});
4377         container.renderfix();
4378         return container;
4379     };
4380     R._engine.setViewBox = function (x, y, w, h, fit) {
4381         eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]);
4382         var size = mmax(w / this.width, h / this.height),
4383             top = this.top,
4384             aspectRatio = fit ? "meet" : "xMinYMin",
4385             vb,
4386             sw;
4387         if (x == null) {
4388             if (this._vbSize) {
4389                 size = 1;
4390             }
4391             delete this._vbSize;
4392             vb = "0 0 " + this.width + S + this.height;
4393         } else {
4394             this._vbSize = size;
4395             vb = x + S + y + S + w + S + h;
4396         }
4397         $(this.canvas, {
4398             viewBox: vb,
4399             preserveAspectRatio: aspectRatio
4400         });
4401         while (size && top) {
4402             sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1;
4403             top.attr({"stroke-width": sw});
4404             top._.dirty = 1;
4405             top._.dirtyT = 1;
4406             top = top.prev;
4407         }
4408         this._viewBox = [x, y, w, h, !!fit];
4409         return this;
4410     };
4411     
4412     R.prototype.renderfix = function () {
4413         var cnvs = this.canvas,
4414             s = cnvs.style,
4415             pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(),
4416             left = -pos.e % 1,
4417             top = -pos.f % 1;
4418         if (left || top) {
4419             if (left) {
4420                 this._left = (this._left + left) % 1;
4421                 s.left = this._left + "px";
4422             }
4423             if (top) {
4424                 this._top = (this._top + top) % 1;
4425                 s.top = this._top + "px";
4426             }
4427         }
4428     };
4429     
4430     R.prototype.clear = function () {
4431         R.eve("clear", this);
4432         var c = this.canvas;
4433         while (c.firstChild) {
4434             c.removeChild(c.firstChild);
4435         }
4436         this.bottom = this.top = null;
4437         (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version));
4438         c.appendChild(this.desc);
4439         c.appendChild(this.defs = $("defs"));
4440     };
4441     
4442     R.prototype.remove = function () {
4443         eve("remove", this);
4444         this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
4445         for (var i in this) {
4446             this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
4447         }
4448     };
4449     var setproto = R.st;
4450     for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
4451         setproto[method] = (function (methodname) {
4452             return function () {
4453                 var arg = arguments;
4454                 return this.forEach(function (el) {
4455                     el[methodname].apply(el, arg);
4456                 });
4457             };
4458         })(method);
4459     }
4460 }(window.Raphael);
4461
4462 // ┌─────────────────────────────────────────────────────────────────────┐ \\
4463 // │ Raphaël - JavaScript Vector Library                                 │ \\
4464 // ├─────────────────────────────────────────────────────────────────────┤ \\
4465 // │ VML Module                                                          │ \\
4466 // ├─────────────────────────────────────────────────────────────────────┤ \\
4467 // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com)   │ \\
4468 // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com)             │ \\
4469 // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\
4470 // └─────────────────────────────────────────────────────────────────────┘ \\
4471
4472
4473 window.Raphael.vml && function (R) {
4474     var has = "hasOwnProperty",
4475         Str = String,
4476         toFloat = parseFloat,
4477         math = Math,
4478         round = math.round,
4479         mmax = math.max,
4480         mmin = math.min,
4481         abs = math.abs,
4482         fillString = "fill",
4483         separator = /[, ]+/,
4484         eve = R.eve,
4485         ms = " progid:DXImageTransform.Microsoft",
4486         S = " ",
4487         E = "",
4488         map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"},
4489         bites = /([clmz]),?([^clmz]*)/gi,
4490         blurregexp = / progid:\S+Blur\([^\)]+\)/g,
4491         val = /-?[^,\s-]+/g,
4492         cssDot = "position:absolute;left:0;top:0;width:1px;height:1px",
4493         zoom = 21600,
4494         pathTypes = {path: 1, rect: 1, image: 1},
4495         ovalTypes = {circle: 1, ellipse: 1},
4496         path2vml = function (path) {
4497             var total =  /[ahqstv]/ig,
4498                 command = R._pathToAbsolute;
4499             Str(path).match(total) && (command = R._path2curve);
4500             total = /[clmz]/g;
4501             if (command == R._pathToAbsolute && !Str(path).match(total)) {
4502                 var res = Str(path).replace(bites, function (all, command, args) {
4503                     var vals = [],
4504                         isMove = command.toLowerCase() == "m",
4505                         res = map[command];
4506                     args.replace(val, function (value) {
4507                         if (isMove && vals.length == 2) {
4508                             res += vals + map[command == "m" ? "l" : "L"];
4509                             vals = [];
4510                         }
4511                         vals.push(round(value * zoom));
4512                     });
4513                     return res + vals;
4514                 });
4515                 return res;
4516             }
4517             var pa = command(path), p, r;
4518             res = [];
4519             for (var i = 0, ii = pa.length; i < ii; i++) {
4520                 p = pa[i];
4521                 r = pa[i][0].toLowerCase();
4522                 r == "z" && (r = "x");
4523                 for (var j = 1, jj = p.length; j < jj; j++) {
4524                     r += round(p[j] * zoom) + (j != jj - 1 ? "," : E);
4525                 }
4526                 res.push(r);
4527             }
4528             return res.join(S);
4529         },
4530         compensation = function (deg, dx, dy) {
4531             var m = R.matrix();
4532             m.rotate(-deg, .5, .5);
4533             return {
4534                 dx: m.x(dx, dy),
4535                 dy: m.y(dx, dy)
4536             };
4537         },
4538         setCoords = function (p, sx, sy, dx, dy, deg) {
4539             var _ = p._,
4540                 m = p.matrix,
4541                 fillpos = _.fillpos,
4542                 o = p.node,
4543                 s = o.style,
4544                 y = 1,
4545                 flip = "",
4546                 dxdy,
4547                 kx = zoom / sx,
4548                 ky = zoom / sy;
4549             s.visibility = "hidden";
4550             if (!sx || !sy) {
4551                 return;
4552             }
4553             o.coordsize = abs(kx) + S + abs(ky);
4554             s.rotation = deg * (sx * sy < 0 ? -1 : 1);
4555             if (deg) {
4556                 var c = compensation(deg, dx, dy);
4557                 dx = c.dx;
4558                 dy = c.dy;
4559             }
4560             sx < 0 && (flip += "x");
4561             sy < 0 && (flip += " y") && (y = -1);
4562             s.flip = flip;
4563             o.coordorigin = (dx * -kx) + S + (dy * -ky);
4564             if (fillpos || _.fillsize) {
4565                 var fill = o.getElementsByTagName(fillString);
4566                 fill = fill && fill[0];
4567                 o.removeChild(fill);
4568                 if (fillpos) {
4569                     c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1]));
4570                     fill.position = c.dx * y + S + c.dy * y;
4571                 }
4572                 if (_.fillsize) {
4573                     fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy);
4574                 }
4575                 o.appendChild(fill);
4576             }
4577             s.visibility = "visible";
4578         };
4579     R.toString = function () {
4580         return  "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version;
4581     };
4582     var addArrow = function (o, value, isEnd) {
4583         var values = Str(value).toLowerCase().split("-"),
4584             se = isEnd ? "end" : "start",
4585             i = values.length,
4586             type = "classic",
4587             w = "medium",
4588             h = "medium";
4589         while (i--) {
4590             switch (values[i]) {
4591                 case "block":
4592                 case "classic":
4593                 case "oval":
4594                 case "diamond":
4595                 case "open":
4596                 case "none":
4597                     type = values[i];
4598                     break;
4599                 case "wide":
4600                 case "narrow": h = values[i]; break;
4601                 case "long":
4602                 case "short": w = values[i]; break;
4603             }
4604         }
4605         var stroke = o.node.getElementsByTagName("stroke")[0];
4606         stroke[se + "arrow"] = type;
4607         stroke[se + "arrowlength"] = w;
4608         stroke[se + "arrowwidth"] = h;
4609     },
4610     setFillAndStroke = function (o, params) {
4611         //Roo.log( ['setFillAndStroke' , o, params]);
4612         // o.paper.canvas.style.display = "none";
4613         o.attrs = o.attrs || {};
4614         var node = o.node,
4615             a = o.attrs,
4616             s = node.style,
4617             xy,
4618             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),
4619             isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry),
4620             res = o;
4621
4622
4623         for (var par in params) if (params[has](par)) {
4624             a[par] = params[par];
4625         }
4626         if (newpath) {
4627             a.path = R._getPath[o.type](o);
4628             o._.dirty = 1;
4629         }
4630         params.href && (node.href = params.href);
4631         params.title && (node.title = params.title);
4632         params.target && (node.target = params.target);
4633         params.cursor && (s.cursor = params.cursor);
4634         "blur" in params && o.blur(params.blur);
4635         if (params.path && o.type == "path" || newpath) {
4636             node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path);
4637             if (o.type == "image") {
4638                 o._.fillpos = [a.x, a.y];
4639                 o._.fillsize = [a.width, a.height];
4640                 setCoords(o, 1, 1, 0, 0, 0);
4641             }
4642         }
4643         "transform" in params && o.transform(params.transform);
4644         if (isOval) {
4645             var cx = +a.cx,
4646                 cy = +a.cy,
4647                 rx = +a.rx || +a.r || 0,
4648                 ry = +a.ry || +a.r || 0;
4649             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));
4650         }
4651         if ("clip-rect" in params) {
4652             var rect = Str(params["clip-rect"]).split(separator);
4653             if (rect.length == 4) {
4654                 rect[2] = +rect[2] + (+rect[0]);
4655                 rect[3] = +rect[3] + (+rect[1]);
4656                 var div = node.clipRect || R._g.doc.createElement("div"),
4657                     dstyle = div.style;
4658                 dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect);
4659                 if (!node.clipRect) {
4660                     dstyle.position = "absolute";
4661                     dstyle.top = 0;
4662                     dstyle.left = 0;
4663                     dstyle.width = o.paper.width + "px";
4664                     dstyle.height = o.paper.height + "px";
4665                     node.parentNode.insertBefore(div, node);
4666                     div.appendChild(node);
4667                     node.clipRect = div;
4668                 }
4669             }
4670             if (!params["clip-rect"]) {
4671                 node.clipRect && (node.clipRect.style.clip = "auto");
4672             }
4673         }
4674         if (o.textpath) {
4675             var textpathStyle = o.textpath.style;
4676             params.font && (textpathStyle.font = params.font);
4677             params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"');
4678             params["font-size"] && (textpathStyle.fontSize = params["font-size"]);
4679             params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]);
4680             params["font-style"] && (textpathStyle.fontStyle = params["font-style"]);
4681         }
4682         if ("arrow-start" in params) {
4683             addArrow(res, params["arrow-start"]);
4684         }
4685         if ("arrow-end" in params) {
4686             addArrow(res, params["arrow-end"], 1);
4687         }
4688         if (params.opacity != null || 
4689             params["stroke-width"] != null ||
4690             params.fill != null ||
4691             params.src != null ||
4692             params.stroke != null ||
4693             params["stroke-width"] != null ||
4694             params["stroke-opacity"] != null ||
4695             params["fill-opacity"] != null ||
4696             params["stroke-dasharray"] != null ||
4697             params["stroke-miterlimit"] != null ||
4698             params["stroke-linejoin"] != null ||
4699             params["stroke-linecap"] != null) {
4700             var fill = node.getElementsByTagName(fillString),
4701                 newfill = false;
4702             fill = fill && fill[0];
4703             !fill && (newfill = fill = createNode(fillString));
4704             if (o.type == "image" && params.src) {
4705                 fill.src = params.src;
4706             }
4707             params.fill && (fill.on = true);
4708             if (fill.on == null || params.fill == "none" || params.fill === null) {
4709                 fill.on = false;
4710             }
4711             if (fill.on && params.fill) {
4712                 var isURL = Str(params.fill).match(R._ISURL);
4713                 if (isURL) {
4714                     fill.parentNode == node && node.removeChild(fill);
4715                     fill.rotate = true;
4716                     fill.src = isURL[1];
4717                     fill.type = "tile";
4718                     var bbox = o.getBBox(1);
4719                     fill.position = bbox.x + S + bbox.y;
4720                     o._.fillpos = [bbox.x, bbox.y];
4721
4722                     R._preload(isURL[1], function () {
4723                         o._.fillsize = [this.offsetWidth, this.offsetHeight];
4724                     });
4725                 } else {
4726                     fill.color = R.getRGB(params.fill).hex;
4727                     fill.src = E;
4728                     fill.type = "solid";
4729                     if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) {
4730                         a.fill = "none";
4731                         a.gradient = params.fill;
4732                         fill.rotate = false;
4733                     }
4734                 }
4735             }
4736             if ("fill-opacity" in params || "opacity" in params) {
4737                 var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1);
4738                 opacity = mmin(mmax(opacity, 0), 1);
4739                 fill.opacity = opacity;
4740                 if (fill.src) {
4741                     fill.color = "none";
4742                 }
4743             }
4744             node.appendChild(fill);
4745             var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]),
4746             newstroke = false;
4747             !stroke && (newstroke = stroke = createNode("stroke"));
4748             if ((params.stroke && params.stroke != "none") ||
4749                 params["stroke-width"] ||
4750                 params["stroke-opacity"] != null ||
4751                 params["stroke-dasharray"] ||
4752                 params["stroke-miterlimit"] ||
4753                 params["stroke-linejoin"] ||
4754                 params["stroke-linecap"]) {
4755                 stroke.on = true;
4756             }
4757             (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false);
4758             var strokeColor = R.getRGB(params.stroke);
4759             stroke.on && params.stroke && (stroke.color = strokeColor.hex);
4760             opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1);
4761             var width = (toFloat(params["stroke-width"]) || 1) * .75;
4762             opacity = mmin(mmax(opacity, 0), 1);
4763             params["stroke-width"] == null && (width = a["stroke-width"]);
4764             params["stroke-width"] && (stroke.weight = width);
4765             width && width < 1 && (opacity *= width) && (stroke.weight = 1);
4766             stroke.opacity = opacity;
4767         
4768             params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter");
4769             stroke.miterlimit = params["stroke-miterlimit"] || 8;
4770             params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round");
4771             if (params["stroke-dasharray"]) {
4772                 var dasharray = {
4773                     "-": "shortdash",
4774                     ".": "shortdot",
4775                     "-.": "shortdashdot",
4776                     "-..": "shortdashdotdot",
4777                     ". ": "dot",
4778                     "- ": "dash",
4779                     "--": "longdash",
4780                     "- .": "dashdot",
4781                     "--.": "longdashdot",
4782                     "--..": "longdashdotdot"
4783                 };
4784                 stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E;
4785             }
4786             newstroke && node.appendChild(stroke);
4787         }
4788         if (res.type == "text") {
4789             res.paper.canvas.style.display = E;
4790             var span = res.paper.span,
4791                 m = 100,
4792                 fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/);
4793             s = span.style;
4794             a.font && (s.font = a.font);
4795             a["font-family"] && (s.fontFamily = a["font-family"]);
4796             a["font-weight"] && (s.fontWeight = a["font-weight"]);
4797             a["font-style"] && (s.fontStyle = a["font-style"]);
4798             fontSize = toFloat(a["font-size"] || fontSize && fontSize[0]) || 10;
4799             s.fontSize = fontSize * m + "px";
4800             res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/</g, "&#60;").replace(/&/g, "&#38;").replace(/\n/g, "<br>"));
4801             var brect = span.getBoundingClientRect();
4802             res.W = a.w = (brect.right - brect.left) / m;
4803             res.H = a.h = (brect.bottom - brect.top) / m;
4804             // res.paper.canvas.style.display = "none";
4805             res.X = a.x;
4806             res.Y = a.y + res.H / 2;
4807
4808             ("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));
4809             var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"];
4810             for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) {
4811                 res._.dirty = 1;
4812                 break;
4813             }
4814         
4815             // text-anchor emulation
4816             switch (a["text-anchor"]) {
4817                 case "start":
4818                     res.textpath.style["v-text-align"] = "left";
4819                     res.bbx = res.W / 2;
4820                 break;
4821                 case "end":
4822                     res.textpath.style["v-text-align"] = "right";
4823                     res.bbx = -res.W / 2;
4824                 break;
4825                 default:
4826                     res.textpath.style["v-text-align"] = "center";
4827                     res.bbx = 0;
4828                 break;
4829             }
4830             res.textpath.style["v-text-kern"] = true;
4831         }
4832         // res.paper.canvas.style.display = E;
4833     },
4834     addGradientFill = function (o, gradient, fill) {
4835         o.attrs = o.attrs || {};
4836         var attrs = o.attrs,
4837             pow = Math.pow,
4838             opacity,
4839             oindex,
4840             type = "linear",
4841             fxfy = ".5 .5";
4842         o.attrs.gradient = gradient;
4843         gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) {
4844             type = "radial";
4845             if (fx && fy) {
4846                 fx = toFloat(fx);
4847                 fy = toFloat(fy);
4848                 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5);
4849                 fxfy = fx + S + fy;
4850             }
4851             return E;
4852         });
4853         gradient = gradient.split(/\s*\-\s*/);
4854         if (type == "linear") {
4855             var angle = gradient.shift();
4856             angle = -toFloat(angle);
4857             if (isNaN(angle)) {
4858                 return null;
4859             }
4860         }
4861         var dots = R._parseDots(gradient);
4862         if (!dots) {
4863             return null;
4864         }
4865         o = o.shape || o.node;
4866         if (dots.length) {
4867             o.removeChild(fill);
4868             fill.on = true;
4869             fill.method = "none";
4870             fill.color = dots[0].color;
4871             fill.color2 = dots[dots.length - 1].color;
4872             var clrs = [];
4873             for (var i = 0, ii = dots.length; i < ii; i++) {
4874                 dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color);
4875             }
4876             fill.colors = clrs.length ? clrs.join() : "0% " + fill.color;
4877             if (type == "radial") {
4878                 fill.type = "gradientTitle";
4879                 fill.focus = "100%";
4880                 fill.focussize = "0 0";
4881                 fill.focusposition = fxfy;
4882                 fill.angle = 0;
4883             } else {
4884                 // fill.rotate= true;
4885                 fill.type = "gradient";
4886                 fill.angle = (270 - angle) % 360;
4887             }
4888             o.appendChild(fill);
4889         }
4890         return 1;
4891     },
4892     Element = function (node, vml) {
4893         this[0] = this.node = node;
4894         node.raphael = true;
4895         this.id = R._oid++;
4896         node.raphaelid = this.id;
4897         this.X = 0;
4898         this.Y = 0;
4899         this.attrs = {};
4900         this.paper = vml;
4901         this.matrix = R.matrix();
4902         this._ = {
4903             transform: [],
4904             sx: 1,
4905             sy: 1,
4906             dx: 0,
4907             dy: 0,
4908             deg: 0,
4909             dirty: 1,
4910             dirtyT: 1
4911         };
4912         !vml.bottom && (vml.bottom = this);
4913         this.prev = vml.top;
4914         vml.top && (vml.top.next = this);
4915         vml.top = this;
4916         this.next = null;
4917     };
4918     var elproto = R.el;
4919
4920     Element.prototype = elproto;
4921     elproto.constructor = Element;
4922     elproto.transform = function (tstr) {
4923         if (tstr == null) {
4924             return this._.transform;
4925         }
4926         var vbs = this.paper._viewBoxShift,
4927             vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E,
4928             oldt;
4929         if (vbs) {
4930             oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E);
4931         }
4932         R._extractTransform(this, vbt + tstr);
4933         var matrix = this.matrix.clone(),
4934             skew = this.skew,
4935             o = this.node,
4936             split,
4937             isGrad = ~Str(this.attrs.fill).indexOf("-"),
4938             isPatt = !Str(this.attrs.fill).indexOf("url(");
4939         matrix.translate(-.5, -.5);
4940         if (isPatt || isGrad || this.type == "image") {
4941             skew.matrix = "1 0 0 1";
4942             skew.offset = "0 0";
4943             split = matrix.split();
4944             if ((isGrad && split.noRotation) || !split.isSimple) {
4945                 o.style.filter = matrix.toFilter();
4946                 var bb = this.getBBox(),
4947                     bbt = this.getBBox(1),
4948                     dx = bb.x - bbt.x,
4949                     dy = bb.y - bbt.y;
4950                 o.coordorigin = (dx * -zoom) + S + (dy * -zoom);
4951                 setCoords(this, 1, 1, dx, dy, 0);
4952             } else {
4953                 o.style.filter = E;
4954                 setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate);
4955             }
4956         } else {
4957             o.style.filter = E;
4958             skew.matrix = Str(matrix);
4959             skew.offset = matrix.offset();
4960         }
4961         oldt && (this._.transform = oldt);
4962         return this;
4963     };
4964     elproto.rotate = function (deg, cx, cy) {
4965         if (this.removed) {
4966             return this;
4967         }
4968         if (deg == null) {
4969             return;
4970         }
4971         deg = Str(deg).split(separator);
4972         if (deg.length - 1) {
4973             cx = toFloat(deg[1]);
4974             cy = toFloat(deg[2]);
4975         }
4976         deg = toFloat(deg[0]);
4977         (cy == null) && (cx = cy);
4978         if (cx == null || cy == null) {
4979             var bbox = this.getBBox(1);
4980             cx = bbox.x + bbox.width / 2;
4981             cy = bbox.y + bbox.height / 2;
4982         }
4983         this._.dirtyT = 1;
4984         this.transform(this._.transform.concat([["r", deg, cx, cy]]));
4985         return this;
4986     };
4987     elproto.translate = function (dx, dy) {
4988         if (this.removed) {
4989             return this;
4990         }
4991         dx = Str(dx).split(separator);
4992         if (dx.length - 1) {
4993             dy = toFloat(dx[1]);
4994         }
4995         dx = toFloat(dx[0]) || 0;
4996         dy = +dy || 0;
4997         if (this._.bbox) {
4998             this._.bbox.x += dx;
4999             this._.bbox.y += dy;
5000         }
5001         this.transform(this._.transform.concat([["t", dx, dy]]));
5002         return this;
5003     };
5004     elproto.scale = function (sx, sy, cx, cy) {
5005         if (this.removed) {
5006             return this;
5007         }
5008         sx = Str(sx).split(separator);
5009         if (sx.length - 1) {
5010             sy = toFloat(sx[1]);
5011             cx = toFloat(sx[2]);
5012             cy = toFloat(sx[3]);
5013             isNaN(cx) && (cx = null);
5014             isNaN(cy) && (cy = null);
5015         }
5016         sx = toFloat(sx[0]);
5017         (sy == null) && (sy = sx);
5018         (cy == null) && (cx = cy);
5019         if (cx == null || cy == null) {
5020             var bbox = this.getBBox(1);
5021         }
5022         cx = cx == null ? bbox.x + bbox.width / 2 : cx;
5023         cy = cy == null ? bbox.y + bbox.height / 2 : cy;
5024     
5025         this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
5026         this._.dirtyT = 1;
5027         return this;
5028     };
5029     elproto.hide = function () {
5030         !this.removed && (this.node.style.display = "none");
5031         return this;
5032     };
5033     elproto.show = function () {
5034         !this.removed && (this.node.style.display = E);
5035         return this;
5036     };
5037     elproto._getBBox = function () {
5038         if (this.removed) {
5039             return {};
5040         }
5041         return {
5042             x: this.X + (this.bbx || 0) - this.W / 2,
5043             y: this.Y - this.H,
5044             width: this.W,
5045             height: this.H
5046         };
5047     };
5048     elproto.remove = function () {
5049         if (this.removed) {
5050             return;
5051         }
5052         this.paper.__set__ && this.paper.__set__.exclude(this);
5053         R.eve.unbind("*.*." + this.id);
5054         R._tear(this, this.paper);
5055         this.node.parentNode.removeChild(this.node);
5056         this.shape && this.shape.parentNode.removeChild(this.shape);
5057         for (var i in this) {
5058             this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
5059         }
5060         this.removed = true;
5061     };
5062     elproto.attr = function (name, value) {
5063         if (this.removed) {
5064             return this;
5065         }
5066         if (name == null) {
5067             var res = {};
5068             for (var a in this.attrs) if (this.attrs[has](a)) {
5069                 res[a] = this.attrs[a];
5070             }
5071             res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
5072             res.transform = this._.transform;
5073             return res;
5074         }
5075         if (value == null && R.is(name, "string")) {
5076             if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) {
5077                 return this.attrs.gradient;
5078             }
5079             var names = name.split(separator),
5080                 out = {};
5081             for (var i = 0, ii = names.length; i < ii; i++) {
5082                 name = names[i];
5083                 if (name in this.attrs) {
5084                     out[name] = this.attrs[name];
5085                 } else if (R.is(this.paper.customAttributes[name], "function")) {
5086                     out[name] = this.paper.customAttributes[name].def;
5087                 } else {
5088                     out[name] = R._availableAttrs[name];
5089                 }
5090             }
5091             return ii - 1 ? out : out[names[0]];
5092         }
5093         if (this.attrs && value == null && R.is(name, "array")) {
5094             out = {};
5095             for (i = 0, ii = name.length; i < ii; i++) {
5096                 out[name[i]] = this.attr(name[i]);
5097             }
5098             return out;
5099         }
5100         var params;
5101         if (value != null) {
5102             params = {};
5103             params[name] = value;
5104         }
5105         value == null && R.is(name, "object") && (params = name);
5106         for (var key in params) {
5107             eve("attr." + key + "." + this.id, this, params[key]);
5108         }
5109         if (params) {
5110             for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
5111                 var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
5112                 this.attrs[key] = params[key];
5113                 for (var subkey in par) if (par[has](subkey)) {
5114                     params[subkey] = par[subkey];
5115                 }
5116             }
5117             // this.paper.canvas.style.display = "none";
5118             if (params.text && this.type == "text") {
5119                 this.textpath.string = params.text;
5120             }
5121             setFillAndStroke(this, params);
5122             // this.paper.canvas.style.display = E;
5123         }
5124         return this;
5125     };
5126     elproto.toFront = function () {
5127         !this.removed && this.node.parentNode.appendChild(this.node);
5128         this.paper && this.paper.top != this && R._tofront(this, this.paper);
5129         return this;
5130     };
5131     elproto.toBack = function () {
5132         if (this.removed) {
5133             return this;
5134         }
5135         if (this.node.parentNode.firstChild != this.node) {
5136             this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
5137             R._toback(this, this.paper);
5138         }
5139         return this;
5140     };
5141     elproto.insertAfter = function (element) {
5142         if (this.removed) {
5143             return this;
5144         }
5145         if (element.constructor == R.st.constructor) {
5146             element = element[element.length - 1];
5147         }
5148         if (element.node.nextSibling) {
5149             element.node.parentNode.insertBefore(this.node, element.node.nextSibling);
5150         } else {
5151             element.node.parentNode.appendChild(this.node);
5152         }
5153         R._insertafter(this, element, this.paper);
5154         return this;
5155     };
5156     elproto.insertBefore = function (element) {
5157         if (this.removed) {
5158             return this;
5159         }
5160         if (element.constructor == R.st.constructor) {
5161             element = element[0];
5162         }
5163         element.node.parentNode.insertBefore(this.node, element.node);
5164         R._insertbefore(this, element, this.paper);
5165         return this;
5166     };
5167     elproto.blur = function (size) {
5168         var s = this.node.runtimeStyle,
5169             f = s.filter;
5170         f = f.replace(blurregexp, E);
5171         if (+size !== 0) {
5172             this.attrs.blur = size;
5173             s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")";
5174             s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5));
5175         } else {
5176             s.filter = f;
5177             s.margin = 0;
5178             delete this.attrs.blur;
5179         }
5180     };
5181
5182     R._engine.path = function (pathString, vml) {
5183         var el = createNode("shape");
5184         el.style.cssText = cssDot;
5185         el.coordsize = zoom + S + zoom;
5186         el.coordorigin = vml.coordorigin;
5187         var p = new Element(el, vml),
5188             attr = {fill: "none", stroke: "#000"};
5189         pathString && (attr.path = pathString);
5190         p.type = "path";
5191         p.path = [];
5192         p.Path = E;
5193         setFillAndStroke(p, attr);
5194         vml.canvas.appendChild(el);
5195         var skew = createNode("skew");
5196         skew.on = true;
5197         el.appendChild(skew);
5198         p.skew = skew;
5199         p.transform(E);
5200         return p;
5201     };
5202     R._engine.rect = function (vml, x, y, w, h, r) {
5203         var path = R._rectPath(x, y, w, h, r),
5204             res = vml.path(path),
5205             a = res.attrs;
5206         res.X = a.x = x;
5207         res.Y = a.y = y;
5208         res.W = a.width = w;
5209         res.H = a.height = h;
5210         a.r = r;
5211         a.path = path;
5212         res.type = "rect";
5213         return res;
5214     };
5215     R._engine.ellipse = function (vml, x, y, rx, ry) {
5216         var res = vml.path(),
5217             a = res.attrs;
5218         res.X = x - rx;
5219         res.Y = y - ry;
5220         res.W = rx * 2;
5221         res.H = ry * 2;
5222         res.type = "ellipse";
5223         setFillAndStroke(res, {
5224             cx: x,
5225             cy: y,
5226             rx: rx,
5227             ry: ry
5228         });
5229         return res;
5230     };
5231     R._engine.circle = function (vml, x, y, r) {
5232         var res = vml.path(),
5233             a = res.attrs;
5234         res.X = x - r;
5235         res.Y = y - r;
5236         res.W = res.H = r * 2;
5237         res.type = "circle";
5238         setFillAndStroke(res, {
5239             cx: x,
5240             cy: y,
5241             r: r
5242         });
5243         return res;
5244     };
5245     R._engine.image = function (vml, src, x, y, w, h) {
5246         var path = R._rectPath(x, y, w, h),
5247             res = vml.path(path).attr({stroke: "none"}),
5248             a = res.attrs,
5249             node = res.node,
5250             fill = node.getElementsByTagName(fillString)[0];
5251         a.src = src;
5252         res.X = a.x = x;
5253         res.Y = a.y = y;
5254         res.W = a.width = w;
5255         res.H = a.height = h;
5256         a.path = path;
5257         res.type = "image";
5258         fill.parentNode == node && node.removeChild(fill);
5259         fill.rotate = true;
5260         fill.src = src;
5261         fill.type = "tile";
5262         res._.fillpos = [x, y];
5263         res._.fillsize = [w, h];
5264         node.appendChild(fill);
5265         setCoords(res, 1, 1, 0, 0, 0);
5266         return res;
5267     };
5268     R._engine.text = function (vml, x, y, text) {
5269         var el = createNode("shape"),
5270             path = createNode("path"),
5271             o = createNode("textpath");
5272         x = x || 0;
5273         y = y || 0;
5274         text = text || "";
5275         path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1);
5276         path.textpathok = true;
5277         o.string = Str(text);
5278         o.on = true;
5279         el.style.cssText = cssDot;
5280         el.coordsize = zoom + S + zoom;
5281         el.coordorigin = "0 0";
5282         var p = new Element(el, vml),
5283             attr = {
5284                 fill: "#000",
5285                 stroke: "none",
5286                 font: R._availableAttrs.font,
5287                 text: text
5288             };
5289         p.shape = el;
5290         p.path = path;
5291         p.textpath = o;
5292         p.type = "text";
5293         p.attrs.text = Str(text);
5294         p.attrs.x = x;
5295         p.attrs.y = y;
5296         p.attrs.w = 1;
5297         p.attrs.h = 1;
5298         setFillAndStroke(p, attr);
5299         el.appendChild(o);
5300         el.appendChild(path);
5301         vml.canvas.appendChild(el);
5302         var skew = createNode("skew");
5303         skew.on = true;
5304         el.appendChild(skew);
5305         p.skew = skew;
5306         p.transform(E);
5307         return p;
5308     };
5309     R._engine.setSize = function (width, height) {
5310         var cs = this.canvas.style;
5311         this.width = width;
5312         this.height = height;
5313         width == +width && (width += "px");
5314         height == +height && (height += "px");
5315         cs.width = width;
5316         cs.height = height;
5317         cs.clip = "rect(0 " + width + " " + height + " 0)";
5318         if (this._viewBox) {
5319             R._engine.setViewBox.apply(this, this._viewBox);
5320         }
5321         return this;
5322     };
5323     R._engine.setViewBox = function (x, y, w, h, fit) {
5324         R.eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]);
5325         var width = this.width,
5326             height = this.height,
5327             size = 1 / mmax(w / width, h / height),
5328             H, W;
5329         if (fit) {
5330             H = height / h;
5331             W = width / w;
5332             if (w * H < width) {
5333                 x -= (width - w * H) / 2 / H;
5334             }
5335             if (h * W < height) {
5336                 y -= (height - h * W) / 2 / W;
5337             }
5338         }
5339         this._viewBox = [x, y, w, h, !!fit];
5340         this._viewBoxShift = {
5341             dx: -x,
5342             dy: -y,
5343             scale: size
5344         };
5345         this.forEach(function (el) {
5346             el.transform("...");
5347         });
5348         return this;
5349     };
5350     var createNode;
5351     R._engine.initWin = function (win) {
5352             var doc = win.document;
5353             doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
5354             try {
5355                 !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
5356                 createNode = function (tagName) {
5357                     return doc.createElement('<rvml:' + tagName + ' class="rvml">');
5358                 };
5359             } catch (e) {
5360                 createNode = function (tagName) {
5361                     return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
5362                 };
5363             }
5364         };
5365     R._engine.initWin(R._g.win);
5366     R._engine.create = function () {
5367         var con = R._getContainer.apply(0, arguments),
5368             container = con.container,
5369             height = con.height,
5370             s,
5371             width = con.width,
5372             x = con.x,
5373             y = con.y;
5374         if (!container) {
5375             throw new Error("VML container not found.");
5376         }
5377         var res = new R._Paper,
5378             c = res.canvas = R._g.doc.createElement("div"),
5379             cs = c.style;
5380         x = x || 0;
5381         y = y || 0;
5382         width = width || 512;
5383         height = height || 342;
5384         res.width = width;
5385         res.height = height;
5386         width == +width && (width += "px");
5387         height == +height && (height += "px");
5388         res.coordsize = zoom * 1e3 + S + zoom * 1e3;
5389         res.coordorigin = "0 0";
5390         res.span = R._g.doc.createElement("span");
5391         res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;";
5392         c.appendChild(res.span);
5393         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);
5394         if (container == 1) {
5395             R._g.doc.body.appendChild(c);
5396             cs.left = x + "px";
5397             cs.top = y + "px";
5398             cs.position = "absolute";
5399         } else {
5400             if (container.firstChild) {
5401                 container.insertBefore(c, container.firstChild);
5402             } else {
5403                 container.appendChild(c);
5404             }
5405         }
5406         // plugins.call(res, res, R.fn);
5407         res.renderfix = function () {};
5408         return res;
5409     };
5410     R.prototype.clear = function () {
5411         R.eve("clear", this);
5412         this.canvas.innerHTML = E;
5413         this.span = R._g.doc.createElement("span");
5414         this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";
5415         this.canvas.appendChild(this.span);
5416         this.bottom = this.top = null;
5417     };
5418     R.prototype.remove = function () {
5419         R.eve("remove", this);
5420         this.canvas.parentNode.removeChild(this.canvas);
5421         for (var i in this) {
5422             this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
5423         }
5424         return true;
5425     };
5426
5427     var setproto = R.st;
5428     for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
5429         setproto[method] = (function (methodname) {
5430             return function () {
5431                 var arg = arguments;
5432                 return this.forEach(function (el) {
5433                     el[methodname].apply(el, arg);
5434                 });
5435             };
5436         })(method);
5437     }
5438 }(window.Raphael);