source: trunk/themes/default/js/raphael.js @ 18630

Last change on this file since 18630 was 13168, checked in by plg, 12 years ago

feature 2575: redesign menubar on clear administration theme

SVG icons with raphael.js (not sure this is the best way to add icons, it's a test)

The menubar is sticked to the left border of the window.

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