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