1// Snap.svg 0.4.1
2//
3// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
17// build: 2015-04-13
18
19// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
20//
21// Licensed under the Apache License, Version 2.0 (the "License");
22// you may not use this file except in compliance with the License.
23// You may obtain a copy of the License at
24//
25// http://www.apache.org/licenses/LICENSE-2.0
26//
27// Unless required by applicable law or agreed to in writing, software
28// distributed under the License is distributed on an "AS IS" BASIS,
29// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30// See the License for the specific language governing permissions and
31// limitations under the License.
32// ┌────────────────────────────────────────────────────────────┐ \\
33// │ Eve 0.4.2 - JavaScript Events Library                      │ \\
34// ├────────────────────────────────────────────────────────────┤ \\
35// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\
36// └────────────────────────────────────────────────────────────┘ \\
37
38(function (glob) {
39    var version = "0.4.2",
40        has = "hasOwnProperty",
41        separator = /[\.\/]/,
42        comaseparator = /\s*,\s*/,
43        wildcard = "*",
44        fun = function () {},
45        numsort = function (a, b) {
46            return a - b;
47        },
48        current_event,
49        stop,
50        events = {n: {}},
51        firstDefined = function () {
52            for (var i = 0, ii = this.length; i < ii; i++) {
53                if (typeof this[i] != "undefined") {
54                    return this[i];
55                }
56            }
57        },
58        lastDefined = function () {
59            var i = this.length;
60            while (--i) {
61                if (typeof this[i] != "undefined") {
62                    return this[i];
63                }
64            }
65        },
66    /*\
67     * eve
68     [ method ]
69
70     * Fires event with given `name`, given scope and other parameters.
71
72     > Arguments
73
74     - name (string) name of the *event*, dot (`.`) or slash (`/`) separated
75     - scope (object) context for the event handlers
76     - varargs (...) the rest of arguments will be sent to event handlers
77
78     = (object) array of returned values from the listeners. Array has two methods `.firstDefined()` and `.lastDefined()` to get first or last not `undefined` value.
79    \*/
80        eve = function (name, scope) {
81            name = String(name);
82            var e = events,
83                oldstop = stop,
84                args = Array.prototype.slice.call(arguments, 2),
85                listeners = eve.listeners(name),
86                z = 0,
87                f = false,
88                l,
89                indexed = [],
90                queue = {},
91                out = [],
92                ce = current_event,
93                errors = [];
94            out.firstDefined = firstDefined;
95            out.lastDefined = lastDefined;
96            current_event = name;
97            stop = 0;
98            for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) {
99                indexed.push(listeners[i].zIndex);
100                if (listeners[i].zIndex < 0) {
101                    queue[listeners[i].zIndex] = listeners[i];
102                }
103            }
104            indexed.sort(numsort);
105            while (indexed[z] < 0) {
106                l = queue[indexed[z++]];
107                out.push(l.apply(scope, args));
108                if (stop) {
109                    stop = oldstop;
110                    return out;
111                }
112            }
113            for (i = 0; i < ii; i++) {
114                l = listeners[i];
115                if ("zIndex" in l) {
116                    if (l.zIndex == indexed[z]) {
117                        out.push(l.apply(scope, args));
118                        if (stop) {
119                            break;
120                        }
121                        do {
122                            z++;
123                            l = queue[indexed[z]];
124                            l && out.push(l.apply(scope, args));
125                            if (stop) {
126                                break;
127                            }
128                        } while (l)
129                    } else {
130                        queue[l.zIndex] = l;
131                    }
132                } else {
133                    out.push(l.apply(scope, args));
134                    if (stop) {
135                        break;
136                    }
137                }
138            }
139            stop = oldstop;
140            current_event = ce;
141            return out;
142        };
143        // Undocumented. Debug only.
144        eve._events = events;
145    /*\
146     * eve.listeners
147     [ method ]
148
149     * Internal method which gives you array of all event handlers that will be triggered by the given `name`.
150
151     > Arguments
152
153     - name (string) name of the event, dot (`.`) or slash (`/`) separated
154
155     = (array) array of event handlers
156    \*/
157    eve.listeners = function (name) {
158        var names = name.split(separator),
159            e = events,
160            item,
161            items,
162            k,
163            i,
164            ii,
165            j,
166            jj,
167            nes,
168            es = [e],
169            out = [];
170        for (i = 0, ii = names.length; i < ii; i++) {
171            nes = [];
172            for (j = 0, jj = es.length; j < jj; j++) {
173                e = es[j].n;
174                items = [e[names[i]], e[wildcard]];
175                k = 2;
176                while (k--) {
177                    item = items[k];
178                    if (item) {
179                        nes.push(item);
180                        out = out.concat(item.f || []);
181                    }
182                }
183            }
184            es = nes;
185        }
186        return out;
187    };
188
189    /*\
190     * eve.on
191     [ method ]
192     **
193     * Binds given event handler with a given name. You can use wildcards “`*`” for the names:
194     | eve.on("*.under.*", f);
195     | eve("mouse.under.floor"); // triggers f
196     * Use @eve to trigger the listener.
197     **
198     > Arguments
199     **
200     - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
201     - f (function) event handler function
202     **
203     = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment.
204     > Example:
205     | eve.on("mouse", eatIt)(2);
206     | eve.on("mouse", scream);
207     | eve.on("mouse", catchIt)(1);
208     * This will ensure that `catchIt` function will be called before `eatIt`.
209     *
210     * If you want to put your handler before non-indexed handlers, specify a negative value.
211     * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”.
212    \*/
213    eve.on = function (name, f) {
214        name = String(name);
215        if (typeof f != "function") {
216            return function () {};
217        }
218        var names = name.split(comaseparator);
219        for (var i = 0, ii = names.length; i < ii; i++) {
220            (function (name) {
221                var names = name.split(separator),
222                    e = events,
223                    exist;
224                for (var i = 0, ii = names.length; i < ii; i++) {
225                    e = e.n;
226                    e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}});
227                }
228                e.f = e.f || [];
229                for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) {
230                    exist = true;
231                    break;
232                }
233                !exist && e.f.push(f);
234            }(names[i]));
235        }
236        return function (zIndex) {
237            if (+zIndex == +zIndex) {
238                f.zIndex = +zIndex;
239            }
240        };
241    };
242    /*\
243     * eve.f
244     [ method ]
245     **
246     * Returns function that will fire given event with optional arguments.
247     * Arguments that will be passed to the result function will be also
248     * concated to the list of final arguments.
249     | el.onclick = eve.f("click", 1, 2);
250     | eve.on("click", function (a, b, c) {
251     |     console.log(a, b, c); // 1, 2, [event object]
252     | });
253     > Arguments
254     - event (string) event name
255     - varargs (…) and any other arguments
256     = (function) possible event handler function
257    \*/
258    eve.f = function (event) {
259        var attrs = [].slice.call(arguments, 1);
260        return function () {
261            eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0)));
262        };
263    };
264    /*\
265     * eve.stop
266     [ method ]
267     **
268     * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing.
269    \*/
270    eve.stop = function () {
271        stop = 1;
272    };
273    /*\
274     * eve.nt
275     [ method ]
276     **
277     * Could be used inside event handler to figure out actual name of the event.
278     **
279     > Arguments
280     **
281     - subname (string) #optional subname of the event
282     **
283     = (string) name of the event, if `subname` is not specified
284     * or
285     = (boolean) `true`, if current event’s name contains `subname`
286    \*/
287    eve.nt = function (subname) {
288        if (subname) {
289            return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event);
290        }
291        return current_event;
292    };
293    /*\
294     * eve.nts
295     [ method ]
296     **
297     * Could be used inside event handler to figure out actual name of the event.
298     **
299     **
300     = (array) names of the event
301    \*/
302    eve.nts = function () {
303        return current_event.split(separator);
304    };
305    /*\
306     * eve.off
307     [ method ]
308     **
309     * Removes given function from the list of event listeners assigned to given name.
310     * If no arguments specified all the events will be cleared.
311     **
312     > Arguments
313     **
314     - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
315     - f (function) event handler function
316    \*/
317    /*\
318     * eve.unbind
319     [ method ]
320     **
321     * See @eve.off
322    \*/
323    eve.off = eve.unbind = function (name, f) {
324        if (!name) {
325            eve._events = events = {n: {}};
326            return;
327        }
328        var names = name.split(comaseparator);
329        if (names.length > 1) {
330            for (var i = 0, ii = names.length; i < ii; i++) {
331                eve.off(names[i], f);
332            }
333            return;
334        }
335        names = name.split(separator);
336        var e,
337            key,
338            splice,
339            i, ii, j, jj,
340            cur = [events];
341        for (i = 0, ii = names.length; i < ii; i++) {
342            for (j = 0; j < cur.length; j += splice.length - 2) {
343                splice = [j, 1];
344                e = cur[j].n;
345                if (names[i] != wildcard) {
346                    if (e[names[i]]) {
347                        splice.push(e[names[i]]);
348                    }
349                } else {
350                    for (key in e) if (e[has](key)) {
351                        splice.push(e[key]);
352                    }
353                }
354                cur.splice.apply(cur, splice);
355            }
356        }
357        for (i = 0, ii = cur.length; i < ii; i++) {
358            e = cur[i];
359            while (e.n) {
360                if (f) {
361                    if (e.f) {
362                        for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) {
363                            e.f.splice(j, 1);
364                            break;
365                        }
366                        !e.f.length && delete e.f;
367                    }
368                    for (key in e.n) if (e.n[has](key) && e.n[key].f) {
369                        var funcs = e.n[key].f;
370                        for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) {
371                            funcs.splice(j, 1);
372                            break;
373                        }
374                        !funcs.length && delete e.n[key].f;
375                    }
376                } else {
377                    delete e.f;
378                    for (key in e.n) if (e.n[has](key) && e.n[key].f) {
379                        delete e.n[key].f;
380                    }
381                }
382                e = e.n;
383            }
384        }
385    };
386    /*\
387     * eve.once
388     [ method ]
389     **
390     * Binds given event handler with a given name to only run once then unbind itself.
391     | eve.once("login", f);
392     | eve("login"); // triggers f
393     | eve("login"); // no listeners
394     * Use @eve to trigger the listener.
395     **
396     > Arguments
397     **
398     - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
399     - f (function) event handler function
400     **
401     = (function) same return function as @eve.on
402    \*/
403    eve.once = function (name, f) {
404        var f2 = function () {
405            eve.unbind(name, f2);
406            return f.apply(this, arguments);
407        };
408        return eve.on(name, f2);
409    };
410    /*\
411     * eve.version
412     [ property (string) ]
413     **
414     * Current version of the library.
415    \*/
416    eve.version = version;
417    eve.toString = function () {
418        return "You are running Eve " + version;
419    };
420    (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define === "function" && define.amd ? (define("eve", [], function() { return eve; })) : (glob.eve = eve));
421})(this);
422
423(function (glob, factory) {
424    // AMD support
425    if (typeof define == "function" && define.amd) {
426        // Define as an anonymous module
427        define(["eve"], function (eve) {
428            return factory(glob, eve);
429        });
430    } else if (typeof exports != 'undefined') {
431        // Next for Node.js or CommonJS
432        var eve = require('eve');
433        module.exports = factory(glob, eve);
434    } else {
435        // Browser globals (glob is window)
436        // Snap adds itself to window
437        factory(glob, glob.eve);
438    }
439}(window || this, function (window, eve) {
440
441// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
442//
443// Licensed under the Apache License, Version 2.0 (the "License");
444// you may not use this file except in compliance with the License.
445// You may obtain a copy of the License at
446//
447// http://www.apache.org/licenses/LICENSE-2.0
448//
449// Unless required by applicable law or agreed to in writing, software
450// distributed under the License is distributed on an "AS IS" BASIS,
451// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
452// See the License for the specific language governing permissions and
453// limitations under the License.
454var mina = (function (eve) {
455    var animations = {},
456    requestAnimFrame = window.requestAnimationFrame       ||
457                       window.webkitRequestAnimationFrame ||
458                       window.mozRequestAnimationFrame    ||
459                       window.oRequestAnimationFrame      ||
460                       window.msRequestAnimationFrame     ||
461                       function (callback) {
462                           setTimeout(callback, 16);
463                       },
464    isArray = Array.isArray || function (a) {
465        return a instanceof Array ||
466            Object.prototype.toString.call(a) == "[object Array]";
467    },
468    idgen = 0,
469    idprefix = "M" + (+new Date).toString(36),
470    ID = function () {
471        return idprefix + (idgen++).toString(36);
472    },
473    diff = function (a, b, A, B) {
474        if (isArray(a)) {
475            res = [];
476            for (var i = 0, ii = a.length; i < ii; i++) {
477                res[i] = diff(a[i], b, A[i], B);
478            }
479            return res;
480        }
481        var dif = (A - a) / (B - b);
482        return function (bb) {
483            return a + dif * (bb - b);
484        };
485    },
486    timer = Date.now || function () {
487        return +new Date;
488    },
489    sta = function (val) {
490        var a = this;
491        if (val == null) {
492            return a.s;
493        }
494        var ds = a.s - val;
495        a.b += a.dur * ds;
496        a.B += a.dur * ds;
497        a.s = val;
498    },
499    speed = function (val) {
500        var a = this;
501        if (val == null) {
502            return a.spd;
503        }
504        a.spd = val;
505    },
506    duration = function (val) {
507        var a = this;
508        if (val == null) {
509            return a.dur;
510        }
511        a.s = a.s * val / a.dur;
512        a.dur = val;
513    },
514    stopit = function () {
515        var a = this;
516        delete animations[a.id];
517        a.update();
518        eve("mina.stop." + a.id, a);
519    },
520    pause = function () {
521        var a = this;
522        if (a.pdif) {
523            return;
524        }
525        delete animations[a.id];
526        a.update();
527        a.pdif = a.get() - a.b;
528    },
529    resume = function () {
530        var a = this;
531        if (!a.pdif) {
532            return;
533        }
534        a.b = a.get() - a.pdif;
535        delete a.pdif;
536        animations[a.id] = a;
537    },
538    update = function () {
539        var a = this,
540            res;
541        if (isArray(a.start)) {
542            res = [];
543            for (var j = 0, jj = a.start.length; j < jj; j++) {
544                res[j] = +a.start[j] +
545                    (a.end[j] - a.start[j]) * a.easing(a.s);
546            }
547        } else {
548            res = +a.start + (a.end - a.start) * a.easing(a.s);
549        }
550        a.set(res);
551    },
552    frame = function () {
553        var len = 0;
554        for (var i in animations) if (animations.hasOwnProperty(i)) {
555            var a = animations[i],
556                b = a.get(),
557                res;
558            len++;
559            a.s = (b - a.b) / (a.dur / a.spd);
560            if (a.s >= 1) {
561                delete animations[i];
562                a.s = 1;
563                len--;
564                (function (a) {
565                    setTimeout(function () {
566                        eve("mina.finish." + a.id, a);
567                    });
568                }(a));
569            }
570            a.update();
571        }
572        len && requestAnimFrame(frame);
573    },
574    /*\
575     * mina
576     [ method ]
577     **
578     * Generic animation of numbers
579     **
580     - a (number) start _slave_ number
581     - A (number) end _slave_ number
582     - b (number) start _master_ number (start time in general case)
583     - B (number) end _master_ number (end time in gereal case)
584     - get (function) getter of _master_ number (see @mina.time)
585     - set (function) setter of _slave_ number
586     - easing (function) #optional easing function, default is @mina.linear
587     = (object) animation descriptor
588     o {
589     o         id (string) animation id,
590     o         start (number) start _slave_ number,
591     o         end (number) end _slave_ number,
592     o         b (number) start _master_ number,
593     o         s (number) animation status (0..1),
594     o         dur (number) animation duration,
595     o         spd (number) animation speed,
596     o         get (function) getter of _master_ number (see @mina.time),
597     o         set (function) setter of _slave_ number,
598     o         easing (function) easing function, default is @mina.linear,
599     o         status (function) status getter/setter,
600     o         speed (function) speed getter/setter,
601     o         duration (function) duration getter/setter,
602     o         stop (function) animation stopper
603     o         pause (function) pauses the animation
604     o         resume (function) resumes the animation
605     o         update (function) calles setter with the right value of the animation
606     o }
607    \*/
608    mina = function (a, A, b, B, get, set, easing) {
609        var anim = {
610            id: ID(),
611            start: a,
612            end: A,
613            b: b,
614            s: 0,
615            dur: B - b,
616            spd: 1,
617            get: get,
618            set: set,
619            easing: easing || mina.linear,
620            status: sta,
621            speed: speed,
622            duration: duration,
623            stop: stopit,
624            pause: pause,
625            resume: resume,
626            update: update
627        };
628        animations[anim.id] = anim;
629        var len = 0, i;
630        for (i in animations) if (animations.hasOwnProperty(i)) {
631            len++;
632            if (len == 2) {
633                break;
634            }
635        }
636        len == 1 && requestAnimFrame(frame);
637        return anim;
638    };
639    /*\
640     * mina.time
641     [ method ]
642     **
643     * Returns the current time. Equivalent to:
644     | function () {
645     |     return (new Date).getTime();
646     | }
647    \*/
648    mina.time = timer;
649    /*\
650     * mina.getById
651     [ method ]
652     **
653     * Returns an animation by its id
654     - id (string) animation's id
655     = (object) See @mina
656    \*/
657    mina.getById = function (id) {
658        return animations[id] || null;
659    };
660
661    /*\
662     * mina.linear
663     [ method ]
664     **
665     * Default linear easing
666     - n (number) input 0..1
667     = (number) output 0..1
668    \*/
669    mina.linear = function (n) {
670        return n;
671    };
672    /*\
673     * mina.easeout
674     [ method ]
675     **
676     * Easeout easing
677     - n (number) input 0..1
678     = (number) output 0..1
679    \*/
680    mina.easeout = function (n) {
681        return Math.pow(n, 1.7);
682    };
683    /*\
684     * mina.easein
685     [ method ]
686     **
687     * Easein easing
688     - n (number) input 0..1
689     = (number) output 0..1
690    \*/
691    mina.easein = function (n) {
692        return Math.pow(n, .48);
693    };
694    /*\
695     * mina.easeinout
696     [ method ]
697     **
698     * Easeinout easing
699     - n (number) input 0..1
700     = (number) output 0..1
701    \*/
702    mina.easeinout = function (n) {
703        if (n == 1) {
704            return 1;
705        }
706        if (n == 0) {
707            return 0;
708        }
709        var q = .48 - n / 1.04,
710            Q = Math.sqrt(.1734 + q * q),
711            x = Q - q,
712            X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1),
713            y = -Q - q,
714            Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1),
715            t = X + Y + .5;
716        return (1 - t) * 3 * t * t + t * t * t;
717    };
718    /*\
719     * mina.backin
720     [ method ]
721     **
722     * Backin easing
723     - n (number) input 0..1
724     = (number) output 0..1
725    \*/
726    mina.backin = function (n) {
727        if (n == 1) {
728            return 1;
729        }
730        var s = 1.70158;
731        return n * n * ((s + 1) * n - s);
732    };
733    /*\
734     * mina.backout
735     [ method ]
736     **
737     * Backout easing
738     - n (number) input 0..1
739     = (number) output 0..1
740    \*/
741    mina.backout = function (n) {
742        if (n == 0) {
743            return 0;
744        }
745        n = n - 1;
746        var s = 1.70158;
747        return n * n * ((s + 1) * n + s) + 1;
748    };
749    /*\
750     * mina.elastic
751     [ method ]
752     **
753     * Elastic easing
754     - n (number) input 0..1
755     = (number) output 0..1
756    \*/
757    mina.elastic = function (n) {
758        if (n == !!n) {
759            return n;
760        }
761        return Math.pow(2, -10 * n) * Math.sin((n - .075) *
762            (2 * Math.PI) / .3) + 1;
763    };
764    /*\
765     * mina.bounce
766     [ method ]
767     **
768     * Bounce easing
769     - n (number) input 0..1
770     = (number) output 0..1
771    \*/
772    mina.bounce = function (n) {
773        var s = 7.5625,
774            p = 2.75,
775            l;
776        if (n < (1 / p)) {
777            l = s * n * n;
778        } else {
779            if (n < (2 / p)) {
780                n -= (1.5 / p);
781                l = s * n * n + .75;
782            } else {
783                if (n < (2.5 / p)) {
784                    n -= (2.25 / p);
785                    l = s * n * n + .9375;
786                } else {
787                    n -= (2.625 / p);
788                    l = s * n * n + .984375;
789                }
790            }
791        }
792        return l;
793    };
794    window.mina = mina;
795    return mina;
796})(typeof eve == "undefined" ? function () {} : eve);
797// Copyright (c) 2013 - 2015 Adobe Systems Incorporated. All rights reserved.
798//
799// Licensed under the Apache License, Version 2.0 (the "License");
800// you may not use this file except in compliance with the License.
801// You may obtain a copy of the License at
802//
803// http://www.apache.org/licenses/LICENSE-2.0
804//
805// Unless required by applicable law or agreed to in writing, software
806// distributed under the License is distributed on an "AS IS" BASIS,
807// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
808// See the License for the specific language governing permissions and
809// limitations under the License.
810
811var Snap = (function(root) {
812Snap.version = "0.4.0";
813/*\
814 * Snap
815 [ method ]
816 **
817 * Creates a drawing surface or wraps existing SVG element.
818 **
819 - width (number|string) width of surface
820 - height (number|string) height of surface
821 * or
822 - DOM (SVGElement) element to be wrapped into Snap structure
823 * or
824 - array (array) array of elements (will return set of elements)
825 * or
826 - query (string) CSS query selector
827 = (object) @Element
828\*/
829function Snap(w, h) {
830    if (w) {
831        if (w.nodeType) {
832            return wrap(w);
833        }
834        if (is(w, "array") && Snap.set) {
835            return Snap.set.apply(Snap, w);
836        }
837        if (w instanceof Element) {
838            return w;
839        }
840        if (h == null) {
841            w = glob.doc.querySelector(String(w));
842            return wrap(w);
843        }
844    }
845    w = w == null ? "100%" : w;
846    h = h == null ? "100%" : h;
847    return new Paper(w, h);
848}
849Snap.toString = function () {
850    return "Snap v" + this.version;
851};
852Snap._ = {};
853var glob = {
854    win: root.window,
855    doc: root.window.document
856};
857Snap._.glob = glob;
858var has = "hasOwnProperty",
859    Str = String,
860    toFloat = parseFloat,
861    toInt = parseInt,
862    math = Math,
863    mmax = math.max,
864    mmin = math.min,
865    abs = math.abs,
866    pow = math.pow,
867    PI = math.PI,
868    round = math.round,
869    E = "",
870    S = " ",
871    objectToString = Object.prototype.toString,
872    ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i,
873    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,
874    bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
875    reURLValue = /^url\(#?([^)]+)\)$/,
876    separator = Snap._.separator = /[,\s]+/,
877    whitespace = /[\s]/g,
878    commaSpaces = /[\s]*,[\s]*/,
879    hsrg = {hs: 1, rg: 1},
880    pathCommand = /([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig,
881    tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig,
882    pathValues = /(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/ig,
883    idgen = 0,
884    idprefix = "S" + (+new Date).toString(36),
885    ID = function (el) {
886        return (el && el.type ? el.type : E) + idprefix + (idgen++).toString(36);
887    },
888    xlink = "http://www.w3.org/1999/xlink",
889    xmlns = "http://www.w3.org/2000/svg",
890    hub = {},
891    URL = Snap.url = function (url) {
892        return "url('#" + url + "')";
893    };
894
895function $(el, attr) {
896    if (attr) {
897        if (el == "#text") {
898            el = glob.doc.createTextNode(attr.text || attr["#text"] || "");
899        }
900        if (el == "#comment") {
901            el = glob.doc.createComment(attr.text || attr["#text"] || "");
902        }
903        if (typeof el == "string") {
904            el = $(el);
905        }
906        if (typeof attr == "string") {
907            if (el.nodeType == 1) {
908                if (attr.substring(0, 6) == "xlink:") {
909                    return el.getAttributeNS(xlink, attr.substring(6));
910                }
911                if (attr.substring(0, 4) == "xml:") {
912                    return el.getAttributeNS(xmlns, attr.substring(4));
913                }
914                return el.getAttribute(attr);
915            } else if (attr == "text") {
916                return el.nodeValue;
917            } else {
918                return null;
919            }
920        }
921        if (el.nodeType == 1) {
922            for (var key in attr) if (attr[has](key)) {
923                var val = Str(attr[key]);
924                if (val) {
925                    if (key.substring(0, 6) == "xlink:") {
926                        el.setAttributeNS(xlink, key.substring(6), val);
927                    } else if (key.substring(0, 4) == "xml:") {
928                        el.setAttributeNS(xmlns, key.substring(4), val);
929                    } else {
930                        el.setAttribute(key, val);
931                    }
932                } else {
933                    el.removeAttribute(key);
934                }
935            }
936        } else if ("text" in attr) {
937            el.nodeValue = attr.text;
938        }
939    } else {
940        el = glob.doc.createElementNS(xmlns, el);
941    }
942    return el;
943}
944Snap._.$ = $;
945Snap._.id = ID;
946function getAttrs(el) {
947    var attrs = el.attributes,
948        name,
949        out = {};
950    for (var i = 0; i < attrs.length; i++) {
951        if (attrs[i].namespaceURI == xlink) {
952            name = "xlink:";
953        } else {
954            name = "";
955        }
956        name += attrs[i].name;
957        out[name] = attrs[i].textContent;
958    }
959    return out;
960}
961function is(o, type) {
962    type = Str.prototype.toLowerCase.call(type);
963    if (type == "finite") {
964        return isFinite(o);
965    }
966    if (type == "array" &&
967        (o instanceof Array || Array.isArray && Array.isArray(o))) {
968        return true;
969    }
970    return  (type == "null" && o === null) ||
971            (type == typeof o && o !== null) ||
972            (type == "object" && o === Object(o)) ||
973            objectToString.call(o).slice(8, -1).toLowerCase() == type;
974}
975/*\
976 * Snap.format
977 [ method ]
978 **
979 * Replaces construction of type `{<name>}` to the corresponding argument
980 **
981 - token (string) string to format
982 - json (object) object which properties are used as a replacement
983 = (string) formatted string
984 > Usage
985 | // this draws a rectangular shape equivalent to "M10,20h40v50h-40z"
986 | paper.path(Snap.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", {
987 |     x: 10,
988 |     y: 20,
989 |     dim: {
990 |         width: 40,
991 |         height: 50,
992 |         "negative width": -40
993 |     }
994 | }));
995\*/
996Snap.format = (function () {
997    var tokenRegex = /\{([^\}]+)\}/g,
998        objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
999        replacer = function (all, key, obj) {
1000            var res = obj;
1001            key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
1002                name = name || quotedName;
1003                if (res) {
1004                    if (name in res) {
1005                        res = res[name];
1006                    }
1007                    typeof res == "function" && isFunc && (res = res());
1008                }
1009            });
1010            res = (res == null || res == obj ? all : res) + "";
1011            return res;
1012        };
1013    return function (str, obj) {
1014        return Str(str).replace(tokenRegex, function (all, key) {
1015            return replacer(all, key, obj);
1016        });
1017    };
1018})();
1019function clone(obj) {
1020    if (typeof obj == "function" || Object(obj) !== obj) {
1021        return obj;
1022    }
1023    var res = new obj.constructor;
1024    for (var key in obj) if (obj[has](key)) {
1025        res[key] = clone(obj[key]);
1026    }
1027    return res;
1028}
1029Snap._.clone = clone;
1030function repush(array, item) {
1031    for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) {
1032        return array.push(array.splice(i, 1)[0]);
1033    }
1034}
1035function cacher(f, scope, postprocessor) {
1036    function newf() {
1037        var arg = Array.prototype.slice.call(arguments, 0),
1038            args = arg.join("\u2400"),
1039            cache = newf.cache = newf.cache || {},
1040            count = newf.count = newf.count || [];
1041        if (cache[has](args)) {
1042            repush(count, args);
1043            return postprocessor ? postprocessor(cache[args]) : cache[args];
1044        }
1045        count.length >= 1e3 && delete cache[count.shift()];
1046        count.push(args);
1047        cache[args] = f.apply(scope, arg);
1048        return postprocessor ? postprocessor(cache[args]) : cache[args];
1049    }
1050    return newf;
1051}
1052Snap._.cacher = cacher;
1053function angle(x1, y1, x2, y2, x3, y3) {
1054    if (x3 == null) {
1055        var x = x1 - x2,
1056            y = y1 - y2;
1057        if (!x && !y) {
1058            return 0;
1059        }
1060        return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360;
1061    } else {
1062        return angle(x1, y1, x3, y3) - angle(x2, y2, x3, y3);
1063    }
1064}
1065function rad(deg) {
1066    return deg % 360 * PI / 180;
1067}
1068function deg(rad) {
1069    return rad * 180 / PI % 360;
1070}
1071function x_y() {
1072    return this.x + S + this.y;
1073}
1074function x_y_w_h() {
1075    return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
1076}
1077
1078/*\
1079 * Snap.rad
1080 [ method ]
1081 **
1082 * Transform angle to radians
1083 - deg (number) angle in degrees
1084 = (number) angle in radians
1085\*/
1086Snap.rad = rad;
1087/*\
1088 * Snap.deg
1089 [ method ]
1090 **
1091 * Transform angle to degrees
1092 - rad (number) angle in radians
1093 = (number) angle in degrees
1094\*/
1095Snap.deg = deg;
1096/*\
1097 * Snap.sin
1098 [ method ]
1099 **
1100 * Equivalent to `Math.sin()` only works with degrees, not radians.
1101 - angle (number) angle in degrees
1102 = (number) sin
1103\*/
1104Snap.sin = function (angle) {
1105    return math.sin(Snap.rad(angle));
1106};
1107/*\
1108 * Snap.tan
1109 [ method ]
1110 **
1111 * Equivalent to `Math.tan()` only works with degrees, not radians.
1112 - angle (number) angle in degrees
1113 = (number) tan
1114\*/
1115Snap.tan = function (angle) {
1116    return math.tan(Snap.rad(angle));
1117};
1118/*\
1119 * Snap.cos
1120 [ method ]
1121 **
1122 * Equivalent to `Math.cos()` only works with degrees, not radians.
1123 - angle (number) angle in degrees
1124 = (number) cos
1125\*/
1126Snap.cos = function (angle) {
1127    return math.cos(Snap.rad(angle));
1128};
1129/*\
1130 * Snap.asin
1131 [ method ]
1132 **
1133 * Equivalent to `Math.asin()` only works with degrees, not radians.
1134 - num (number) value
1135 = (number) asin in degrees
1136\*/
1137Snap.asin = function (num) {
1138    return Snap.deg(math.asin(num));
1139};
1140/*\
1141 * Snap.acos
1142 [ method ]
1143 **
1144 * Equivalent to `Math.acos()` only works with degrees, not radians.
1145 - num (number) value
1146 = (number) acos in degrees
1147\*/
1148Snap.acos = function (num) {
1149    return Snap.deg(math.acos(num));
1150};
1151/*\
1152 * Snap.atan
1153 [ method ]
1154 **
1155 * Equivalent to `Math.atan()` only works with degrees, not radians.
1156 - num (number) value
1157 = (number) atan in degrees
1158\*/
1159Snap.atan = function (num) {
1160    return Snap.deg(math.atan(num));
1161};
1162/*\
1163 * Snap.atan2
1164 [ method ]
1165 **
1166 * Equivalent to `Math.atan2()` only works with degrees, not radians.
1167 - num (number) value
1168 = (number) atan2 in degrees
1169\*/
1170Snap.atan2 = function (num) {
1171    return Snap.deg(math.atan2(num));
1172};
1173/*\
1174 * Snap.angle
1175 [ method ]
1176 **
1177 * Returns an angle between two or three points
1178 > Parameters
1179 - x1 (number) x coord of first point
1180 - y1 (number) y coord of first point
1181 - x2 (number) x coord of second point
1182 - y2 (number) y coord of second point
1183 - x3 (number) #optional x coord of third point
1184 - y3 (number) #optional y coord of third point
1185 = (number) angle in degrees
1186\*/
1187Snap.angle = angle;
1188/*\
1189 * Snap.len
1190 [ method ]
1191 **
1192 * Returns distance between two points
1193 > Parameters
1194 - x1 (number) x coord of first point
1195 - y1 (number) y coord of first point
1196 - x2 (number) x coord of second point
1197 - y2 (number) y coord of second point
1198 = (number) distance
1199\*/
1200Snap.len = function (x1, y1, x2, y2) {
1201    return Math.sqrt(Snap.len2(x1, y1, x2, y2));
1202};
1203/*\
1204 * Snap.len2
1205 [ method ]
1206 **
1207 * Returns squared distance between two points
1208 > Parameters
1209 - x1 (number) x coord of first point
1210 - y1 (number) y coord of first point
1211 - x2 (number) x coord of second point
1212 - y2 (number) y coord of second point
1213 = (number) distance
1214\*/
1215Snap.len2 = function (x1, y1, x2, y2) {
1216    return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
1217};
1218/*\
1219 * Snap.closestPoint
1220 [ method ]
1221 **
1222 * Returns closest point to a given one on a given path.
1223 > Parameters
1224 - path (Element) path element
1225 - x (number) x coord of a point
1226 - y (number) y coord of a point
1227 = (object) in format
1228 {
1229    x (number) x coord of the point on the path
1230    y (number) y coord of the point on the path
1231    length (number) length of the path to the point
1232    distance (number) distance from the given point to the path
1233 }
1234\*/
1235// Copied from http://bl.ocks.org/mbostock/8027637
1236Snap.closestPoint = function (path, x, y) {
1237    function distance2(p) {
1238        var dx = p.x - x,
1239            dy = p.y - y;
1240        return dx * dx + dy * dy;
1241    }
1242    var pathNode = path.node,
1243        pathLength = pathNode.getTotalLength(),
1244        precision = pathLength / pathNode.pathSegList.numberOfItems * .125,
1245        best,
1246        bestLength,
1247        bestDistance = Infinity;
1248
1249    // linear scan for coarse approximation
1250    for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {
1251        if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) {
1252            best = scan, bestLength = scanLength, bestDistance = scanDistance;
1253        }
1254    }
1255
1256    // binary search for precise estimate
1257    precision *= .5;
1258    while (precision > .5) {
1259        var before,
1260            after,
1261            beforeLength,
1262            afterLength,
1263            beforeDistance,
1264            afterDistance;
1265        if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) {
1266            best = before, bestLength = beforeLength, bestDistance = beforeDistance;
1267        } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) {
1268            best = after, bestLength = afterLength, bestDistance = afterDistance;
1269        } else {
1270            precision *= .5;
1271        }
1272    }
1273
1274    best = {
1275        x: best.x,
1276        y: best.y,
1277        length: bestLength,
1278        distance: Math.sqrt(bestDistance)
1279    };
1280    return best;
1281}
1282/*\
1283 * Snap.is
1284 [ method ]
1285 **
1286 * Handy replacement for the `typeof` operator
1287 - o (…) any object or primitive
1288 - type (string) name of the type, e.g., `string`, `function`, `number`, etc.
1289 = (boolean) `true` if given value is of given type
1290\*/
1291Snap.is = is;
1292/*\
1293 * Snap.snapTo
1294 [ method ]
1295 **
1296 * Snaps given value to given grid
1297 - values (array|number) given array of values or step of the grid
1298 - value (number) value to adjust
1299 - tolerance (number) #optional maximum distance to the target value that would trigger the snap. Default is `10`.
1300 = (number) adjusted value
1301\*/
1302Snap.snapTo = function (values, value, tolerance) {
1303    tolerance = is(tolerance, "finite") ? tolerance : 10;
1304    if (is(values, "array")) {
1305        var i = values.length;
1306        while (i--) if (abs(values[i] - value) <= tolerance) {
1307            return values[i];
1308        }
1309    } else {
1310        values = +values;
1311        var rem = value % values;
1312        if (rem < tolerance) {
1313            return value - rem;
1314        }
1315        if (rem > values - tolerance) {
1316            return value - rem + values;
1317        }
1318    }
1319    return value;
1320};
1321// Colour
1322/*\
1323 * Snap.getRGB
1324 [ method ]
1325 **
1326 * Parses color string as RGB object
1327 - color (string) color string in one of the following formats:
1328 # <ul>
1329 #     <li>Color name (<code>red</code>, <code>green</code>, <code>cornflowerblue</code>, etc)</li>
1330 #     <li>#••• — shortened HTML color: (<code>#000</code>, <code>#fc0</code>, etc.)</li>
1331 #     <li>#•••••• — full length HTML color: (<code>#000000</code>, <code>#bd2300</code>)</li>
1332 #     <li>rgb(•••, •••, •••) — red, green and blue channels values: (<code>rgb(200,&nbsp;100,&nbsp;0)</code>)</li>
1333 #     <li>rgba(•••, •••, •••, •••) — also with opacity</li>
1334 #     <li>rgb(•••%, •••%, •••%) — same as above, but in %: (<code>rgb(100%,&nbsp;175%,&nbsp;0%)</code>)</li>
1335 #     <li>rgba(•••%, •••%, •••%, •••%) — also with opacity</li>
1336 #     <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (<code>hsb(0.5,&nbsp;0.25,&nbsp;1)</code>)</li>
1337 #     <li>hsba(•••, •••, •••, •••) — also with opacity</li>
1338 #     <li>hsb(•••%, •••%, •••%) — same as above, but in %</li>
1339 #     <li>hsba(•••%, •••%, •••%, •••%) — also with opacity</li>
1340 #     <li>hsl(•••, •••, •••) — hue, saturation and luminosity values: (<code>hsb(0.5,&nbsp;0.25,&nbsp;0.5)</code>)</li>
1341 #     <li>hsla(•••, •••, •••, •••) — also with opacity</li>
1342 #     <li>hsl(•••%, •••%, •••%) — same as above, but in %</li>
1343 #     <li>hsla(•••%, •••%, •••%, •••%) — also with opacity</li>
1344 # </ul>
1345 * Note that `%` can be used any time: `rgb(20%, 255, 50%)`.
1346 = (object) RGB object in the following format:
1347 o {
1348 o     r (number) red,
1349 o     g (number) green,
1350 o     b (number) blue,
1351 o     hex (string) color in HTML/CSS format: #••••••,
1352 o     error (boolean) true if string can't be parsed
1353 o }
1354\*/
1355Snap.getRGB = cacher(function (colour) {
1356    if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) {
1357        return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
1358    }
1359    if (colour == "none") {
1360        return {r: -1, g: -1, b: -1, hex: "none", toString: rgbtoString};
1361    }
1362    !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour));
1363    if (!colour) {
1364        return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
1365    }
1366    var res,
1367        red,
1368        green,
1369        blue,
1370        opacity,
1371        t,
1372        values,
1373        rgb = colour.match(colourRegExp);
1374    if (rgb) {
1375        if (rgb[2]) {
1376            blue = toInt(rgb[2].substring(5), 16);
1377            green = toInt(rgb[2].substring(3, 5), 16);
1378            red = toInt(rgb[2].substring(1, 3), 16);
1379        }
1380        if (rgb[3]) {
1381            blue = toInt((t = rgb[3].charAt(3)) + t, 16);
1382            green = toInt((t = rgb[3].charAt(2)) + t, 16);
1383            red = toInt((t = rgb[3].charAt(1)) + t, 16);
1384        }
1385        if (rgb[4]) {
1386            values = rgb[4].split(commaSpaces);
1387            red = toFloat(values[0]);
1388            values[0].slice(-1) == "%" && (red *= 2.55);
1389            green = toFloat(values[1]);
1390            values[1].slice(-1) == "%" && (green *= 2.55);
1391            blue = toFloat(values[2]);
1392            values[2].slice(-1) == "%" && (blue *= 2.55);
1393            rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3]));
1394            values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
1395        }
1396        if (rgb[5]) {
1397            values = rgb[5].split(commaSpaces);
1398            red = toFloat(values[0]);
1399            values[0].slice(-1) == "%" && (red /= 100);
1400            green = toFloat(values[1]);
1401            values[1].slice(-1) == "%" && (green /= 100);
1402            blue = toFloat(values[2]);
1403            values[2].slice(-1) == "%" && (blue /= 100);
1404            (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
1405            rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3]));
1406            values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
1407            return Snap.hsb2rgb(red, green, blue, opacity);
1408        }
1409        if (rgb[6]) {
1410            values = rgb[6].split(commaSpaces);
1411            red = toFloat(values[0]);
1412            values[0].slice(-1) == "%" && (red /= 100);
1413            green = toFloat(values[1]);
1414            values[1].slice(-1) == "%" && (green /= 100);
1415            blue = toFloat(values[2]);
1416            values[2].slice(-1) == "%" && (blue /= 100);
1417            (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
1418            rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3]));
1419            values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
1420            return Snap.hsl2rgb(red, green, blue, opacity);
1421        }
1422        red = mmin(math.round(red), 255);
1423        green = mmin(math.round(green), 255);
1424        blue = mmin(math.round(blue), 255);
1425        opacity = mmin(mmax(opacity, 0), 1);
1426        rgb = {r: red, g: green, b: blue, toString: rgbtoString};
1427        rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1);
1428        rgb.opacity = is(opacity, "finite") ? opacity : 1;
1429        return rgb;
1430    }
1431    return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
1432}, Snap);
1433/*\
1434 * Snap.hsb
1435 [ method ]
1436 **
1437 * Converts HSB values to a hex representation of the color
1438 - h (number) hue
1439 - s (number) saturation
1440 - b (number) value or brightness
1441 = (string) hex representation of the color
1442\*/
1443Snap.hsb = cacher(function (h, s, b) {
1444    return Snap.hsb2rgb(h, s, b).hex;
1445});
1446/*\
1447 * Snap.hsl
1448 [ method ]
1449 **
1450 * Converts HSL values to a hex representation of the color
1451 - h (number) hue
1452 - s (number) saturation
1453 - l (number) luminosity
1454 = (string) hex representation of the color
1455\*/
1456Snap.hsl = cacher(function (h, s, l) {
1457    return Snap.hsl2rgb(h, s, l).hex;
1458});
1459/*\
1460 * Snap.rgb
1461 [ method ]
1462 **
1463 * Converts RGB values to a hex representation of the color
1464 - r (number) red
1465 - g (number) green
1466 - b (number) blue
1467 = (string) hex representation of the color
1468\*/
1469Snap.rgb = cacher(function (r, g, b, o) {
1470    if (is(o, "finite")) {
1471        var round = math.round;
1472        return "rgba(" + [round(r), round(g), round(b), +o.toFixed(2)] + ")";
1473    }
1474    return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1);
1475});
1476var toHex = function (color) {
1477    var i = glob.doc.getElementsByTagName("head")[0] || glob.doc.getElementsByTagName("svg")[0],
1478        red = "rgb(255, 0, 0)";
1479    toHex = cacher(function (color) {
1480        if (color.toLowerCase() == "red") {
1481            return red;
1482        }
1483        i.style.color = red;
1484        i.style.color = color;
1485        var out = glob.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color");
1486        return out == red ? null : out;
1487    });
1488    return toHex(color);
1489},
1490hsbtoString = function () {
1491    return "hsb(" + [this.h, this.s, this.b] + ")";
1492},
1493hsltoString = function () {
1494    return "hsl(" + [this.h, this.s, this.l] + ")";
1495},
1496rgbtoString = function () {
1497    return this.opacity == 1 || this.opacity == null ?
1498            this.hex :
1499            "rgba(" + [this.r, this.g, this.b, this.opacity] + ")";
1500},
1501prepareRGB = function (r, g, b) {
1502    if (g == null && is(r, "object") && "r" in r && "g" in r && "b" in r) {
1503        b = r.b;
1504        g = r.g;
1505        r = r.r;
1506    }
1507    if (g == null && is(r, string)) {
1508        var clr = Snap.getRGB(r);
1509        r = clr.r;
1510        g = clr.g;
1511        b = clr.b;
1512    }
1513    if (r > 1 || g > 1 || b > 1) {
1514        r /= 255;
1515        g /= 255;
1516        b /= 255;
1517    }
1518
1519    return [r, g, b];
1520},
1521packageRGB = function (r, g, b, o) {
1522    r = math.round(r * 255);
1523    g = math.round(g * 255);
1524    b = math.round(b * 255);
1525    var rgb = {
1526        r: r,
1527        g: g,
1528        b: b,
1529        opacity: is(o, "finite") ? o : 1,
1530        hex: Snap.rgb(r, g, b),
1531        toString: rgbtoString
1532    };
1533    is(o, "finite") && (rgb.opacity = o);
1534    return rgb;
1535};
1536/*\
1537 * Snap.color
1538 [ method ]
1539 **
1540 * Parses the color string and returns an object featuring the color's component values
1541 - clr (string) color string in one of the supported formats (see @Snap.getRGB)
1542 = (object) Combined RGB/HSB object in the following format:
1543 o {
1544 o     r (number) red,
1545 o     g (number) green,
1546 o     b (number) blue,
1547 o     hex (string) color in HTML/CSS format: #••••••,
1548 o     error (boolean) `true` if string can't be parsed,
1549 o     h (number) hue,
1550 o     s (number) saturation,
1551 o     v (number) value (brightness),
1552 o     l (number) lightness
1553 o }
1554\*/
1555Snap.color = function (clr) {
1556    var rgb;
1557    if (is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) {
1558        rgb = Snap.hsb2rgb(clr);
1559        clr.r = rgb.r;
1560        clr.g = rgb.g;
1561        clr.b = rgb.b;
1562        clr.opacity = 1;
1563        clr.hex = rgb.hex;
1564    } else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) {
1565        rgb = Snap.hsl2rgb(clr);
1566        clr.r = rgb.r;
1567        clr.g = rgb.g;
1568        clr.b = rgb.b;
1569        clr.opacity = 1;
1570        clr.hex = rgb.hex;
1571    } else {
1572        if (is(clr, "string")) {
1573            clr = Snap.getRGB(clr);
1574        }
1575        if (is(clr, "object") && "r" in clr && "g" in clr && "b" in clr && !("error" in clr)) {
1576            rgb = Snap.rgb2hsl(clr);
1577            clr.h = rgb.h;
1578            clr.s = rgb.s;
1579            clr.l = rgb.l;
1580            rgb = Snap.rgb2hsb(clr);
1581            clr.v = rgb.b;
1582        } else {
1583            clr = {hex: "none"};
1584            clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1;
1585            clr.error = 1;
1586        }
1587    }
1588    clr.toString = rgbtoString;
1589    return clr;
1590};
1591/*\
1592 * Snap.hsb2rgb
1593 [ method ]
1594 **
1595 * Converts HSB values to an RGB object
1596 - h (number) hue
1597 - s (number) saturation
1598 - v (number) value or brightness
1599 = (object) RGB object in the following format:
1600 o {
1601 o     r (number) red,
1602 o     g (number) green,
1603 o     b (number) blue,
1604 o     hex (string) color in HTML/CSS format: #••••••
1605 o }
1606\*/
1607Snap.hsb2rgb = function (h, s, v, o) {
1608    if (is(h, "object") && "h" in h && "s" in h && "b" in h) {
1609        v = h.b;
1610        s = h.s;
1611        o = h.o;
1612        h = h.h;
1613    }
1614    h *= 360;
1615    var R, G, B, X, C;
1616    h = (h % 360) / 60;
1617    C = v * s;
1618    X = C * (1 - abs(h % 2 - 1));
1619    R = G = B = v - C;
1620
1621    h = ~~h;
1622    R += [C, X, 0, 0, X, C][h];
1623    G += [X, C, C, X, 0, 0][h];
1624    B += [0, 0, X, C, C, X][h];
1625    return packageRGB(R, G, B, o);
1626};
1627/*\
1628 * Snap.hsl2rgb
1629 [ method ]
1630 **
1631 * Converts HSL values to an RGB object
1632 - h (number) hue
1633 - s (number) saturation
1634 - l (number) luminosity
1635 = (object) RGB object in the following format:
1636 o {
1637 o     r (number) red,
1638 o     g (number) green,
1639 o     b (number) blue,
1640 o     hex (string) color in HTML/CSS format: #••••••
1641 o }
1642\*/
1643Snap.hsl2rgb = function (h, s, l, o) {
1644    if (is(h, "object") && "h" in h && "s" in h && "l" in h) {
1645        l = h.l;
1646        s = h.s;
1647        h = h.h;
1648    }
1649    if (h > 1 || s > 1 || l > 1) {
1650        h /= 360;
1651        s /= 100;
1652        l /= 100;
1653    }
1654    h *= 360;
1655    var R, G, B, X, C;
1656    h = (h % 360) / 60;
1657    C = 2 * s * (l < .5 ? l : 1 - l);
1658    X = C * (1 - abs(h % 2 - 1));
1659    R = G = B = l - C / 2;
1660
1661    h = ~~h;
1662    R += [C, X, 0, 0, X, C][h];
1663    G += [X, C, C, X, 0, 0][h];
1664    B += [0, 0, X, C, C, X][h];
1665    return packageRGB(R, G, B, o);
1666};
1667/*\
1668 * Snap.rgb2hsb
1669 [ method ]
1670 **
1671 * Converts RGB values to an HSB object
1672 - r (number) red
1673 - g (number) green
1674 - b (number) blue
1675 = (object) HSB object in the following format:
1676 o {
1677 o     h (number) hue,
1678 o     s (number) saturation,
1679 o     b (number) brightness
1680 o }
1681\*/
1682Snap.rgb2hsb = function (r, g, b) {
1683    b = prepareRGB(r, g, b);
1684    r = b[0];
1685    g = b[1];
1686    b = b[2];
1687
1688    var H, S, V, C;
1689    V = mmax(r, g, b);
1690    C = V - mmin(r, g, b);
1691    H = (C == 0 ? null :
1692         V == r ? (g - b) / C :
1693         V == g ? (b - r) / C + 2 :
1694                  (r - g) / C + 4
1695        );
1696    H = ((H + 360) % 6) * 60 / 360;
1697    S = C == 0 ? 0 : C / V;
1698    return {h: H, s: S, b: V, toString: hsbtoString};
1699};
1700/*\
1701 * Snap.rgb2hsl
1702 [ method ]
1703 **
1704 * Converts RGB values to an HSL object
1705 - r (number) red
1706 - g (number) green
1707 - b (number) blue
1708 = (object) HSL object in the following format:
1709 o {
1710 o     h (number) hue,
1711 o     s (number) saturation,
1712 o     l (number) luminosity
1713 o }
1714\*/
1715Snap.rgb2hsl = function (r, g, b) {
1716    b = prepareRGB(r, g, b);
1717    r = b[0];
1718    g = b[1];
1719    b = b[2];
1720
1721    var H, S, L, M, m, C;
1722    M = mmax(r, g, b);
1723    m = mmin(r, g, b);
1724    C = M - m;
1725    H = (C == 0 ? null :
1726         M == r ? (g - b) / C :
1727         M == g ? (b - r) / C + 2 :
1728                  (r - g) / C + 4);
1729    H = ((H + 360) % 6) * 60 / 360;
1730    L = (M + m) / 2;
1731    S = (C == 0 ? 0 :
1732         L < .5 ? C / (2 * L) :
1733                  C / (2 - 2 * L));
1734    return {h: H, s: S, l: L, toString: hsltoString};
1735};
1736
1737// Transformations
1738/*\
1739 * Snap.parsePathString
1740 [ method ]
1741 **
1742 * Utility method
1743 **
1744 * Parses given path string into an array of arrays of path segments
1745 - pathString (string|array) path string or array of segments (in the last case it is returned straight away)
1746 = (array) array of segments
1747\*/
1748Snap.parsePathString = function (pathString) {
1749    if (!pathString) {
1750        return null;
1751    }
1752    var pth = Snap.path(pathString);
1753    if (pth.arr) {
1754        return Snap.path.clone(pth.arr);
1755    }
1756
1757    var paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0},
1758        data = [];
1759    if (is(pathString, "array") && is(pathString[0], "array")) { // rough assumption
1760        data = Snap.path.clone(pathString);
1761    }
1762    if (!data.length) {
1763        Str(pathString).replace(pathCommand, function (a, b, c) {
1764            var params = [],
1765                name = b.toLowerCase();
1766            c.replace(pathValues, function (a, b) {
1767                b && params.push(+b);
1768            });
1769            if (name == "m" && params.length > 2) {
1770                data.push([b].concat(params.splice(0, 2)));
1771                name = "l";
1772                b = b == "m" ? "l" : "L";
1773            }
1774            if (name == "o" && params.length == 1) {
1775                data.push([b, params[0]]);
1776            }
1777            if (name == "r") {
1778                data.push([b].concat(params));
1779            } else while (params.length >= paramCounts[name]) {
1780                data.push([b].concat(params.splice(0, paramCounts[name])));
1781                if (!paramCounts[name]) {
1782                    break;
1783                }
1784            }
1785        });
1786    }
1787    data.toString = Snap.path.toString;
1788    pth.arr = Snap.path.clone(data);
1789    return data;
1790};
1791/*\
1792 * Snap.parseTransformString
1793 [ method ]
1794 **
1795 * Utility method
1796 **
1797 * Parses given transform string into an array of transformations
1798 - TString (string|array) transform string or array of transformations (in the last case it is returned straight away)
1799 = (array) array of transformations
1800\*/
1801var parseTransformString = Snap.parseTransformString = function (TString) {
1802    if (!TString) {
1803        return null;
1804    }
1805    var paramCounts = {r: 3, s: 4, t: 2, m: 6},
1806        data = [];
1807    if (is(TString, "array") && is(TString[0], "array")) { // rough assumption
1808        data = Snap.path.clone(TString);
1809    }
1810    if (!data.length) {
1811        Str(TString).replace(tCommand, function (a, b, c) {
1812            var params = [],
1813                name = b.toLowerCase();
1814            c.replace(pathValues, function (a, b) {
1815                b && params.push(+b);
1816            });
1817            data.push([b].concat(params));
1818        });
1819    }
1820    data.toString = Snap.path.toString;
1821    return data;
1822};
1823function svgTransform2string(tstr) {
1824    var res = [];
1825    tstr = tstr.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g, function (all, name, params) {
1826        params = params.split(/\s*,\s*|\s+/);
1827        if (name == "rotate" && params.length == 1) {
1828            params.push(0, 0);
1829        }
1830        if (name == "scale") {
1831            if (params.length > 2) {
1832                params = params.slice(0, 2);
1833            } else if (params.length == 2) {
1834                params.push(0, 0);
1835            }
1836            if (params.length == 1) {
1837                params.push(params[0], 0, 0);
1838            }
1839        }
1840        if (name == "skewX") {
1841            res.push(["m", 1, 0, math.tan(rad(params[0])), 1, 0, 0]);
1842        } else if (name == "skewY") {
1843            res.push(["m", 1, math.tan(rad(params[0])), 0, 1, 0, 0]);
1844        } else {
1845            res.push([name.charAt(0)].concat(params));
1846        }
1847        return all;
1848    });
1849    return res;
1850}
1851Snap._.svgTransform2string = svgTransform2string;
1852Snap._.rgTransform = /^[a-z][\s]*-?\.?\d/i;
1853function transform2matrix(tstr, bbox) {
1854    var tdata = parseTransformString(tstr),
1855        m = new Snap.Matrix;
1856    if (tdata) {
1857        for (var i = 0, ii = tdata.length; i < ii; i++) {
1858            var t = tdata[i],
1859                tlen = t.length,
1860                command = Str(t[0]).toLowerCase(),
1861                absolute = t[0] != command,
1862                inver = absolute ? m.invert() : 0,
1863                x1,
1864                y1,
1865                x2,
1866                y2,
1867                bb;
1868            if (command == "t" && tlen == 2){
1869                m.translate(t[1], 0);
1870            } else if (command == "t" && tlen == 3) {
1871                if (absolute) {
1872                    x1 = inver.x(0, 0);
1873                    y1 = inver.y(0, 0);
1874                    x2 = inver.x(t[1], t[2]);
1875                    y2 = inver.y(t[1], t[2]);
1876                    m.translate(x2 - x1, y2 - y1);
1877                } else {
1878                    m.translate(t[1], t[2]);
1879                }
1880            } else if (command == "r") {
1881                if (tlen == 2) {
1882                    bb = bb || bbox;
1883                    m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2);
1884                } else if (tlen == 4) {
1885                    if (absolute) {
1886                        x2 = inver.x(t[2], t[3]);
1887                        y2 = inver.y(t[2], t[3]);
1888                        m.rotate(t[1], x2, y2);
1889                    } else {
1890                        m.rotate(t[1], t[2], t[3]);
1891                    }
1892                }
1893            } else if (command == "s") {
1894                if (tlen == 2 || tlen == 3) {
1895                    bb = bb || bbox;
1896                    m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2);
1897                } else if (tlen == 4) {
1898                    if (absolute) {
1899                        x2 = inver.x(t[2], t[3]);
1900                        y2 = inver.y(t[2], t[3]);
1901                        m.scale(t[1], t[1], x2, y2);
1902                    } else {
1903                        m.scale(t[1], t[1], t[2], t[3]);
1904                    }
1905                } else if (tlen == 5) {
1906                    if (absolute) {
1907                        x2 = inver.x(t[3], t[4]);
1908                        y2 = inver.y(t[3], t[4]);
1909                        m.scale(t[1], t[2], x2, y2);
1910                    } else {
1911                        m.scale(t[1], t[2], t[3], t[4]);
1912                    }
1913                }
1914            } else if (command == "m" && tlen == 7) {
1915                m.add(t[1], t[2], t[3], t[4], t[5], t[6]);
1916            }
1917        }
1918    }
1919    return m;
1920}
1921Snap._.transform2matrix = transform2matrix;
1922Snap._unit2px = unit2px;
1923var contains = glob.doc.contains || glob.doc.compareDocumentPosition ?
1924    function (a, b) {
1925        var adown = a.nodeType == 9 ? a.documentElement : a,
1926            bup = b && b.parentNode;
1927            return a == bup || !!(bup && bup.nodeType == 1 && (
1928                adown.contains ?
1929                    adown.contains(bup) :
1930                    a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16
1931            ));
1932    } :
1933    function (a, b) {
1934        if (b) {
1935            while (b) {
1936                b = b.parentNode;
1937                if (b == a) {
1938                    return true;
1939                }
1940            }
1941        }
1942        return false;
1943    };
1944function getSomeDefs(el) {
1945    var p = (el.node.ownerSVGElement && wrap(el.node.ownerSVGElement)) ||
1946            (el.node.parentNode && wrap(el.node.parentNode)) ||
1947            Snap.select("svg") ||
1948            Snap(0, 0),
1949        pdefs = p.select("defs"),
1950        defs  = pdefs == null ? false : pdefs.node;
1951    if (!defs) {
1952        defs = make("defs", p.node).node;
1953    }
1954    return defs;
1955}
1956function getSomeSVG(el) {
1957    return el.node.ownerSVGElement && wrap(el.node.ownerSVGElement) || Snap.select("svg");
1958}
1959Snap._.getSomeDefs = getSomeDefs;
1960Snap._.getSomeSVG = getSomeSVG;
1961function unit2px(el, name, value) {
1962    var svg = getSomeSVG(el).node,
1963        out = {},
1964        mgr = svg.querySelector(".svg---mgr");
1965    if (!mgr) {
1966        mgr = $("rect");
1967        $(mgr, {x: -9e9, y: -9e9, width: 10, height: 10, "class": "svg---mgr", fill: "none"});
1968        svg.appendChild(mgr);
1969    }
1970    function getW(val) {
1971        if (val == null) {
1972            return E;
1973        }
1974        if (val == +val) {
1975            return val;
1976        }
1977        $(mgr, {width: val});
1978        try {
1979            return mgr.getBBox().width;
1980        } catch (e) {
1981            return 0;
1982        }
1983    }
1984    function getH(val) {
1985        if (val == null) {
1986            return E;
1987        }
1988        if (val == +val) {
1989            return val;
1990        }
1991        $(mgr, {height: val});
1992        try {
1993            return mgr.getBBox().height;
1994        } catch (e) {
1995            return 0;
1996        }
1997    }
1998    function set(nam, f) {
1999        if (name == null) {
2000            out[nam] = f(el.attr(nam) || 0);
2001        } else if (nam == name) {
2002            out = f(value == null ? el.attr(nam) || 0 : value);
2003        }
2004    }
2005    switch (el.type) {
2006        case "rect":
2007            set("rx", getW);
2008            set("ry", getH);
2009        case "image":
2010            set("width", getW);
2011            set("height", getH);
2012        case "text":
2013            set("x", getW);
2014            set("y", getH);
2015        break;
2016        case "circle":
2017            set("cx", getW);
2018            set("cy", getH);
2019            set("r", getW);
2020        break;
2021        case "ellipse":
2022            set("cx", getW);
2023            set("cy", getH);
2024            set("rx", getW);
2025            set("ry", getH);
2026        break;
2027        case "line":
2028            set("x1", getW);
2029            set("x2", getW);
2030            set("y1", getH);
2031            set("y2", getH);
2032        break;
2033        case "marker":
2034            set("refX", getW);
2035            set("markerWidth", getW);
2036            set("refY", getH);
2037            set("markerHeight", getH);
2038        break;
2039        case "radialGradient":
2040            set("fx", getW);
2041            set("fy", getH);
2042        break;
2043        case "tspan":
2044            set("dx", getW);
2045            set("dy", getH);
2046        break;
2047        default:
2048            set(name, getW);
2049    }
2050    svg.removeChild(mgr);
2051    return out;
2052}
2053/*\
2054 * Snap.select
2055 [ method ]
2056 **
2057 * Wraps a DOM element specified by CSS selector as @Element
2058 - query (string) CSS selector of the element
2059 = (Element) the current element
2060\*/
2061Snap.select = function (query) {
2062    query = Str(query).replace(/([^\\]):/g, "$1\\:");
2063    return wrap(glob.doc.querySelector(query));
2064};
2065/*\
2066 * Snap.selectAll
2067 [ method ]
2068 **
2069 * Wraps DOM elements specified by CSS selector as set or array of @Element
2070 - query (string) CSS selector of the element
2071 = (Element) the current element
2072\*/
2073Snap.selectAll = function (query) {
2074    var nodelist = glob.doc.querySelectorAll(query),
2075        set = (Snap.set || Array)();
2076    for (var i = 0; i < nodelist.length; i++) {
2077        set.push(wrap(nodelist[i]));
2078    }
2079    return set;
2080};
2081
2082function add2group(list) {
2083    if (!is(list, "array")) {
2084        list = Array.prototype.slice.call(arguments, 0);
2085    }
2086    var i = 0,
2087        j = 0,
2088        node = this.node;
2089    while (this[i]) delete this[i++];
2090    for (i = 0; i < list.length; i++) {
2091        if (list[i].type == "set") {
2092            list[i].forEach(function (el) {
2093                node.appendChild(el.node);
2094            });
2095        } else {
2096            node.appendChild(list[i].node);
2097        }
2098    }
2099    var children = node.childNodes;
2100    for (i = 0; i < children.length; i++) {
2101        this[j++] = wrap(children[i]);
2102    }
2103    return this;
2104}
2105// Hub garbage collector every 10s
2106setInterval(function () {
2107    for (var key in hub) if (hub[has](key)) {
2108        var el = hub[key],
2109            node = el.node;
2110        if (el.type != "svg" && !node.ownerSVGElement || el.type == "svg" && (!node.parentNode || "ownerSVGElement" in node.parentNode && !node.ownerSVGElement)) {
2111            delete hub[key];
2112        }
2113    }
2114}, 1e4);
2115function Element(el) {
2116    if (el.snap in hub) {
2117        return hub[el.snap];
2118    }
2119    var svg;
2120    try {
2121        svg = el.ownerSVGElement;
2122    } catch(e) {}
2123    /*\
2124     * Element.node
2125     [ property (object) ]
2126     **
2127     * Gives you a reference to the DOM object, so you can assign event handlers or just mess around.
2128     > Usage
2129     | // draw a circle at coordinate 10,10 with radius of 10
2130     | var c = paper.circle(10, 10, 10);
2131     | c.node.onclick = function () {
2132     |     c.attr("fill", "red");
2133     | };
2134    \*/
2135    this.node = el;
2136    if (svg) {
2137        this.paper = new Paper(svg);
2138    }
2139    /*\
2140     * Element.type
2141     [ property (string) ]
2142     **
2143     * SVG tag name of the given element.
2144    \*/
2145    this.type = el.tagName || el.nodeName;
2146    var id = this.id = ID(this);
2147    this.anims = {};
2148    this._ = {
2149        transform: []
2150    };
2151    el.snap = id;
2152    hub[id] = this;
2153    if (this.type == "g") {
2154        this.add = add2group;
2155    }
2156    if (this.type in {g: 1, mask: 1, pattern: 1, symbol: 1}) {
2157        for (var method in Paper.prototype) if (Paper.prototype[has](method)) {
2158            this[method] = Paper.prototype[method];
2159        }
2160    }
2161}
2162   /*\
2163     * Element.attr
2164     [ method ]
2165     **
2166     * Gets or sets given attributes of the element.
2167     **
2168     - params (object) contains key-value pairs of attributes you want to set
2169     * or
2170     - param (string) name of the attribute
2171     = (Element) the current element
2172     * or
2173     = (string) value of attribute
2174     > Usage
2175     | el.attr({
2176     |     fill: "#fc0",
2177     |     stroke: "#000",
2178     |     strokeWidth: 2, // CamelCase...
2179     |     "fill-opacity": 0.5, // or dash-separated names
2180     |     width: "*=2" // prefixed values
2181     | });
2182     | console.log(el.attr("fill")); // #fc0
2183     * Prefixed values in format `"+=10"` supported. All four operations
2184     * (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+`
2185     * and `-`: `"+=2em"`.
2186    \*/
2187    Element.prototype.attr = function (params, value) {
2188        var el = this,
2189            node = el.node;
2190        if (!params) {
2191            if (node.nodeType != 1) {
2192                return {
2193                    text: node.nodeValue
2194                };
2195            }
2196            var attr = node.attributes,
2197                out = {};
2198            for (var i = 0, ii = attr.length; i < ii; i++) {
2199                out[attr[i].nodeName] = attr[i].nodeValue;
2200            }
2201            return out;
2202        }
2203        if (is(params, "string")) {
2204            if (arguments.length > 1) {
2205                var json = {};
2206                json[params] = value;
2207                params = json;
2208            } else {
2209                return eve("snap.util.getattr." + params, el).firstDefined();
2210            }
2211        }
2212        for (var att in params) {
2213            if (params[has](att)) {
2214                eve("snap.util.attr." + att, el, params[att]);
2215            }
2216        }
2217        return el;
2218    };
2219/*\
2220 * Snap.parse
2221 [ method ]
2222 **
2223 * Parses SVG fragment and converts it into a @Fragment
2224 **
2225 - svg (string) SVG string
2226 = (Fragment) the @Fragment
2227\*/
2228Snap.parse = function (svg) {
2229    var f = glob.doc.createDocumentFragment(),
2230        full = true,
2231        div = glob.doc.createElement("div");
2232    svg = Str(svg);
2233    if (!svg.match(/^\s*<\s*svg(?:\s|>)/)) {
2234        svg = "<svg>" + svg + "</svg>";
2235        full = false;
2236    }
2237    div.innerHTML = svg;
2238    svg = div.getElementsByTagName("svg")[0];
2239    if (svg) {
2240        if (full) {
2241            f = svg;
2242        } else {
2243            while (svg.firstChild) {
2244                f.appendChild(svg.firstChild);
2245            }
2246        }
2247    }
2248    return new Fragment(f);
2249};
2250function Fragment(frag) {
2251    this.node = frag;
2252}
2253/*\
2254 * Snap.fragment
2255 [ method ]
2256 **
2257 * Creates a DOM fragment from a given list of elements or strings
2258 **
2259 - varargs (…) SVG string
2260 = (Fragment) the @Fragment
2261\*/
2262Snap.fragment = function () {
2263    var args = Array.prototype.slice.call(arguments, 0),
2264        f = glob.doc.createDocumentFragment();
2265    for (var i = 0, ii = args.length; i < ii; i++) {
2266        var item = args[i];
2267        if (item.node && item.node.nodeType) {
2268            f.appendChild(item.node);
2269        }
2270        if (item.nodeType) {
2271            f.appendChild(item);
2272        }
2273        if (typeof item == "string") {
2274            f.appendChild(Snap.parse(item).node);
2275        }
2276    }
2277    return new Fragment(f);
2278};
2279
2280function make(name, parent) {
2281    var res = $(name);
2282    parent.appendChild(res);
2283    var el = wrap(res);
2284    return el;
2285}
2286function Paper(w, h) {
2287    var res,
2288        desc,
2289        defs,
2290        proto = Paper.prototype;
2291    if (w && w.tagName == "svg") {
2292        if (w.snap in hub) {
2293            return hub[w.snap];
2294        }
2295        var doc = w.ownerDocument;
2296        res = new Element(w);
2297        desc = w.getElementsByTagName("desc")[0];
2298        defs = w.getElementsByTagName("defs")[0];
2299        if (!desc) {
2300            desc = $("desc");
2301            desc.appendChild(doc.createTextNode("Created with Snap"));
2302            res.node.appendChild(desc);
2303        }
2304        if (!defs) {
2305            defs = $("defs");
2306            res.node.appendChild(defs);
2307        }
2308        res.defs = defs;
2309        for (var key in proto) if (proto[has](key)) {
2310            res[key] = proto[key];
2311        }
2312        res.paper = res.root = res;
2313    } else {
2314        res = make("svg", glob.doc.body);
2315        $(res.node, {
2316            height: h,
2317            version: 1.1,
2318            width: w,
2319            xmlns: xmlns
2320        });
2321    }
2322    return res;
2323}
2324function wrap(dom) {
2325    if (!dom) {
2326        return dom;
2327    }
2328    if (dom instanceof Element || dom instanceof Fragment) {
2329        return dom;
2330    }
2331    if (dom.tagName && dom.tagName.toLowerCase() == "svg") {
2332        return new Paper(dom);
2333    }
2334    if (dom.tagName && dom.tagName.toLowerCase() == "object" && dom.type == "image/svg+xml") {
2335        return new Paper(dom.contentDocument.getElementsByTagName("svg")[0]);
2336    }
2337    return new Element(dom);
2338}
2339
2340Snap._.make = make;
2341Snap._.wrap = wrap;
2342/*\
2343 * Paper.el
2344 [ method ]
2345 **
2346 * Creates an element on paper with a given name and no attributes
2347 **
2348 - name (string) tag name
2349 - attr (object) attributes
2350 = (Element) the current element
2351 > Usage
2352 | var c = paper.circle(10, 10, 10); // is the same as...
2353 | var c = paper.el("circle").attr({
2354 |     cx: 10,
2355 |     cy: 10,
2356 |     r: 10
2357 | });
2358 | // and the same as
2359 | var c = paper.el("circle", {
2360 |     cx: 10,
2361 |     cy: 10,
2362 |     r: 10
2363 | });
2364\*/
2365Paper.prototype.el = function (name, attr) {
2366    var el = make(name, this.node);
2367    attr && el.attr(attr);
2368    return el;
2369};
2370/*\
2371 * Element.children
2372 [ method ]
2373 **
2374 * Returns array of all the children of the element.
2375 = (array) array of Elements
2376\*/
2377Element.prototype.children = function () {
2378    var out = [],
2379        ch = this.node.childNodes;
2380    for (var i = 0, ii = ch.length; i < ii; i++) {
2381        out[i] = Snap(ch[i]);
2382    }
2383    return out;
2384};
2385function jsonFiller(root, o) {
2386    for (var i = 0, ii = root.length; i < ii; i++) {
2387        var item = {
2388                type: root[i].type,
2389                attr: root[i].attr()
2390            },
2391            children = root[i].children();
2392        o.push(item);
2393        if (children.length) {
2394            jsonFiller(children, item.childNodes = []);
2395        }
2396    }
2397}
2398/*\
2399 * Element.toJSON
2400 [ method ]
2401 **
2402 * Returns object representation of the given element and all its children.
2403 = (object) in format
2404 o {
2405 o     type (string) this.type,
2406 o     attr (object) attributes map,
2407 o     childNodes (array) optional array of children in the same format
2408 o }
2409\*/
2410Element.prototype.toJSON = function () {
2411    var out = [];
2412    jsonFiller([this], out);
2413    return out[0];
2414};
2415// default
2416eve.on("snap.util.getattr", function () {
2417    var att = eve.nt();
2418    att = att.substring(att.lastIndexOf(".") + 1);
2419    var css = att.replace(/[A-Z]/g, function (letter) {
2420        return "-" + letter.toLowerCase();
2421    });
2422    if (cssAttr[has](css)) {
2423        return this.node.ownerDocument.defaultView.getComputedStyle(this.node, null).getPropertyValue(css);
2424    } else {
2425        return $(this.node, att);
2426    }
2427});
2428var cssAttr = {
2429    "alignment-baseline": 0,
2430    "baseline-shift": 0,
2431    "clip": 0,
2432    "clip-path": 0,
2433    "clip-rule": 0,
2434    "color": 0,
2435    "color-interpolation": 0,
2436    "color-interpolation-filters": 0,
2437    "color-profile": 0,
2438    "color-rendering": 0,
2439    "cursor": 0,
2440    "direction": 0,
2441    "display": 0,
2442    "dominant-baseline": 0,
2443    "enable-background": 0,
2444    "fill": 0,
2445    "fill-opacity": 0,
2446    "fill-rule": 0,
2447    "filter": 0,
2448    "flood-color": 0,
2449    "flood-opacity": 0,
2450    "font": 0,
2451    "font-family": 0,
2452    "font-size": 0,
2453    "font-size-adjust": 0,
2454    "font-stretch": 0,
2455    "font-style": 0,
2456    "font-variant": 0,
2457    "font-weight": 0,
2458    "glyph-orientation-horizontal": 0,
2459    "glyph-orientation-vertical": 0,
2460    "image-rendering": 0,
2461    "kerning": 0,
2462    "letter-spacing": 0,
2463    "lighting-color": 0,
2464    "marker": 0,
2465    "marker-end": 0,
2466    "marker-mid": 0,
2467    "marker-start": 0,
2468    "mask": 0,
2469    "opacity": 0,
2470    "overflow": 0,
2471    "pointer-events": 0,
2472    "shape-rendering": 0,
2473    "stop-color": 0,
2474    "stop-opacity": 0,
2475    "stroke": 0,
2476    "stroke-dasharray": 0,
2477    "stroke-dashoffset": 0,
2478    "stroke-linecap": 0,
2479    "stroke-linejoin": 0,
2480    "stroke-miterlimit": 0,
2481    "stroke-opacity": 0,
2482    "stroke-width": 0,
2483    "text-anchor": 0,
2484    "text-decoration": 0,
2485    "text-rendering": 0,
2486    "unicode-bidi": 0,
2487    "visibility": 0,
2488    "word-spacing": 0,
2489    "writing-mode": 0
2490};
2491
2492eve.on("snap.util.attr", function (value) {
2493    var att = eve.nt(),
2494        attr = {};
2495    att = att.substring(att.lastIndexOf(".") + 1);
2496    attr[att] = value;
2497    var style = att.replace(/-(\w)/gi, function (all, letter) {
2498            return letter.toUpperCase();
2499        }),
2500        css = att.replace(/[A-Z]/g, function (letter) {
2501            return "-" + letter.toLowerCase();
2502        });
2503    if (cssAttr[has](css)) {
2504        this.node.style[style] = value == null ? E : value;
2505    } else {
2506        $(this.node, attr);
2507    }
2508});
2509(function (proto) {}(Paper.prototype));
2510
2511// simple ajax
2512/*\
2513 * Snap.ajax
2514 [ method ]
2515 **
2516 * Simple implementation of Ajax
2517 **
2518 - url (string) URL
2519 - postData (object|string) data for post request
2520 - callback (function) callback
2521 - scope (object) #optional scope of callback
2522 * or
2523 - url (string) URL
2524 - callback (function) callback
2525 - scope (object) #optional scope of callback
2526 = (XMLHttpRequest) the XMLHttpRequest object, just in case
2527\*/
2528Snap.ajax = function (url, postData, callback, scope){
2529    var req = new XMLHttpRequest,
2530        id = ID();
2531    if (req) {
2532        if (is(postData, "function")) {
2533            scope = callback;
2534            callback = postData;
2535            postData = null;
2536        } else if (is(postData, "object")) {
2537            var pd = [];
2538            for (var key in postData) if (postData.hasOwnProperty(key)) {
2539                pd.push(encodeURIComponent(key) + "=" + encodeURIComponent(postData[key]));
2540            }
2541            postData = pd.join("&");
2542        }
2543        req.open((postData ? "POST" : "GET"), url, true);
2544        if (postData) {
2545            req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
2546            req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
2547        }
2548        if (callback) {
2549            eve.once("snap.ajax." + id + ".0", callback);
2550            eve.once("snap.ajax." + id + ".200", callback);
2551            eve.once("snap.ajax." + id + ".304", callback);
2552        }
2553        req.onreadystatechange = function() {
2554            if (req.readyState != 4) return;
2555            eve("snap.ajax." + id + "." + req.status, scope, req);
2556        };
2557        if (req.readyState == 4) {
2558            return req;
2559        }
2560        req.send(postData);
2561        return req;
2562    }
2563};
2564/*\
2565 * Snap.load
2566 [ method ]
2567 **
2568 * Loads external SVG file as a @Fragment (see @Snap.ajax for more advanced AJAX)
2569 **
2570 - url (string) URL
2571 - callback (function) callback
2572 - scope (object) #optional scope of callback
2573\*/
2574Snap.load = function (url, callback, scope) {
2575    Snap.ajax(url, function (req) {
2576        var f = Snap.parse(req.responseText);
2577        scope ? callback.call(scope, f) : callback(f);
2578    });
2579};
2580var getOffset = function (elem) {
2581    var box = elem.getBoundingClientRect(),
2582        doc = elem.ownerDocument,
2583        body = doc.body,
2584        docElem = doc.documentElement,
2585        clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
2586        top  = box.top  + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop,
2587        left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
2588    return {
2589        y: top,
2590        x: left
2591    };
2592};
2593/*\
2594 * Snap.getElementByPoint
2595 [ method ]
2596 **
2597 * Returns you topmost element under given point.
2598 **
2599 = (object) Snap element object
2600 - x (number) x coordinate from the top left corner of the window
2601 - y (number) y coordinate from the top left corner of the window
2602 > Usage
2603 | Snap.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
2604\*/
2605Snap.getElementByPoint = function (x, y) {
2606    var paper = this,
2607        svg = paper.canvas,
2608        target = glob.doc.elementFromPoint(x, y);
2609    if (glob.win.opera && target.tagName == "svg") {
2610        var so = getOffset(target),
2611            sr = target.createSVGRect();
2612        sr.x = x - so.x;
2613        sr.y = y - so.y;
2614        sr.width = sr.height = 1;
2615        var hits = target.getIntersectionList(sr, null);
2616        if (hits.length) {
2617            target = hits[hits.length - 1];
2618        }
2619    }
2620    if (!target) {
2621        return null;
2622    }
2623    return wrap(target);
2624};
2625/*\
2626 * Snap.plugin
2627 [ method ]
2628 **
2629 * Let you write plugins. You pass in a function with five arguments, like this:
2630 | Snap.plugin(function (Snap, Element, Paper, global, Fragment) {
2631 |     Snap.newmethod = function () {};
2632 |     Element.prototype.newmethod = function () {};
2633 |     Paper.prototype.newmethod = function () {};
2634 | });
2635 * Inside the function you have access to all main objects (and their
2636 * prototypes). This allow you to extend anything you want.
2637 **
2638 - f (function) your plugin body
2639\*/
2640Snap.plugin = function (f) {
2641    f(Snap, Element, Paper, glob, Fragment);
2642};
2643glob.win.Snap = Snap;
2644return Snap;
2645}(window || this));
2646
2647// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
2648//
2649// Licensed under the Apache License, Version 2.0 (the "License");
2650// you may not use this file except in compliance with the License.
2651// You may obtain a copy of the License at
2652//
2653// http://www.apache.org/licenses/LICENSE-2.0
2654//
2655// Unless required by applicable law or agreed to in writing, software
2656// distributed under the License is distributed on an "AS IS" BASIS,
2657// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2658// See the License for the specific language governing permissions and
2659// limitations under the License.
2660Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
2661    var elproto = Element.prototype,
2662        is = Snap.is,
2663        Str = String,
2664        unit2px = Snap._unit2px,
2665        $ = Snap._.$,
2666        make = Snap._.make,
2667        getSomeDefs = Snap._.getSomeDefs,
2668        has = "hasOwnProperty",
2669        wrap = Snap._.wrap;
2670    /*\
2671     * Element.getBBox
2672     [ method ]
2673     **
2674     * Returns the bounding box descriptor for the given element
2675     **
2676     = (object) bounding box descriptor:
2677     o {
2678     o     cx: (number) x of the center,
2679     o     cy: (number) x of the center,
2680     o     h: (number) height,
2681     o     height: (number) height,
2682     o     path: (string) path command for the box,
2683     o     r0: (number) radius of a circle that fully encloses the box,
2684     o     r1: (number) radius of the smallest circle that can be enclosed,
2685     o     r2: (number) radius of the largest circle that can be enclosed,
2686     o     vb: (string) box as a viewbox command,
2687     o     w: (number) width,
2688     o     width: (number) width,
2689     o     x2: (number) x of the right side,
2690     o     x: (number) x of the left side,
2691     o     y2: (number) y of the bottom edge,
2692     o     y: (number) y of the top edge
2693     o }
2694    \*/
2695    elproto.getBBox = function (isWithoutTransform) {
2696        if (!Snap.Matrix || !Snap.path) {
2697            return this.node.getBBox();
2698        }
2699        var el = this,
2700            m = new Snap.Matrix;
2701        if (el.removed) {
2702            return Snap._.box();
2703        }
2704        while (el.type == "use") {
2705            if (!isWithoutTransform) {
2706                m = m.add(el.transform().localMatrix.translate(el.attr("x") || 0, el.attr("y") || 0));
2707            }
2708            if (el.original) {
2709                el = el.original;
2710            } else {
2711                var href = el.attr("xlink:href");
2712                el = el.original = el.node.ownerDocument.getElementById(href.substring(href.indexOf("#") + 1));
2713            }
2714        }
2715        var _ = el._,
2716            pathfinder = Snap.path.get[el.type] || Snap.path.get.deflt;
2717        try {
2718            if (isWithoutTransform) {
2719                _.bboxwt = pathfinder ? Snap.path.getBBox(el.realPath = pathfinder(el)) : Snap._.box(el.node.getBBox());
2720                return Snap._.box(_.bboxwt);
2721            } else {
2722                el.realPath = pathfinder(el);
2723                el.matrix = el.transform().localMatrix;
2724                _.bbox = Snap.path.getBBox(Snap.path.map(el.realPath, m.add(el.matrix)));
2725                return Snap._.box(_.bbox);
2726            }
2727        } catch (e) {
2728            // Firefox doesn’t give you bbox of hidden element
2729            return Snap._.box();
2730        }
2731    };
2732    var propString = function () {
2733        return this.string;
2734    };
2735    function extractTransform(el, tstr) {
2736        if (tstr == null) {
2737            var doReturn = true;
2738            if (el.type == "linearGradient" || el.type == "radialGradient") {
2739                tstr = el.node.getAttribute("gradientTransform");
2740            } else if (el.type == "pattern") {
2741                tstr = el.node.getAttribute("patternTransform");
2742            } else {
2743                tstr = el.node.getAttribute("transform");
2744            }
2745            if (!tstr) {
2746                return new Snap.Matrix;
2747            }
2748            tstr = Snap._.svgTransform2string(tstr);
2749        } else {
2750            if (!Snap._.rgTransform.test(tstr)) {
2751                tstr = Snap._.svgTransform2string(tstr);
2752            } else {
2753                tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || "");
2754            }
2755            if (is(tstr, "array")) {
2756                tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr);
2757            }
2758            el._.transform = tstr;
2759        }
2760        var m = Snap._.transform2matrix(tstr, el.getBBox(1));
2761        if (doReturn) {
2762            return m;
2763        } else {
2764            el.matrix = m;
2765        }
2766    }
2767    /*\
2768     * Element.transform
2769     [ method ]
2770     **
2771     * Gets or sets transformation of the element
2772     **
2773     - tstr (string) transform string in Snap or SVG format
2774     = (Element) the current element
2775     * or
2776     = (object) transformation descriptor:
2777     o {
2778     o     string (string) transform string,
2779     o     globalMatrix (Matrix) matrix of all transformations applied to element or its parents,
2780     o     localMatrix (Matrix) matrix of transformations applied only to the element,
2781     o     diffMatrix (Matrix) matrix of difference between global and local transformations,
2782     o     global (string) global transformation as string,
2783     o     local (string) local transformation as string,
2784     o     toString (function) returns `string` property
2785     o }
2786    \*/
2787    elproto.transform = function (tstr) {
2788        var _ = this._;
2789        if (tstr == null) {
2790            var papa = this,
2791                global = new Snap.Matrix(this.node.getCTM()),
2792                local = extractTransform(this),
2793                ms = [local],
2794                m = new Snap.Matrix,
2795                i,
2796                localString = local.toTransformString(),
2797                string = Str(local) == Str(this.matrix) ?
2798                            Str(_.transform) : localString;
2799            while (papa.type != "svg" && (papa = papa.parent())) {
2800                ms.push(extractTransform(papa));
2801            }
2802            i = ms.length;
2803            while (i--) {
2804                m.add(ms[i]);
2805            }
2806            return {
2807                string: string,
2808                globalMatrix: global,
2809                totalMatrix: m,
2810                localMatrix: local,
2811                diffMatrix: global.clone().add(local.invert()),
2812                global: global.toTransformString(),
2813                total: m.toTransformString(),
2814                local: localString,
2815                toString: propString
2816            };
2817        }
2818        if (tstr instanceof Snap.Matrix) {
2819            this.matrix = tstr;
2820            this._.transform = tstr.toTransformString();
2821        } else {
2822            extractTransform(this, tstr);
2823        }
2824
2825        if (this.node) {
2826            if (this.type == "linearGradient" || this.type == "radialGradient") {
2827                $(this.node, {gradientTransform: this.matrix});
2828            } else if (this.type == "pattern") {
2829                $(this.node, {patternTransform: this.matrix});
2830            } else {
2831                $(this.node, {transform: this.matrix});
2832            }
2833        }
2834
2835        return this;
2836    };
2837    /*\
2838     * Element.parent
2839     [ method ]
2840     **
2841     * Returns the element's parent
2842     **
2843     = (Element) the parent element
2844    \*/
2845    elproto.parent = function () {
2846        return wrap(this.node.parentNode);
2847    };
2848    /*\
2849     * Element.append
2850     [ method ]
2851     **
2852     * Appends the given element to current one
2853     **
2854     - el (Element|Set) element to append
2855     = (Element) the parent element
2856    \*/
2857    /*\
2858     * Element.add
2859     [ method ]
2860     **
2861     * See @Element.append
2862    \*/
2863    elproto.append = elproto.add = function (el) {
2864        if (el) {
2865            if (el.type == "set") {
2866                var it = this;
2867                el.forEach(function (el) {
2868                    it.add(el);
2869                });
2870                return this;
2871            }
2872            el = wrap(el);
2873            this.node.appendChild(el.node);
2874            el.paper = this.paper;
2875        }
2876        return this;
2877    };
2878    /*\
2879     * Element.appendTo
2880     [ method ]
2881     **
2882     * Appends the current element to the given one
2883     **
2884     - el (Element) parent element to append to
2885     = (Element) the child element
2886    \*/
2887    elproto.appendTo = function (el) {
2888        if (el) {
2889            el = wrap(el);
2890            el.append(this);
2891        }
2892        return this;
2893    };
2894    /*\
2895     * Element.prepend
2896     [ method ]
2897     **
2898     * Prepends the given element to the current one
2899     **
2900     - el (Element) element to prepend
2901     = (Element) the parent element
2902    \*/
2903    elproto.prepend = function (el) {
2904        if (el) {
2905            if (el.type == "set") {
2906                var it = this,
2907                    first;
2908                el.forEach(function (el) {
2909                    if (first) {
2910                        first.after(el);
2911                    } else {
2912                        it.prepend(el);
2913                    }
2914                    first = el;
2915                });
2916                return this;
2917            }
2918            el = wrap(el);
2919            var parent = el.parent();
2920            this.node.insertBefore(el.node, this.node.firstChild);
2921            this.add && this.add();
2922            el.paper = this.paper;
2923            this.parent() && this.parent().add();
2924            parent && parent.add();
2925        }
2926        return this;
2927    };
2928    /*\
2929     * Element.prependTo
2930     [ method ]
2931     **
2932     * Prepends the current element to the given one
2933     **
2934     - el (Element) parent element to prepend to
2935     = (Element) the child element
2936    \*/
2937    elproto.prependTo = function (el) {
2938        el = wrap(el);
2939        el.prepend(this);
2940        return this;
2941    };
2942    /*\
2943     * Element.before
2944     [ method ]
2945     **
2946     * Inserts given element before the current one
2947     **
2948     - el (Element) element to insert
2949     = (Element) the parent element
2950    \*/
2951    elproto.before = function (el) {
2952        if (el.type == "set") {
2953            var it = this;
2954            el.forEach(function (el) {
2955                var parent = el.parent();
2956                it.node.parentNode.insertBefore(el.node, it.node);
2957                parent && parent.add();
2958            });
2959            this.parent().add();
2960            return this;
2961        }
2962        el = wrap(el);
2963        var parent = el.parent();
2964        this.node.parentNode.insertBefore(el.node, this.node);
2965        this.parent() && this.parent().add();
2966        parent && parent.add();
2967        el.paper = this.paper;
2968        return this;
2969    };
2970    /*\
2971     * Element.after
2972     [ method ]
2973     **
2974     * Inserts given element after the current one
2975     **
2976     - el (Element) element to insert
2977     = (Element) the parent element
2978    \*/
2979    elproto.after = function (el) {
2980        el = wrap(el);
2981        var parent = el.parent();
2982        if (this.node.nextSibling) {
2983            this.node.parentNode.insertBefore(el.node, this.node.nextSibling);
2984        } else {
2985            this.node.parentNode.appendChild(el.node);
2986        }
2987        this.parent() && this.parent().add();
2988        parent && parent.add();
2989        el.paper = this.paper;
2990        return this;
2991    };
2992    /*\
2993     * Element.insertBefore
2994     [ method ]
2995     **
2996     * Inserts the element after the given one
2997     **
2998     - el (Element) element next to whom insert to
2999     = (Element) the parent element
3000    \*/
3001    elproto.insertBefore = function (el) {
3002        el = wrap(el);
3003        var parent = this.parent();
3004        el.node.parentNode.insertBefore(this.node, el.node);
3005        this.paper = el.paper;
3006        parent && parent.add();
3007        el.parent() && el.parent().add();
3008        return this;
3009    };
3010    /*\
3011     * Element.insertAfter
3012     [ method ]
3013     **
3014     * Inserts the element after the given one
3015     **
3016     - el (Element) element next to whom insert to
3017     = (Element) the parent element
3018    \*/
3019    elproto.insertAfter = function (el) {
3020        el = wrap(el);
3021        var parent = this.parent();
3022        el.node.parentNode.insertBefore(this.node, el.node.nextSibling);
3023        this.paper = el.paper;
3024        parent && parent.add();
3025        el.parent() && el.parent().add();
3026        return this;
3027    };
3028    /*\
3029     * Element.remove
3030     [ method ]
3031     **
3032     * Removes element from the DOM
3033     = (Element) the detached element
3034    \*/
3035    elproto.remove = function () {
3036        var parent = this.parent();
3037        this.node.parentNode && this.node.parentNode.removeChild(this.node);
3038        delete this.paper;
3039        this.removed = true;
3040        parent && parent.add();
3041        return this;
3042    };
3043    /*\
3044     * Element.select
3045     [ method ]
3046     **
3047     * Gathers the nested @Element matching the given set of CSS selectors
3048     **
3049     - query (string) CSS selector
3050     = (Element) result of query selection
3051    \*/
3052    elproto.select = function (query) {
3053        return wrap(this.node.querySelector(query));
3054    };
3055    /*\
3056     * Element.selectAll
3057     [ method ]
3058     **
3059     * Gathers nested @Element objects matching the given set of CSS selectors
3060     **
3061     - query (string) CSS selector
3062     = (Set|array) result of query selection
3063    \*/
3064    elproto.selectAll = function (query) {
3065        var nodelist = this.node.querySelectorAll(query),
3066            set = (Snap.set || Array)();
3067        for (var i = 0; i < nodelist.length; i++) {
3068            set.push(wrap(nodelist[i]));
3069        }
3070        return set;
3071    };
3072    /*\
3073     * Element.asPX
3074     [ method ]
3075     **
3076     * Returns given attribute of the element as a `px` value (not %, em, etc.)
3077     **
3078     - attr (string) attribute name
3079     - value (string) #optional attribute value
3080     = (Element) result of query selection
3081    \*/
3082    elproto.asPX = function (attr, value) {
3083        if (value == null) {
3084            value = this.attr(attr);
3085        }
3086        return +unit2px(this, attr, value);
3087    };
3088    // SIERRA Element.use(): I suggest adding a note about how to access the original element the returned <use> instantiates. It's a part of SVG with which ordinary web developers may be least familiar.
3089    /*\
3090     * Element.use
3091     [ method ]
3092     **
3093     * Creates a `<use>` element linked to the current element
3094     **
3095     = (Element) the `<use>` element
3096    \*/
3097    elproto.use = function () {
3098        var use,
3099            id = this.node.id;
3100        if (!id) {
3101            id = this.id;
3102            $(this.node, {
3103                id: id
3104            });
3105        }
3106        if (this.type == "linearGradient" || this.type == "radialGradient" ||
3107            this.type == "pattern") {
3108            use = make(this.type, this.node.parentNode);
3109        } else {
3110            use = make("use", this.node.parentNode);
3111        }
3112        $(use.node, {
3113            "xlink:href": "#" + id
3114        });
3115        use.original = this;
3116        return use;
3117    };
3118    function fixids(el) {
3119        var els = el.selectAll("*"),
3120            it,
3121            url = /^\s*url\(("|'|)(.*)\1\)\s*$/,
3122            ids = [],
3123            uses = {};
3124        function urltest(it, name) {
3125            var val = $(it.node, name);
3126            val = val && val.match(url);
3127            val = val && val[2];
3128            if (val && val.charAt() == "#") {
3129                val = val.substring(1);
3130            } else {
3131                return;
3132            }
3133            if (val) {
3134                uses[val] = (uses[val] || []).concat(function (id) {
3135                    var attr = {};
3136                    attr[name] = URL(id);
3137                    $(it.node, attr);
3138                });
3139            }
3140        }
3141        function linktest(it) {
3142            var val = $(it.node, "xlink:href");
3143            if (val && val.charAt() == "#") {
3144                val = val.substring(1);
3145            } else {
3146                return;
3147            }
3148            if (val) {
3149                uses[val] = (uses[val] || []).concat(function (id) {
3150                    it.attr("xlink:href", "#" + id);
3151                });
3152            }
3153        }
3154        for (var i = 0, ii = els.length; i < ii; i++) {
3155            it = els[i];
3156            urltest(it, "fill");
3157            urltest(it, "stroke");
3158            urltest(it, "filter");
3159            urltest(it, "mask");
3160            urltest(it, "clip-path");
3161            linktest(it);
3162            var oldid = $(it.node, "id");
3163            if (oldid) {
3164                $(it.node, {id: it.id});
3165                ids.push({
3166                    old: oldid,
3167                    id: it.id
3168                });
3169            }
3170        }
3171        for (i = 0, ii = ids.length; i < ii; i++) {
3172            var fs = uses[ids[i].old];
3173            if (fs) {
3174                for (var j = 0, jj = fs.length; j < jj; j++) {
3175                    fs[j](ids[i].id);
3176                }
3177            }
3178        }
3179    }
3180    /*\
3181     * Element.clone
3182     [ method ]
3183     **
3184     * Creates a clone of the element and inserts it after the element
3185     **
3186     = (Element) the clone
3187    \*/
3188    elproto.clone = function () {
3189        var clone = wrap(this.node.cloneNode(true));
3190        if ($(clone.node, "id")) {
3191            $(clone.node, {id: clone.id});
3192        }
3193        fixids(clone);
3194        clone.insertAfter(this);
3195        return clone;
3196    };
3197    /*\
3198     * Element.toDefs
3199     [ method ]
3200     **
3201     * Moves element to the shared `<defs>` area
3202     **
3203     = (Element) the element
3204    \*/
3205    elproto.toDefs = function () {
3206        var defs = getSomeDefs(this);
3207        defs.appendChild(this.node);
3208        return this;
3209    };
3210    /*\
3211     * Element.toPattern
3212     [ method ]
3213     **
3214     * Creates a `<pattern>` element from the current element
3215     **
3216     * To create a pattern you have to specify the pattern rect:
3217     - x (string|number)
3218     - y (string|number)
3219     - width (string|number)
3220     - height (string|number)
3221     = (Element) the `<pattern>` element
3222     * You can use pattern later on as an argument for `fill` attribute:
3223     | var p = paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({
3224     |         fill: "none",
3225     |         stroke: "#bada55",
3226     |         strokeWidth: 5
3227     |     }).pattern(0, 0, 10, 10),
3228     |     c = paper.circle(200, 200, 100);
3229     | c.attr({
3230     |     fill: p
3231     | });
3232    \*/
3233    elproto.pattern = elproto.toPattern = function (x, y, width, height) {
3234        var p = make("pattern", getSomeDefs(this));
3235        if (x == null) {
3236            x = this.getBBox();
3237        }
3238        if (is(x, "object") && "x" in x) {
3239            y = x.y;
3240            width = x.width;
3241            height = x.height;
3242            x = x.x;
3243        }
3244        $(p.node, {
3245            x: x,
3246            y: y,
3247            width: width,
3248            height: height,
3249            patternUnits: "userSpaceOnUse",
3250            id: p.id,
3251            viewBox: [x, y, width, height].join(" ")
3252        });
3253        p.node.appendChild(this.node);
3254        return p;
3255    };
3256// SIERRA Element.marker(): clarify what a reference point is. E.g., helps you offset the object from its edge such as when centering it over a path.
3257// SIERRA Element.marker(): I suggest the method should accept default reference point values.  Perhaps centered with (refX = width/2) and (refY = height/2)? Also, couldn't it assume the element's current _width_ and _height_? And please specify what _x_ and _y_ mean: offsets? If so, from where?  Couldn't they also be assigned default values?
3258    /*\
3259     * Element.marker
3260     [ method ]
3261     **
3262     * Creates a `<marker>` element from the current element
3263     **
3264     * To create a marker you have to specify the bounding rect and reference point:
3265     - x (number)
3266     - y (number)
3267     - width (number)
3268     - height (number)
3269     - refX (number)
3270     - refY (number)
3271     = (Element) the `<marker>` element
3272     * You can specify the marker later as an argument for `marker-start`, `marker-end`, `marker-mid`, and `marker` attributes. The `marker` attribute places the marker at every point along the path, and `marker-mid` places them at every point except the start and end.
3273    \*/
3274    // TODO add usage for markers
3275    elproto.marker = function (x, y, width, height, refX, refY) {
3276        var p = make("marker", getSomeDefs(this));
3277        if (x == null) {
3278            x = this.getBBox();
3279        }
3280        if (is(x, "object") && "x" in x) {
3281            y = x.y;
3282            width = x.width;
3283            height = x.height;
3284            refX = x.refX || x.cx;
3285            refY = x.refY || x.cy;
3286            x = x.x;
3287        }
3288        $(p.node, {
3289            viewBox: [x, y, width, height].join(" "),
3290            markerWidth: width,
3291            markerHeight: height,
3292            orient: "auto",
3293            refX: refX || 0,
3294            refY: refY || 0,
3295            id: p.id
3296        });
3297        p.node.appendChild(this.node);
3298        return p;
3299    };
3300    // animation
3301    function slice(from, to, f) {
3302        return function (arr) {
3303            var res = arr.slice(from, to);
3304            if (res.length == 1) {
3305                res = res[0];
3306            }
3307            return f ? f(res) : res;
3308        };
3309    }
3310    var Animation = function (attr, ms, easing, callback) {
3311        if (typeof easing == "function" && !easing.length) {
3312            callback = easing;
3313            easing = mina.linear;
3314        }
3315        this.attr = attr;
3316        this.dur = ms;
3317        easing && (this.easing = easing);
3318        callback && (this.callback = callback);
3319    };
3320    Snap._.Animation = Animation;
3321    /*\
3322     * Snap.animation
3323     [ method ]
3324     **
3325     * Creates an animation object
3326     **
3327     - attr (object) attributes of final destination
3328     - duration (number) duration of the animation, in milliseconds
3329     - easing (function) #optional one of easing functions of @mina or custom one
3330     - callback (function) #optional callback function that fires when animation ends
3331     = (object) animation object
3332    \*/
3333    Snap.animation = function (attr, ms, easing, callback) {
3334        return new Animation(attr, ms, easing, callback);
3335    };
3336    /*\
3337     * Element.inAnim
3338     [ method ]
3339     **
3340     * Returns a set of animations that may be able to manipulate the current element
3341     **
3342     = (object) in format:
3343     o {
3344     o     anim (object) animation object,
3345     o     mina (object) @mina object,
3346     o     curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished,
3347     o     status (function) gets or sets the status of the animation,
3348     o     stop (function) stops the animation
3349     o }
3350    \*/
3351    elproto.inAnim = function () {
3352        var el = this,
3353            res = [];
3354        for (var id in el.anims) if (el.anims[has](id)) {
3355            (function (a) {
3356                res.push({
3357                    anim: new Animation(a._attrs, a.dur, a.easing, a._callback),
3358                    mina: a,
3359                    curStatus: a.status(),
3360                    status: function (val) {
3361                        return a.status(val);
3362                    },
3363                    stop: function () {
3364                        a.stop();
3365                    }
3366                });
3367            }(el.anims[id]));
3368        }
3369        return res;
3370    };
3371    /*\
3372     * Snap.animate
3373     [ method ]
3374     **
3375     * Runs generic animation of one number into another with a caring function
3376     **
3377     - from (number|array) number or array of numbers
3378     - to (number|array) number or array of numbers
3379     - setter (function) caring function that accepts one number argument
3380     - duration (number) duration, in milliseconds
3381     - easing (function) #optional easing function from @mina or custom
3382     - callback (function) #optional callback function to execute when animation ends
3383     = (object) animation object in @mina format
3384     o {
3385     o     id (string) animation id, consider it read-only,
3386     o     duration (function) gets or sets the duration of the animation,
3387     o     easing (function) easing,
3388     o     speed (function) gets or sets the speed of the animation,
3389     o     status (function) gets or sets the status of the animation,
3390     o     stop (function) stops the animation
3391     o }
3392     | var rect = Snap().rect(0, 0, 10, 10);
3393     | Snap.animate(0, 10, function (val) {
3394     |     rect.attr({
3395     |         x: val
3396     |     });
3397     | }, 1000);
3398     | // in given context is equivalent to
3399     | rect.animate({x: 10}, 1000);
3400    \*/
3401    Snap.animate = function (from, to, setter, ms, easing, callback) {
3402        if (typeof easing == "function" && !easing.length) {
3403            callback = easing;
3404            easing = mina.linear;
3405        }
3406        var now = mina.time(),
3407            anim = mina(from, to, now, now + ms, mina.time, setter, easing);
3408        callback && eve.once("mina.finish." + anim.id, callback);
3409        return anim;
3410    };
3411    /*\
3412     * Element.stop
3413     [ method ]
3414     **
3415     * Stops all the animations for the current element
3416     **
3417     = (Element) the current element
3418    \*/
3419    elproto.stop = function () {
3420        var anims = this.inAnim();
3421        for (var i = 0, ii = anims.length; i < ii; i++) {
3422            anims[i].stop();
3423        }
3424        return this;
3425    };
3426    /*\
3427     * Element.animate
3428     [ method ]
3429     **
3430     * Animates the given attributes of the element
3431     **
3432     - attrs (object) key-value pairs of destination attributes
3433     - duration (number) duration of the animation in milliseconds
3434     - easing (function) #optional easing function from @mina or custom
3435     - callback (function) #optional callback function that executes when the animation ends
3436     = (Element) the current element
3437    \*/
3438    elproto.animate = function (attrs, ms, easing, callback) {
3439        if (typeof easing == "function" && !easing.length) {
3440            callback = easing;
3441            easing = mina.linear;
3442        }
3443        if (attrs instanceof Animation) {
3444            callback = attrs.callback;
3445            easing = attrs.easing;
3446            ms = attrs.dur;
3447            attrs = attrs.attr;
3448        }
3449        var fkeys = [], tkeys = [], keys = {}, from, to, f, eq,
3450            el = this;
3451        for (var key in attrs) if (attrs[has](key)) {
3452            if (el.equal) {
3453                eq = el.equal(key, Str(attrs[key]));
3454                from = eq.from;
3455                to = eq.to;
3456                f = eq.f;
3457            } else {
3458                from = +el.attr(key);
3459                to = +attrs[key];
3460            }
3461            var len = is(from, "array") ? from.length : 1;
3462            keys[key] = slice(fkeys.length, fkeys.length + len, f);
3463            fkeys = fkeys.concat(from);
3464            tkeys = tkeys.concat(to);
3465        }
3466        var now = mina.time(),
3467            anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) {
3468                var attr = {};
3469                for (var key in keys) if (keys[has](key)) {
3470                    attr[key] = keys[key](val);
3471                }
3472                el.attr(attr);
3473            }, easing);
3474        el.anims[anim.id] = anim;
3475        anim._attrs = attrs;
3476        anim._callback = callback;
3477        eve("snap.animcreated." + el.id, anim);
3478        eve.once("mina.finish." + anim.id, function () {
3479            delete el.anims[anim.id];
3480            callback && callback.call(el);
3481        });
3482        eve.once("mina.stop." + anim.id, function () {
3483            delete el.anims[anim.id];
3484        });
3485        return el;
3486    };
3487    var eldata = {};
3488    /*\
3489     * Element.data
3490     [ method ]
3491     **
3492     * Adds or retrieves given value associated with given key. (Don’t confuse
3493     * with `data-` attributes)
3494     *
3495     * See also @Element.removeData
3496     - key (string) key to store data
3497     - value (any) #optional value to store
3498     = (object) @Element
3499     * or, if value is not specified:
3500     = (any) value
3501     > Usage
3502     | for (var i = 0, i < 5, i++) {
3503     |     paper.circle(10 + 15 * i, 10, 10)
3504     |          .attr({fill: "#000"})
3505     |          .data("i", i)
3506     |          .click(function () {
3507     |             alert(this.data("i"));
3508     |          });
3509     | }
3510    \*/
3511    elproto.data = function (key, value) {
3512        var data = eldata[this.id] = eldata[this.id] || {};
3513        if (arguments.length == 0){
3514            eve("snap.data.get." + this.id, this, data, null);
3515            return data;
3516        }
3517        if (arguments.length == 1) {
3518            if (Snap.is(key, "object")) {
3519                for (var i in key) if (key[has](i)) {
3520                    this.data(i, key[i]);
3521                }
3522                return this;
3523            }
3524            eve("snap.data.get." + this.id, this, data[key], key);
3525            return data[key];
3526        }
3527        data[key] = value;
3528        eve("snap.data.set." + this.id, this, value, key);
3529        return this;
3530    };
3531    /*\
3532     * Element.removeData
3533     [ method ]
3534     **
3535     * Removes value associated with an element by given key.
3536     * If key is not provided, removes all the data of the element.
3537     - key (string) #optional key
3538     = (object) @Element
3539    \*/
3540    elproto.removeData = function (key) {
3541        if (key == null) {
3542            eldata[this.id] = {};
3543        } else {
3544            eldata[this.id] && delete eldata[this.id][key];
3545        }
3546        return this;
3547    };
3548    /*\
3549     * Element.outerSVG
3550     [ method ]
3551     **
3552     * Returns SVG code for the element, equivalent to HTML's `outerHTML`.
3553     *
3554     * See also @Element.innerSVG
3555     = (string) SVG code for the element
3556    \*/
3557    /*\
3558     * Element.toString
3559     [ method ]
3560     **
3561     * See @Element.outerSVG
3562    \*/
3563    elproto.outerSVG = elproto.toString = toString(1);
3564    /*\
3565     * Element.innerSVG
3566     [ method ]
3567     **
3568     * Returns SVG code for the element's contents, equivalent to HTML's `innerHTML`
3569     = (string) SVG code for the element
3570    \*/
3571    elproto.innerSVG = toString();
3572    function toString(type) {
3573        return function () {
3574            var res = type ? "<" + this.type : "",
3575                attr = this.node.attributes,
3576                chld = this.node.childNodes;
3577            if (type) {
3578                for (var i = 0, ii = attr.length; i < ii; i++) {
3579                    res += " " + attr[i].name + '="' +
3580                            attr[i].value.replace(/"/g, '\\"') + '"';
3581                }
3582            }
3583            if (chld.length) {
3584                type && (res += ">");
3585                for (i = 0, ii = chld.length; i < ii; i++) {
3586                    if (chld[i].nodeType == 3) {
3587                        res += chld[i].nodeValue;
3588                    } else if (chld[i].nodeType == 1) {
3589                        res += wrap(chld[i]).toString();
3590                    }
3591                }
3592                type && (res += "</" + this.type + ">");
3593            } else {
3594                type && (res += "/>");
3595            }
3596            return res;
3597        };
3598    }
3599    elproto.toDataURL = function () {
3600        if (window && window.btoa) {
3601            var bb = this.getBBox(),
3602                svg = Snap.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>', {
3603                x: +bb.x.toFixed(3),
3604                y: +bb.y.toFixed(3),
3605                width: +bb.width.toFixed(3),
3606                height: +bb.height.toFixed(3),
3607                contents: this.outerSVG()
3608            });
3609            return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg)));
3610        }
3611    };
3612    /*\
3613     * Fragment.select
3614     [ method ]
3615     **
3616     * See @Element.select
3617    \*/
3618    Fragment.prototype.select = elproto.select;
3619    /*\
3620     * Fragment.selectAll
3621     [ method ]
3622     **
3623     * See @Element.selectAll
3624    \*/
3625    Fragment.prototype.selectAll = elproto.selectAll;
3626});
3627
3628// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
3629//
3630// Licensed under the Apache License, Version 2.0 (the "License");
3631// you may not use this file except in compliance with the License.
3632// You may obtain a copy of the License at
3633//
3634// http://www.apache.org/licenses/LICENSE-2.0
3635//
3636// Unless required by applicable law or agreed to in writing, software
3637// distributed under the License is distributed on an "AS IS" BASIS,
3638// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3639// See the License for the specific language governing permissions and
3640// limitations under the License.
3641Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
3642    var objectToString = Object.prototype.toString,
3643        Str = String,
3644        math = Math,
3645        E = "";
3646    function Matrix(a, b, c, d, e, f) {
3647        if (b == null && objectToString.call(a) == "[object SVGMatrix]") {
3648            this.a = a.a;
3649            this.b = a.b;
3650            this.c = a.c;
3651            this.d = a.d;
3652            this.e = a.e;
3653            this.f = a.f;
3654            return;
3655        }
3656        if (a != null) {
3657            this.a = +a;
3658            this.b = +b;
3659            this.c = +c;
3660            this.d = +d;
3661            this.e = +e;
3662            this.f = +f;
3663        } else {
3664            this.a = 1;
3665            this.b = 0;
3666            this.c = 0;
3667            this.d = 1;
3668            this.e = 0;
3669            this.f = 0;
3670        }
3671    }
3672    (function (matrixproto) {
3673        /*\
3674         * Matrix.add
3675         [ method ]
3676         **
3677         * Adds the given matrix to existing one
3678         - a (number)
3679         - b (number)
3680         - c (number)
3681         - d (number)
3682         - e (number)
3683         - f (number)
3684         * or
3685         - matrix (object) @Matrix
3686        \*/
3687        matrixproto.add = function (a, b, c, d, e, f) {
3688            var out = [[], [], []],
3689                m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]],
3690                matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
3691                x, y, z, res;
3692
3693            if (a && a instanceof Matrix) {
3694                matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]];
3695            }
3696
3697            for (x = 0; x < 3; x++) {
3698                for (y = 0; y < 3; y++) {
3699                    res = 0;
3700                    for (z = 0; z < 3; z++) {
3701                        res += m[x][z] * matrix[z][y];
3702                    }
3703                    out[x][y] = res;
3704                }
3705            }
3706            this.a = out[0][0];
3707            this.b = out[1][0];
3708            this.c = out[0][1];
3709            this.d = out[1][1];
3710            this.e = out[0][2];
3711            this.f = out[1][2];
3712            return this;
3713        };
3714        /*\
3715         * Matrix.invert
3716         [ method ]
3717         **
3718         * Returns an inverted version of the matrix
3719         = (object) @Matrix
3720        \*/
3721        matrixproto.invert = function () {
3722            var me = this,
3723                x = me.a * me.d - me.b * me.c;
3724            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);
3725        };
3726        /*\
3727         * Matrix.clone
3728         [ method ]
3729         **
3730         * Returns a copy of the matrix
3731         = (object) @Matrix
3732        \*/
3733        matrixproto.clone = function () {
3734            return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
3735        };
3736        /*\
3737         * Matrix.translate
3738         [ method ]
3739         **
3740         * Translate the matrix
3741         - x (number) horizontal offset distance
3742         - y (number) vertical offset distance
3743        \*/
3744        matrixproto.translate = function (x, y) {
3745            return this.add(1, 0, 0, 1, x, y);
3746        };
3747        /*\
3748         * Matrix.scale
3749         [ method ]
3750         **
3751         * Scales the matrix
3752         - x (number) amount to be scaled, with `1` resulting in no change
3753         - y (number) #optional amount to scale along the vertical axis. (Otherwise `x` applies to both axes.)
3754         - cx (number) #optional horizontal origin point from which to scale
3755         - cy (number) #optional vertical origin point from which to scale
3756         * Default cx, cy is the middle point of the element.
3757        \*/
3758        matrixproto.scale = function (x, y, cx, cy) {
3759            y == null && (y = x);
3760            (cx || cy) && this.add(1, 0, 0, 1, cx, cy);
3761            this.add(x, 0, 0, y, 0, 0);
3762            (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy);
3763            return this;
3764        };
3765        /*\
3766         * Matrix.rotate
3767         [ method ]
3768         **
3769         * Rotates the matrix
3770         - a (number) angle of rotation, in degrees
3771         - x (number) horizontal origin point from which to rotate
3772         - y (number) vertical origin point from which to rotate
3773        \*/
3774        matrixproto.rotate = function (a, x, y) {
3775            a = Snap.rad(a);
3776            x = x || 0;
3777            y = y || 0;
3778            var cos = +math.cos(a).toFixed(9),
3779                sin = +math.sin(a).toFixed(9);
3780            this.add(cos, sin, -sin, cos, x, y);
3781            return this.add(1, 0, 0, 1, -x, -y);
3782        };
3783        /*\
3784         * Matrix.x
3785         [ method ]
3786         **
3787         * Returns x coordinate for given point after transformation described by the matrix. See also @Matrix.y
3788         - x (number)
3789         - y (number)
3790         = (number) x
3791        \*/
3792        matrixproto.x = function (x, y) {
3793            return x * this.a + y * this.c + this.e;
3794        };
3795        /*\
3796         * Matrix.y
3797         [ method ]
3798         **
3799         * Returns y coordinate for given point after transformation described by the matrix. See also @Matrix.x
3800         - x (number)
3801         - y (number)
3802         = (number) y
3803        \*/
3804        matrixproto.y = function (x, y) {
3805            return x * this.b + y * this.d + this.f;
3806        };
3807        matrixproto.get = function (i) {
3808            return +this[Str.fromCharCode(97 + i)].toFixed(4);
3809        };
3810        matrixproto.toString = function () {
3811            return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")";
3812        };
3813        matrixproto.offset = function () {
3814            return [this.e.toFixed(4), this.f.toFixed(4)];
3815        };
3816        function norm(a) {
3817            return a[0] * a[0] + a[1] * a[1];
3818        }
3819        function normalize(a) {
3820            var mag = math.sqrt(norm(a));
3821            a[0] && (a[0] /= mag);
3822            a[1] && (a[1] /= mag);
3823        }
3824        /*\
3825         * Matrix.determinant
3826         [ method ]
3827         **
3828         * Finds determinant of the given matrix.
3829         = (number) determinant
3830        \*/
3831        matrixproto.determinant = function () {
3832            return this.a * this.d - this.b * this.c;
3833        };
3834        /*\
3835         * Matrix.split
3836         [ method ]
3837         **
3838         * Splits matrix into primitive transformations
3839         = (object) in format:
3840         o dx (number) translation by x
3841         o dy (number) translation by y
3842         o scalex (number) scale by x
3843         o scaley (number) scale by y
3844         o shear (number) shear
3845         o rotate (number) rotation in deg
3846         o isSimple (boolean) could it be represented via simple transformations
3847        \*/
3848        matrixproto.split = function () {
3849            var out = {};
3850            // translation
3851            out.dx = this.e;
3852            out.dy = this.f;
3853
3854            // scale and shear
3855            var row = [[this.a, this.c], [this.b, this.d]];
3856            out.scalex = math.sqrt(norm(row[0]));
3857            normalize(row[0]);
3858
3859            out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
3860            row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
3861
3862            out.scaley = math.sqrt(norm(row[1]));
3863            normalize(row[1]);
3864            out.shear /= out.scaley;
3865
3866            if (this.determinant() < 0) {
3867                out.scalex = -out.scalex;
3868            }
3869
3870            // rotation
3871            var sin = -row[0][1],
3872                cos = row[1][1];
3873            if (cos < 0) {
3874                out.rotate = Snap.deg(math.acos(cos));
3875                if (sin < 0) {
3876                    out.rotate = 360 - out.rotate;
3877                }
3878            } else {
3879                out.rotate = Snap.deg(math.asin(sin));
3880            }
3881
3882            out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
3883            out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate;
3884            out.noRotation = !+out.shear.toFixed(9) && !out.rotate;
3885            return out;
3886        };
3887        /*\
3888         * Matrix.toTransformString
3889         [ method ]
3890         **
3891         * Returns transform string that represents given matrix
3892         = (string) transform string
3893        \*/
3894        matrixproto.toTransformString = function (shorter) {
3895            var s = shorter || this.split();
3896            if (!+s.shear.toFixed(9)) {
3897                s.scalex = +s.scalex.toFixed(4);
3898                s.scaley = +s.scaley.toFixed(4);
3899                s.rotate = +s.rotate.toFixed(4);
3900                return  (s.dx || s.dy ? "t" + [+s.dx.toFixed(4), +s.dy.toFixed(4)] : E) +
3901                        (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) +
3902                        (s.rotate ? "r" + [+s.rotate.toFixed(4), 0, 0] : E);
3903            } else {
3904                return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
3905            }
3906        };
3907    })(Matrix.prototype);
3908    /*\
3909     * Snap.Matrix
3910     [ method ]
3911     **
3912     * Matrix constructor, extend on your own risk.
3913     * To create matrices use @Snap.matrix.
3914    \*/
3915    Snap.Matrix = Matrix;
3916    /*\
3917     * Snap.matrix
3918     [ method ]
3919     **
3920     * Utility method
3921     **
3922     * Returns a matrix based on the given parameters
3923     - a (number)
3924     - b (number)
3925     - c (number)
3926     - d (number)
3927     - e (number)
3928     - f (number)
3929     * or
3930     - svgMatrix (SVGMatrix)
3931     = (object) @Matrix
3932    \*/
3933    Snap.matrix = function (a, b, c, d, e, f) {
3934        return new Matrix(a, b, c, d, e, f);
3935    };
3936});
3937// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
3938//
3939// Licensed under the Apache License, Version 2.0 (the "License");
3940// you may not use this file except in compliance with the License.
3941// You may obtain a copy of the License at
3942//
3943// http://www.apache.org/licenses/LICENSE-2.0
3944//
3945// Unless required by applicable law or agreed to in writing, software
3946// distributed under the License is distributed on an "AS IS" BASIS,
3947// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3948// See the License for the specific language governing permissions and
3949// limitations under the License.
3950Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
3951    var has = "hasOwnProperty",
3952        make = Snap._.make,
3953        wrap = Snap._.wrap,
3954        is = Snap.is,
3955        getSomeDefs = Snap._.getSomeDefs,
3956        reURLValue = /^url\(#?([^)]+)\)$/,
3957        $ = Snap._.$,
3958        URL = Snap.url,
3959        Str = String,
3960        separator = Snap._.separator,
3961        E = "";
3962    // Attributes event handlers
3963    eve.on("snap.util.attr.mask", function (value) {
3964        if (value instanceof Element || value instanceof Fragment) {
3965            eve.stop();
3966            if (value instanceof Fragment && value.node.childNodes.length == 1) {
3967                value = value.node.firstChild;
3968                getSomeDefs(this).appendChild(value);
3969                value = wrap(value);
3970            }
3971            if (value.type == "mask") {
3972                var mask = value;
3973            } else {
3974                mask = make("mask", getSomeDefs(this));
3975                mask.node.appendChild(value.node);
3976            }
3977            !mask.node.id && $(mask.node, {
3978                id: mask.id
3979            });
3980            $(this.node, {
3981                mask: URL(mask.id)
3982            });
3983        }
3984    });
3985    (function (clipIt) {
3986        eve.on("snap.util.attr.clip", clipIt);
3987        eve.on("snap.util.attr.clip-path", clipIt);
3988        eve.on("snap.util.attr.clipPath", clipIt);
3989    }(function (value) {
3990        if (value instanceof Element || value instanceof Fragment) {
3991            eve.stop();
3992            if (value.type == "clipPath") {
3993                var clip = value;
3994            } else {
3995                clip = make("clipPath", getSomeDefs(this));
3996                clip.node.appendChild(value.node);
3997                !clip.node.id && $(clip.node, {
3998                    id: clip.id
3999                });
4000            }
4001            $(this.node, {
4002                "clip-path": URL(clip.node.id || clip.id)
4003            });
4004        }
4005    }));
4006    function fillStroke(name) {
4007        return function (value) {
4008            eve.stop();
4009            if (value instanceof Fragment && value.node.childNodes.length == 1 &&
4010                (value.node.firstChild.tagName == "radialGradient" ||
4011                value.node.firstChild.tagName == "linearGradient" ||
4012                value.node.firstChild.tagName == "pattern")) {
4013                value = value.node.firstChild;
4014                getSomeDefs(this).appendChild(value);
4015                value = wrap(value);
4016            }
4017            if (value instanceof Element) {
4018                if (value.type == "radialGradient" || value.type == "linearGradient"
4019                   || value.type == "pattern") {
4020                    if (!value.node.id) {
4021                        $(value.node, {
4022                            id: value.id
4023                        });
4024                    }
4025                    var fill = URL(value.node.id);
4026                } else {
4027                    fill = value.attr(name);
4028                }
4029            } else {
4030                fill = Snap.color(value);
4031                if (fill.error) {
4032                    var grad = Snap(getSomeDefs(this).ownerSVGElement).gradient(value);
4033                    if (grad) {
4034                        if (!grad.node.id) {
4035                            $(grad.node, {
4036                                id: grad.id
4037                            });
4038                        }
4039                        fill = URL(grad.node.id);
4040                    } else {
4041                        fill = value;
4042                    }
4043                } else {
4044                    fill = Str(fill);
4045                }
4046            }
4047            var attrs = {};
4048            attrs[name] = fill;
4049            $(this.node, attrs);
4050            this.node.style[name] = E;
4051        };
4052    }
4053    eve.on("snap.util.attr.fill", fillStroke("fill"));
4054    eve.on("snap.util.attr.stroke", fillStroke("stroke"));
4055    var gradrg = /^([lr])(?:\(([^)]*)\))?(.*)$/i;
4056    eve.on("snap.util.grad.parse", function parseGrad(string) {
4057        string = Str(string);
4058        var tokens = string.match(gradrg);
4059        if (!tokens) {
4060            return null;
4061        }
4062        var type = tokens[1],
4063            params = tokens[2],
4064            stops = tokens[3];
4065        params = params.split(/\s*,\s*/).map(function (el) {
4066            return +el == el ? +el : el;
4067        });
4068        if (params.length == 1 && params[0] == 0) {
4069            params = [];
4070        }
4071        stops = stops.split("-");
4072        stops = stops.map(function (el) {
4073            el = el.split(":");
4074            var out = {
4075                color: el[0]
4076            };
4077            if (el[1]) {
4078                out.offset = parseFloat(el[1]);
4079            }
4080            return out;
4081        });
4082        return {
4083            type: type,
4084            params: params,
4085            stops: stops
4086        };
4087    });
4088
4089    eve.on("snap.util.attr.d", function (value) {
4090        eve.stop();
4091        if (is(value, "array") && is(value[0], "array")) {
4092            value = Snap.path.toString.call(value);
4093        }
4094        value = Str(value);
4095        if (value.match(/[ruo]/i)) {
4096            value = Snap.path.toAbsolute(value);
4097        }
4098        $(this.node, {d: value});
4099    })(-1);
4100    eve.on("snap.util.attr.#text", function (value) {
4101        eve.stop();
4102        value = Str(value);
4103        var txt = glob.doc.createTextNode(value);
4104        while (this.node.firstChild) {
4105            this.node.removeChild(this.node.firstChild);
4106        }
4107        this.node.appendChild(txt);
4108    })(-1);
4109    eve.on("snap.util.attr.path", function (value) {
4110        eve.stop();
4111        this.attr({d: value});
4112    })(-1);
4113    eve.on("snap.util.attr.class", function (value) {
4114        eve.stop();
4115        this.node.className.baseVal = value;
4116    })(-1);
4117    eve.on("snap.util.attr.viewBox", function (value) {
4118        var vb;
4119        if (is(value, "object") && "x" in value) {
4120            vb = [value.x, value.y, value.width, value.height].join(" ");
4121        } else if (is(value, "array")) {
4122            vb = value.join(" ");
4123        } else {
4124            vb = value;
4125        }
4126        $(this.node, {
4127            viewBox: vb
4128        });
4129        eve.stop();
4130    })(-1);
4131    eve.on("snap.util.attr.transform", function (value) {
4132        this.transform(value);
4133        eve.stop();
4134    })(-1);
4135    eve.on("snap.util.attr.r", function (value) {
4136        if (this.type == "rect") {
4137            eve.stop();
4138            $(this.node, {
4139                rx: value,
4140                ry: value
4141            });
4142        }
4143    })(-1);
4144    eve.on("snap.util.attr.textpath", function (value) {
4145        eve.stop();
4146        if (this.type == "text") {
4147            var id, tp, node;
4148            if (!value && this.textPath) {
4149                tp = this.textPath;
4150                while (tp.node.firstChild) {
4151                    this.node.appendChild(tp.node.firstChild);
4152                }
4153                tp.remove();
4154                delete this.textPath;
4155                return;
4156            }
4157            if (is(value, "string")) {
4158                var defs = getSomeDefs(this),
4159                    path = wrap(defs.parentNode).path(value);
4160                defs.appendChild(path.node);
4161                id = path.id;
4162                path.attr({id: id});
4163            } else {
4164                value = wrap(value);
4165                if (value instanceof Element) {
4166                    id = value.attr("id");
4167                    if (!id) {
4168                        id = value.id;
4169                        value.attr({id: id});
4170                    }
4171                }
4172            }
4173            if (id) {
4174                tp = this.textPath;
4175                node = this.node;
4176                if (tp) {
4177                    tp.attr({"xlink:href": "#" + id});
4178                } else {
4179                    tp = $("textPath", {
4180                        "xlink:href": "#" + id
4181                    });
4182                    while (node.firstChild) {
4183                        tp.appendChild(node.firstChild);
4184                    }
4185                    node.appendChild(tp);
4186                    this.textPath = wrap(tp);
4187                }
4188            }
4189        }
4190    })(-1);
4191    eve.on("snap.util.attr.text", function (value) {
4192        if (this.type == "text") {
4193            var i = 0,
4194                node = this.node,
4195                tuner = function (chunk) {
4196                    var out = $("tspan");
4197                    if (is(chunk, "array")) {
4198                        for (var i = 0; i < chunk.length; i++) {
4199                            out.appendChild(tuner(chunk[i]));
4200                        }
4201                    } else {
4202                        out.appendChild(glob.doc.createTextNode(chunk));
4203                    }
4204                    out.normalize && out.normalize();
4205                    return out;
4206                };
4207            while (node.firstChild) {
4208                node.removeChild(node.firstChild);
4209            }
4210            var tuned = tuner(value);
4211            while (tuned.firstChild) {
4212                node.appendChild(tuned.firstChild);
4213            }
4214        }
4215        eve.stop();
4216    })(-1);
4217    function setFontSize(value) {
4218        eve.stop();
4219        if (value == +value) {
4220            value += "px";
4221        }
4222        this.node.style.fontSize = value;
4223    }
4224    eve.on("snap.util.attr.fontSize", setFontSize)(-1);
4225    eve.on("snap.util.attr.font-size", setFontSize)(-1);
4226
4227
4228    eve.on("snap.util.getattr.transform", function () {
4229        eve.stop();
4230        return this.transform();
4231    })(-1);
4232    eve.on("snap.util.getattr.textpath", function () {
4233        eve.stop();
4234        return this.textPath;
4235    })(-1);
4236    // Markers
4237    (function () {
4238        function getter(end) {
4239            return function () {
4240                eve.stop();
4241                var style = glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue("marker-" + end);
4242                if (style == "none") {
4243                    return style;
4244                } else {
4245                    return Snap(glob.doc.getElementById(style.match(reURLValue)[1]));
4246                }
4247            };
4248        }
4249        function setter(end) {
4250            return function (value) {
4251                eve.stop();
4252                var name = "marker" + end.charAt(0).toUpperCase() + end.substring(1);
4253                if (value == "" || !value) {
4254                    this.node.style[name] = "none";
4255                    return;
4256                }
4257                if (value.type == "marker") {
4258                    var id = value.node.id;
4259                    if (!id) {
4260                        $(value.node, {id: value.id});
4261                    }
4262                    this.node.style[name] = URL(id);
4263                    return;
4264                }
4265            };
4266        }
4267        eve.on("snap.util.getattr.marker-end", getter("end"))(-1);
4268        eve.on("snap.util.getattr.markerEnd", getter("end"))(-1);
4269        eve.on("snap.util.getattr.marker-start", getter("start"))(-1);
4270        eve.on("snap.util.getattr.markerStart", getter("start"))(-1);
4271        eve.on("snap.util.getattr.marker-mid", getter("mid"))(-1);
4272        eve.on("snap.util.getattr.markerMid", getter("mid"))(-1);
4273        eve.on("snap.util.attr.marker-end", setter("end"))(-1);
4274        eve.on("snap.util.attr.markerEnd", setter("end"))(-1);
4275        eve.on("snap.util.attr.marker-start", setter("start"))(-1);
4276        eve.on("snap.util.attr.markerStart", setter("start"))(-1);
4277        eve.on("snap.util.attr.marker-mid", setter("mid"))(-1);
4278        eve.on("snap.util.attr.markerMid", setter("mid"))(-1);
4279    }());
4280    eve.on("snap.util.getattr.r", function () {
4281        if (this.type == "rect" && $(this.node, "rx") == $(this.node, "ry")) {
4282            eve.stop();
4283            return $(this.node, "rx");
4284        }
4285    })(-1);
4286    function textExtract(node) {
4287        var out = [];
4288        var children = node.childNodes;
4289        for (var i = 0, ii = children.length; i < ii; i++) {
4290            var chi = children[i];
4291            if (chi.nodeType == 3) {
4292                out.push(chi.nodeValue);
4293            }
4294            if (chi.tagName == "tspan") {
4295                if (chi.childNodes.length == 1 && chi.firstChild.nodeType == 3) {
4296                    out.push(chi.firstChild.nodeValue);
4297                } else {
4298                    out.push(textExtract(chi));
4299                }
4300            }
4301        }
4302        return out;
4303    }
4304    eve.on("snap.util.getattr.text", function () {
4305        if (this.type == "text" || this.type == "tspan") {
4306            eve.stop();
4307            var out = textExtract(this.node);
4308            return out.length == 1 ? out[0] : out;
4309        }
4310    })(-1);
4311    eve.on("snap.util.getattr.#text", function () {
4312        return this.node.textContent;
4313    })(-1);
4314    eve.on("snap.util.getattr.viewBox", function () {
4315        eve.stop();
4316        var vb = $(this.node, "viewBox");
4317        if (vb) {
4318            vb = vb.split(separator);
4319            return Snap._.box(+vb[0], +vb[1], +vb[2], +vb[3]);
4320        } else {
4321            return;
4322        }
4323    })(-1);
4324    eve.on("snap.util.getattr.points", function () {
4325        var p = $(this.node, "points");
4326        eve.stop();
4327        if (p) {
4328            return p.split(separator);
4329        } else {
4330            return;
4331        }
4332    })(-1);
4333    eve.on("snap.util.getattr.path", function () {
4334        var p = $(this.node, "d");
4335        eve.stop();
4336        return p;
4337    })(-1);
4338    eve.on("snap.util.getattr.class", function () {
4339        return this.node.className.baseVal;
4340    })(-1);
4341    function getFontSize() {
4342        eve.stop();
4343        return this.node.style.fontSize;
4344    }
4345    eve.on("snap.util.getattr.fontSize", getFontSize)(-1);
4346    eve.on("snap.util.getattr.font-size", getFontSize)(-1);
4347});
4348
4349// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
4350//
4351// Licensed under the Apache License, Version 2.0 (the "License");
4352// you may not use this file except in compliance with the License.
4353// You may obtain a copy of the License at
4354//
4355// http://www.apache.org/licenses/LICENSE-2.0
4356//
4357// Unless required by applicable law or agreed to in writing, software
4358// distributed under the License is distributed on an "AS IS" BASIS,
4359// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4360// See the License for the specific language governing permissions and
4361// limitations under the License.
4362Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
4363    var rgNotSpace = /\S+/g,
4364        rgBadSpace = /[\t\r\n\f]/g,
4365        rgTrim = /(^\s+|\s+$)/g,
4366        Str = String,
4367        elproto = Element.prototype;
4368    /*\
4369     * Element.addClass
4370     [ method ]
4371     **
4372     * Adds given class name or list of class names to the element.
4373     - value (string) class name or space separated list of class names
4374     **
4375     = (Element) original element.
4376    \*/
4377    elproto.addClass = function (value) {
4378        var classes = Str(value || "").match(rgNotSpace) || [],
4379            elem = this.node,
4380            className = elem.className.baseVal,
4381            curClasses = className.match(rgNotSpace) || [],
4382            j,
4383            pos,
4384            clazz,
4385            finalValue;
4386
4387        if (classes.length) {
4388            j = 0;
4389            while ((clazz = classes[j++])) {
4390                pos = curClasses.indexOf(clazz);
4391                if (!~pos) {
4392                    curClasses.push(clazz);
4393                }
4394            }
4395
4396            finalValue = curClasses.join(" ");
4397            if (className != finalValue) {
4398                elem.className.baseVal = finalValue;
4399            }
4400        }
4401        return this;
4402    };
4403    /*\
4404     * Element.removeClass
4405     [ method ]
4406     **
4407     * Removes given class name or list of class names from the element.
4408     - value (string) class name or space separated list of class names
4409     **
4410     = (Element) original element.
4411    \*/
4412    elproto.removeClass = function (value) {
4413        var classes = Str(value || "").match(rgNotSpace) || [],
4414            elem = this.node,
4415            className = elem.className.baseVal,
4416            curClasses = className.match(rgNotSpace) || [],
4417            j,
4418            pos,
4419            clazz,
4420            finalValue;
4421        if (curClasses.length) {
4422            j = 0;
4423            while ((clazz = classes[j++])) {
4424                pos = curClasses.indexOf(clazz);
4425                if (~pos) {
4426                    curClasses.splice(pos, 1);
4427                }
4428            }
4429
4430            finalValue = curClasses.join(" ");
4431            if (className != finalValue) {
4432                elem.className.baseVal = finalValue;
4433            }
4434        }
4435        return this;
4436    };
4437    /*\
4438     * Element.hasClass
4439     [ method ]
4440     **
4441     * Checks if the element has a given class name in the list of class names applied to it.
4442     - value (string) class name
4443     **
4444     = (boolean) `true` if the element has given class
4445    \*/
4446    elproto.hasClass = function (value) {
4447        var elem = this.node,
4448            className = elem.className.baseVal,
4449            curClasses = className.match(rgNotSpace) || [];
4450        return !!~curClasses.indexOf(value);
4451    };
4452    /*\
4453     * Element.toggleClass
4454     [ method ]
4455     **
4456     * Add or remove one or more classes from the element, depending on either
4457     * the class’s presence or the value of the `flag` argument.
4458     - value (string) class name or space separated list of class names
4459     - flag (boolean) value to determine whether the class should be added or removed
4460     **
4461     = (Element) original element.
4462    \*/
4463    elproto.toggleClass = function (value, flag) {
4464        if (flag != null) {
4465            if (flag) {
4466                return this.addClass(value);
4467            } else {
4468                return this.removeClass(value);
4469            }
4470        }
4471        var classes = (value || "").match(rgNotSpace) || [],
4472            elem = this.node,
4473            className = elem.className.baseVal,
4474            curClasses = className.match(rgNotSpace) || [],
4475            j,
4476            pos,
4477            clazz,
4478            finalValue;
4479        j = 0;
4480        while ((clazz = classes[j++])) {
4481            pos = curClasses.indexOf(clazz);
4482            if (~pos) {
4483                curClasses.splice(pos, 1);
4484            } else {
4485                curClasses.push(clazz);
4486            }
4487        }
4488
4489        finalValue = curClasses.join(" ");
4490        if (className != finalValue) {
4491            elem.className.baseVal = finalValue;
4492        }
4493        return this;
4494    };
4495});
4496
4497// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
4498//
4499// Licensed under the Apache License, Version 2.0 (the "License");
4500// you may not use this file except in compliance with the License.
4501// You may obtain a copy of the License at
4502//
4503// http://www.apache.org/licenses/LICENSE-2.0
4504//
4505// Unless required by applicable law or agreed to in writing, software
4506// distributed under the License is distributed on an "AS IS" BASIS,
4507// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4508// See the License for the specific language governing permissions and
4509// limitations under the License.
4510Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
4511    var operators = {
4512            "+": function (x, y) {
4513                    return x + y;
4514                },
4515            "-": function (x, y) {
4516                    return x - y;
4517                },
4518            "/": function (x, y) {
4519                    return x / y;
4520                },
4521            "*": function (x, y) {
4522                    return x * y;
4523                }
4524        },
4525        Str = String,
4526        reUnit = /[a-z]+$/i,
4527        reAddon = /^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/;
4528    function getNumber(val) {
4529        return val;
4530    }
4531    function getUnit(unit) {
4532        return function (val) {
4533            return +val.toFixed(3) + unit;
4534        };
4535    }
4536    eve.on("snap.util.attr", function (val) {
4537        var plus = Str(val).match(reAddon);
4538        if (plus) {
4539            var evnt = eve.nt(),
4540                name = evnt.substring(evnt.lastIndexOf(".") + 1),
4541                a = this.attr(name),
4542                atr = {};
4543            eve.stop();
4544            var unit = plus[3] || "",
4545                aUnit = a.match(reUnit),
4546                op = operators[plus[1]];
4547            if (aUnit && aUnit == unit) {
4548                val = op(parseFloat(a), +plus[2]);
4549            } else {
4550                a = this.asPX(name);
4551                val = op(this.asPX(name), this.asPX(name, plus[2] + unit));
4552            }
4553            if (isNaN(a) || isNaN(val)) {
4554                return;
4555            }
4556            atr[name] = val;
4557            this.attr(atr);
4558        }
4559    })(-10);
4560    eve.on("snap.util.equal", function (name, b) {
4561        var A, B, a = Str(this.attr(name) || ""),
4562            el = this,
4563            bplus = Str(b).match(reAddon);
4564        if (bplus) {
4565            eve.stop();
4566            var unit = bplus[3] || "",
4567                aUnit = a.match(reUnit),
4568                op = operators[bplus[1]];
4569            if (aUnit && aUnit == unit) {
4570                return {
4571                    from: parseFloat(a),
4572                    to: op(parseFloat(a), +bplus[2]),
4573                    f: getUnit(aUnit)
4574                };
4575            } else {
4576                a = this.asPX(name);
4577                return {
4578                    from: a,
4579                    to: op(a, this.asPX(name, bplus[2] + unit)),
4580                    f: getNumber
4581                };
4582            }
4583        }
4584    })(-10);
4585});
4586// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
4587//
4588// Licensed under the Apache License, Version 2.0 (the "License");
4589// you may not use this file except in compliance with the License.
4590// You may obtain a copy of the License at
4591//
4592// http://www.apache.org/licenses/LICENSE-2.0
4593//
4594// Unless required by applicable law or agreed to in writing, software
4595// distributed under the License is distributed on an "AS IS" BASIS,
4596// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4597// See the License for the specific language governing permissions and
4598// limitations under the License.
4599Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
4600    var proto = Paper.prototype,
4601        is = Snap.is;
4602    /*\
4603     * Paper.rect
4604     [ method ]
4605     *
4606     * Draws a rectangle
4607     **
4608     - x (number) x coordinate of the top left corner
4609     - y (number) y coordinate of the top left corner
4610     - width (number) width
4611     - height (number) height
4612     - rx (number) #optional horizontal radius for rounded corners, default is 0
4613     - ry (number) #optional vertical radius for rounded corners, default is rx or 0
4614     = (object) the `rect` element
4615     **
4616     > Usage
4617     | // regular rectangle
4618     | var c = paper.rect(10, 10, 50, 50);
4619     | // rectangle with rounded corners
4620     | var c = paper.rect(40, 40, 50, 50, 10);
4621    \*/
4622    proto.rect = function (x, y, w, h, rx, ry) {
4623        var attr;
4624        if (ry == null) {
4625            ry = rx;
4626        }
4627        if (is(x, "object") && x == "[object Object]") {
4628            attr = x;
4629        } else if (x != null) {
4630            attr = {
4631                x: x,
4632                y: y,
4633                width: w,
4634                height: h
4635            };
4636            if (rx != null) {
4637                attr.rx = rx;
4638                attr.ry = ry;
4639            }
4640        }
4641        return this.el("rect", attr);
4642    };
4643    /*\
4644     * Paper.circle
4645     [ method ]
4646     **
4647     * Draws a circle
4648     **
4649     - x (number) x coordinate of the centre
4650     - y (number) y coordinate of the centre
4651     - r (number) radius
4652     = (object) the `circle` element
4653     **
4654     > Usage
4655     | var c = paper.circle(50, 50, 40);
4656    \*/
4657    proto.circle = function (cx, cy, r) {
4658        var attr;
4659        if (is(cx, "object") && cx == "[object Object]") {
4660            attr = cx;
4661        } else if (cx != null) {
4662            attr = {
4663                cx: cx,
4664                cy: cy,
4665                r: r
4666            };
4667        }
4668        return this.el("circle", attr);
4669    };
4670
4671    var preload = (function () {
4672        function onerror() {
4673            this.parentNode.removeChild(this);
4674        }
4675        return function (src, f) {
4676            var img = glob.doc.createElement("img"),
4677                body = glob.doc.body;
4678            img.style.cssText = "position:absolute;left:-9999em;top:-9999em";
4679            img.onload = function () {
4680                f.call(img);
4681                img.onload = img.onerror = null;
4682                body.removeChild(img);
4683            };
4684            img.onerror = onerror;
4685            body.appendChild(img);
4686            img.src = src;
4687        };
4688    }());
4689
4690    /*\
4691     * Paper.image
4692     [ method ]
4693     **
4694     * Places an image on the surface
4695     **
4696     - src (string) URI of the source image
4697     - x (number) x offset position
4698     - y (number) y offset position
4699     - width (number) width of the image
4700     - height (number) height of the image
4701     = (object) the `image` element
4702     * or
4703     = (object) Snap element object with type `image`
4704     **
4705     > Usage
4706     | var c = paper.image("apple.png", 10, 10, 80, 80);
4707    \*/
4708    proto.image = function (src, x, y, width, height) {
4709        var el = this.el("image");
4710        if (is(src, "object") && "src" in src) {
4711            el.attr(src);
4712        } else if (src != null) {
4713            var set = {
4714                "xlink:href": src,
4715                preserveAspectRatio: "none"
4716            };
4717            if (x != null && y != null) {
4718                set.x = x;
4719                set.y = y;
4720            }
4721            if (width != null && height != null) {
4722                set.width = width;
4723                set.height = height;
4724            } else {
4725                preload(src, function () {
4726                    Snap._.$(el.node, {
4727                        width: this.offsetWidth,
4728                        height: this.offsetHeight
4729                    });
4730                });
4731            }
4732            Snap._.$(el.node, set);
4733        }
4734        return el;
4735    };
4736    /*\
4737     * Paper.ellipse
4738     [ method ]
4739     **
4740     * Draws an ellipse
4741     **
4742     - x (number) x coordinate of the centre
4743     - y (number) y coordinate of the centre
4744     - rx (number) horizontal radius
4745     - ry (number) vertical radius
4746     = (object) the `ellipse` element
4747     **
4748     > Usage
4749     | var c = paper.ellipse(50, 50, 40, 20);
4750    \*/
4751    proto.ellipse = function (cx, cy, rx, ry) {
4752        var attr;
4753        if (is(cx, "object") && cx == "[object Object]") {
4754            attr = cx;
4755        } else if (cx != null) {
4756            attr ={
4757                cx: cx,
4758                cy: cy,
4759                rx: rx,
4760                ry: ry
4761            };
4762        }
4763        return this.el("ellipse", attr);
4764    };
4765    // SIERRA Paper.path(): Unclear from the link what a Catmull-Rom curveto is, and why it would make life any easier.
4766    /*\
4767     * Paper.path
4768     [ method ]
4769     **
4770     * Creates a `<path>` element using the given string as the path's definition
4771     - pathString (string) #optional path string in SVG format
4772     * Path string consists of one-letter commands, followed by comma seprarated arguments in numerical form. Example:
4773     | "M10,20L30,40"
4774     * This example features two commands: `M`, with arguments `(10, 20)` and `L` with arguments `(30, 40)`. Uppercase letter commands express coordinates in absolute terms, while lowercase commands express them in relative terms from the most recently declared coordinates.
4775     *
4776     # <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a> or <a href="https://developer.mozilla.org/en/SVG/Tutorial/Paths">article about path strings at MDN</a>.</p>
4777     # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody>
4778     # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr>
4779     # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr>
4780     # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr>
4781     # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr>
4782     # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr>
4783     # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr>
4784     # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr>
4785     # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr>
4786     # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr>
4787     # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr>
4788     # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table>
4789     * * _Catmull-Rom curveto_ is a not standard SVG command and added to make life easier.
4790     * Note: there is a special case when a path consists of only three commands: `M10,10R…z`. In this case the path connects back to its starting point.
4791     > Usage
4792     | var c = paper.path("M10 10L90 90");
4793     | // draw a diagonal line:
4794     | // move to 10,10, line to 90,90
4795    \*/
4796    proto.path = function (d) {
4797        var attr;
4798        if (is(d, "object") && !is(d, "array")) {
4799            attr = d;
4800        } else if (d) {
4801            attr = {d: d};
4802        }
4803        return this.el("path", attr);
4804    };
4805    /*\
4806     * Paper.g
4807     [ method ]
4808     **
4809     * Creates a group element
4810     **
4811     - varargs (…) #optional elements to nest within the group
4812     = (object) the `g` element
4813     **
4814     > Usage
4815     | var c1 = paper.circle(),
4816     |     c2 = paper.rect(),
4817     |     g = paper.g(c2, c1); // note that the order of elements is different
4818     * or
4819     | var c1 = paper.circle(),
4820     |     c2 = paper.rect(),
4821     |     g = paper.g();
4822     | g.add(c2, c1);
4823    \*/
4824    /*\
4825     * Paper.group
4826     [ method ]
4827     **
4828     * See @Paper.g
4829    \*/
4830    proto.group = proto.g = function (first) {
4831        var attr,
4832            el = this.el("g");
4833        if (arguments.length == 1 && first && !first.type) {
4834            el.attr(first);
4835        } else if (arguments.length) {
4836            el.add(Array.prototype.slice.call(arguments, 0));
4837        }
4838        return el;
4839    };
4840    /*\
4841     * Paper.svg
4842     [ method ]
4843     **
4844     * Creates a nested SVG element.
4845     - x (number) @optional X of the element
4846     - y (number) @optional Y of the element
4847     - width (number) @optional width of the element
4848     - height (number) @optional height of the element
4849     - vbx (number) @optional viewbox X
4850     - vby (number) @optional viewbox Y
4851     - vbw (number) @optional viewbox width
4852     - vbh (number) @optional viewbox height
4853     **
4854     = (object) the `svg` element
4855     **
4856    \*/
4857    proto.svg = function (x, y, width, height, vbx, vby, vbw, vbh) {
4858        var attrs = {};
4859        if (is(x, "object") && y == null) {
4860            attrs = x;
4861        } else {
4862            if (x != null) {
4863                attrs.x = x;
4864            }
4865            if (y != null) {
4866                attrs.y = y;
4867            }
4868            if (width != null) {
4869                attrs.width = width;
4870            }
4871            if (height != null) {
4872                attrs.height = height;
4873            }
4874            if (vbx != null && vby != null && vbw != null && vbh != null) {
4875                attrs.viewBox = [vbx, vby, vbw, vbh];
4876            }
4877        }
4878        return this.el("svg", attrs);
4879    };
4880    /*\
4881     * Paper.mask
4882     [ method ]
4883     **
4884     * Equivalent in behaviour to @Paper.g, except it’s a mask.
4885     **
4886     = (object) the `mask` element
4887     **
4888    \*/
4889    proto.mask = function (first) {
4890        var attr,
4891            el = this.el("mask");
4892        if (arguments.length == 1 && first && !first.type) {
4893            el.attr(first);
4894        } else if (arguments.length) {
4895            el.add(Array.prototype.slice.call(arguments, 0));
4896        }
4897        return el;
4898    };
4899    /*\
4900     * Paper.ptrn
4901     [ method ]
4902     **
4903     * Equivalent in behaviour to @Paper.g, except it’s a pattern.
4904     - x (number) @optional X of the element
4905     - y (number) @optional Y of the element
4906     - width (number) @optional width of the element
4907     - height (number) @optional height of the element
4908     - vbx (number) @optional viewbox X
4909     - vby (number) @optional viewbox Y
4910     - vbw (number) @optional viewbox width
4911     - vbh (number) @optional viewbox height
4912     **
4913     = (object) the `pattern` element
4914     **
4915    \*/
4916    proto.ptrn = function (x, y, width, height, vx, vy, vw, vh) {
4917        if (is(x, "object")) {
4918            var attr = x;
4919        } else {
4920            attr = {patternUnits: "userSpaceOnUse"};
4921            if (x) {
4922                attr.x = x;
4923            }
4924            if (y) {
4925                attr.y = y;
4926            }
4927            if (width != null) {
4928                attr.width = width;
4929            }
4930            if (height != null) {
4931                attr.height = height;
4932            }
4933            if (vx != null && vy != null && vw != null && vh != null) {
4934                attr.viewBox = [vx, vy, vw, vh];
4935            } else {
4936                attr.viewBox = [x || 0, y || 0, width || 0, height || 0];
4937            }
4938        }
4939        return this.el("pattern", attr);
4940    };
4941    /*\
4942     * Paper.use
4943     [ method ]
4944     **
4945     * Creates a <use> element.
4946     - id (string) @optional id of element to link
4947     * or
4948     - id (Element) @optional element to link
4949     **
4950     = (object) the `use` element
4951     **
4952    \*/
4953    proto.use = function (id) {
4954        if (id != null) {
4955            if (id instanceof Element) {
4956                if (!id.attr("id")) {
4957                    id.attr({id: Snap._.id(id)});
4958                }
4959                id = id.attr("id");
4960            }
4961            if (String(id).charAt() == "#") {
4962                id = id.substring(1);
4963            }
4964            return this.el("use", {"xlink:href": "#" + id});
4965        } else {
4966            return Element.prototype.use.call(this);
4967        }
4968    };
4969    /*\
4970     * Paper.symbol
4971     [ method ]
4972     **
4973     * Creates a <symbol> element.
4974     - vbx (number) @optional viewbox X
4975     - vby (number) @optional viewbox Y
4976     - vbw (number) @optional viewbox width
4977     - vbh (number) @optional viewbox height
4978     = (object) the `symbol` element
4979     **
4980    \*/
4981    proto.symbol = function (vx, vy, vw, vh) {
4982        var attr = {};
4983        if (vx != null && vy != null && vw != null && vh != null) {
4984            attr.viewBox = [vx, vy, vw, vh];
4985        }
4986
4987        return this.el("symbol", attr);
4988    };
4989    /*\
4990     * Paper.text
4991     [ method ]
4992     **
4993     * Draws a text string
4994     **
4995     - x (number) x coordinate position
4996     - y (number) y coordinate position
4997     - text (string|array) The text string to draw or array of strings to nest within separate `<tspan>` elements
4998     = (object) the `text` element
4999     **
5000     > Usage
5001     | var t1 = paper.text(50, 50, "Snap");
5002     | var t2 = paper.text(50, 50, ["S","n","a","p"]);
5003     | // Text path usage
5004     | t1.attr({textpath: "M10,10L100,100"});
5005     | // or
5006     | var pth = paper.path("M10,10L100,100");
5007     | t1.attr({textpath: pth});
5008    \*/
5009    proto.text = function (x, y, text) {
5010        var attr = {};
5011        if (is(x, "object")) {
5012            attr = x;
5013        } else if (x != null) {
5014            attr = {
5015                x: x,
5016                y: y,
5017                text: text || ""
5018            };
5019        }
5020        return this.el("text", attr);
5021    };
5022    /*\
5023     * Paper.line
5024     [ method ]
5025     **
5026     * Draws a line
5027     **
5028     - x1 (number) x coordinate position of the start
5029     - y1 (number) y coordinate position of the start
5030     - x2 (number) x coordinate position of the end
5031     - y2 (number) y coordinate position of the end
5032     = (object) the `line` element
5033     **
5034     > Usage
5035     | var t1 = paper.line(50, 50, 100, 100);
5036    \*/
5037    proto.line = function (x1, y1, x2, y2) {
5038        var attr = {};
5039        if (is(x1, "object")) {
5040            attr = x1;
5041        } else if (x1 != null) {
5042            attr = {
5043                x1: x1,
5044                x2: x2,
5045                y1: y1,
5046                y2: y2
5047            };
5048        }
5049        return this.el("line", attr);
5050    };
5051    /*\
5052     * Paper.polyline
5053     [ method ]
5054     **
5055     * Draws a polyline
5056     **
5057     - points (array) array of points
5058     * or
5059     - varargs (…) points
5060     = (object) the `polyline` element
5061     **
5062     > Usage
5063     | var p1 = paper.polyline([10, 10, 100, 100]);
5064     | var p2 = paper.polyline(10, 10, 100, 100);
5065    \*/
5066    proto.polyline = function (points) {
5067        if (arguments.length > 1) {
5068            points = Array.prototype.slice.call(arguments, 0);
5069        }
5070        var attr = {};
5071        if (is(points, "object") && !is(points, "array")) {
5072            attr = points;
5073        } else if (points != null) {
5074            attr = {points: points};
5075        }
5076        return this.el("polyline", attr);
5077    };
5078    /*\
5079     * Paper.polygon
5080     [ method ]
5081     **
5082     * Draws a polygon. See @Paper.polyline
5083    \*/
5084    proto.polygon = function (points) {
5085        if (arguments.length > 1) {
5086            points = Array.prototype.slice.call(arguments, 0);
5087        }
5088        var attr = {};
5089        if (is(points, "object") && !is(points, "array")) {
5090            attr = points;
5091        } else if (points != null) {
5092            attr = {points: points};
5093        }
5094        return this.el("polygon", attr);
5095    };
5096    // gradients
5097    (function () {
5098        var $ = Snap._.$;
5099        // gradients' helpers
5100        function Gstops() {
5101            return this.selectAll("stop");
5102        }
5103        function GaddStop(color, offset) {
5104            var stop = $("stop"),
5105                attr = {
5106                    offset: +offset + "%"
5107                };
5108            color = Snap.color(color);
5109            attr["stop-color"] = color.hex;
5110            if (color.opacity < 1) {
5111                attr["stop-opacity"] = color.opacity;
5112            }
5113            $(stop, attr);
5114            this.node.appendChild(stop);
5115            return this;
5116        }
5117        function GgetBBox() {
5118            if (this.type == "linearGradient") {
5119                var x1 = $(this.node, "x1") || 0,
5120                    x2 = $(this.node, "x2") || 1,
5121                    y1 = $(this.node, "y1") || 0,
5122                    y2 = $(this.node, "y2") || 0;
5123                return Snap._.box(x1, y1, math.abs(x2 - x1), math.abs(y2 - y1));
5124            } else {
5125                var cx = this.node.cx || .5,
5126                    cy = this.node.cy || .5,
5127                    r = this.node.r || 0;
5128                return Snap._.box(cx - r, cy - r, r * 2, r * 2);
5129            }
5130        }
5131        function gradient(defs, str) {
5132            var grad = eve("snap.util.grad.parse", null, str).firstDefined(),
5133                el;
5134            if (!grad) {
5135                return null;
5136            }
5137            grad.params.unshift(defs);
5138            if (grad.type.toLowerCase() == "l") {
5139                el = gradientLinear.apply(0, grad.params);
5140            } else {
5141                el = gradientRadial.apply(0, grad.params);
5142            }
5143            if (grad.type != grad.type.toLowerCase()) {
5144                $(el.node, {
5145                    gradientUnits: "userSpaceOnUse"
5146                });
5147            }
5148            var stops = grad.stops,
5149                len = stops.length,
5150                start = 0,
5151                j = 0;
5152            function seed(i, end) {
5153                var step = (end - start) / (i - j);
5154                for (var k = j; k < i; k++) {
5155                    stops[k].offset = +(+start + step * (k - j)).toFixed(2);
5156                }
5157                j = i;
5158                start = end;
5159            }
5160            len--;
5161            for (var i = 0; i < len; i++) if ("offset" in stops[i]) {
5162                seed(i, stops[i].offset);
5163            }
5164            stops[len].offset = stops[len].offset || 100;
5165            seed(len, stops[len].offset);
5166            for (i = 0; i <= len; i++) {
5167                var stop = stops[i];
5168                el.addStop(stop.color, stop.offset);
5169            }
5170            return el;
5171        }
5172        function gradientLinear(defs, x1, y1, x2, y2) {
5173            var el = Snap._.make("linearGradient", defs);
5174            el.stops = Gstops;
5175            el.addStop = GaddStop;
5176            el.getBBox = GgetBBox;
5177            if (x1 != null) {
5178                $(el.node, {
5179                    x1: x1,
5180                    y1: y1,
5181                    x2: x2,
5182                    y2: y2
5183                });
5184            }
5185            return el;
5186        }
5187        function gradientRadial(defs, cx, cy, r, fx, fy) {
5188            var el = Snap._.make("radialGradient", defs);
5189            el.stops = Gstops;
5190            el.addStop = GaddStop;
5191            el.getBBox = GgetBBox;
5192            if (cx != null) {
5193                $(el.node, {
5194                    cx: cx,
5195                    cy: cy,
5196                    r: r
5197                });
5198            }
5199            if (fx != null && fy != null) {
5200                $(el.node, {
5201                    fx: fx,
5202                    fy: fy
5203                });
5204            }
5205            return el;
5206        }
5207        /*\
5208         * Paper.gradient
5209         [ method ]
5210         **
5211         * Creates a gradient element
5212         **
5213         - gradient (string) gradient descriptor
5214         > Gradient Descriptor
5215         * The gradient descriptor is an expression formatted as
5216         * follows: `<type>(<coords>)<colors>`.  The `<type>` can be
5217         * either linear or radial.  The uppercase `L` or `R` letters
5218         * indicate absolute coordinates offset from the SVG surface.
5219         * Lowercase `l` or `r` letters indicate coordinates
5220         * calculated relative to the element to which the gradient is
5221         * applied.  Coordinates specify a linear gradient vector as
5222         * `x1`, `y1`, `x2`, `y2`, or a radial gradient as `cx`, `cy`,
5223         * `r` and optional `fx`, `fy` specifying a focal point away
5224         * from the center of the circle. Specify `<colors>` as a list
5225         * of dash-separated CSS color values.  Each color may be
5226         * followed by a custom offset value, separated with a colon
5227         * character.
5228         > Examples
5229         * Linear gradient, relative from top-left corner to bottom-right
5230         * corner, from black through red to white:
5231         | var g = paper.gradient("l(0, 0, 1, 1)#000-#f00-#fff");
5232         * Linear gradient, absolute from (0, 0) to (100, 100), from black
5233         * through red at 25% to white:
5234         | var g = paper.gradient("L(0, 0, 100, 100)#000-#f00:25-#fff");
5235         * Radial gradient, relative from the center of the element with radius
5236         * half the width, from black to white:
5237         | var g = paper.gradient("r(0.5, 0.5, 0.5)#000-#fff");
5238         * To apply the gradient:
5239         | paper.circle(50, 50, 40).attr({
5240         |     fill: g
5241         | });
5242         = (object) the `gradient` element
5243        \*/
5244        proto.gradient = function (str) {
5245            return gradient(this.defs, str);
5246        };
5247        proto.gradientLinear = function (x1, y1, x2, y2) {
5248            return gradientLinear(this.defs, x1, y1, x2, y2);
5249        };
5250        proto.gradientRadial = function (cx, cy, r, fx, fy) {
5251            return gradientRadial(this.defs, cx, cy, r, fx, fy);
5252        };
5253        /*\
5254         * Paper.toString
5255         [ method ]
5256         **
5257         * Returns SVG code for the @Paper
5258         = (string) SVG code for the @Paper
5259        \*/
5260        proto.toString = function () {
5261            var doc = this.node.ownerDocument,
5262                f = doc.createDocumentFragment(),
5263                d = doc.createElement("div"),
5264                svg = this.node.cloneNode(true),
5265                res;
5266            f.appendChild(d);
5267            d.appendChild(svg);
5268            Snap._.$(svg, {xmlns: "http://www.w3.org/2000/svg"});
5269            res = d.innerHTML;
5270            f.removeChild(f.firstChild);
5271            return res;
5272        };
5273        /*\
5274         * Paper.toDataURL
5275         [ method ]
5276         **
5277         * Returns SVG code for the @Paper as Data URI string.
5278         = (string) Data URI string
5279        \*/
5280        proto.toDataURL = function () {
5281            if (window && window.btoa) {
5282                return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(this)));
5283            }
5284        };
5285        /*\
5286         * Paper.clear
5287         [ method ]
5288         **
5289         * Removes all child nodes of the paper, except <defs>.
5290        \*/
5291        proto.clear = function () {
5292            var node = this.node.firstChild,
5293                next;
5294            while (node) {
5295                next = node.nextSibling;
5296                if (node.tagName != "defs") {
5297                    node.parentNode.removeChild(node);
5298                } else {
5299                    proto.clear.call({node: node});
5300                }
5301                node = next;
5302            }
5303        };
5304    }());
5305});
5306
5307// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
5308//
5309// Licensed under the Apache License, Version 2.0 (the "License");
5310// you may not use this file except in compliance with the License.
5311// You may obtain a copy of the License at
5312//
5313// http://www.apache.org/licenses/LICENSE-2.0
5314//
5315// Unless required by applicable law or agreed to in writing, software
5316// distributed under the License is distributed on an "AS IS" BASIS,
5317// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5318// See the License for the specific language governing permissions and
5319// limitations under the License.
5320Snap.plugin(function (Snap, Element, Paper, glob) {
5321    var elproto = Element.prototype,
5322        is = Snap.is,
5323        clone = Snap._.clone,
5324        has = "hasOwnProperty",
5325        p2s = /,?([a-z]),?/gi,
5326        toFloat = parseFloat,
5327        math = Math,
5328        PI = math.PI,
5329        mmin = math.min,
5330        mmax = math.max,
5331        pow = math.pow,
5332        abs = math.abs;
5333    function paths(ps) {
5334        var p = paths.ps = paths.ps || {};
5335        if (p[ps]) {
5336            p[ps].sleep = 100;
5337        } else {
5338            p[ps] = {
5339                sleep: 100
5340            };
5341        }
5342        setTimeout(function () {
5343            for (var key in p) if (p[has](key) && key != ps) {
5344                p[key].sleep--;
5345                !p[key].sleep && delete p[key];
5346            }
5347        });
5348        return p[ps];
5349    }
5350    function box(x, y, width, height) {
5351        if (x == null) {
5352            x = y = width = height = 0;
5353        }
5354        if (y == null) {
5355            y = x.y;
5356            width = x.width;
5357            height = x.height;
5358            x = x.x;
5359        }
5360        return {
5361            x: x,
5362            y: y,
5363            width: width,
5364            w: width,
5365            height: height,
5366            h: height,
5367            x2: x + width,
5368            y2: y + height,
5369            cx: x + width / 2,
5370            cy: y + height / 2,
5371            r1: math.min(width, height) / 2,
5372            r2: math.max(width, height) / 2,
5373            r0: math.sqrt(width * width + height * height) / 2,
5374            path: rectPath(x, y, width, height),
5375            vb: [x, y, width, height].join(" ")
5376        };
5377    }
5378    function toString() {
5379        return this.join(",").replace(p2s, "$1");
5380    }
5381    function pathClone(pathArray) {
5382        var res = clone(pathArray);
5383        res.toString = toString;
5384        return res;
5385    }
5386    function getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {
5387        if (length == null) {
5388            return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
5389        } else {
5390            return findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y,
5391                getTotLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length));
5392        }
5393    }
5394    function getLengthFactory(istotal, subpath) {
5395        function O(val) {
5396            return +(+val).toFixed(3);
5397        }
5398        return Snap._.cacher(function (path, length, onlystart) {
5399            if (path instanceof Element) {
5400                path = path.attr("d");
5401            }
5402            path = path2curve(path);
5403            var x, y, p, l, sp = "", subpaths = {}, point,
5404                len = 0;
5405            for (var i = 0, ii = path.length; i < ii; i++) {
5406                p = path[i];
5407                if (p[0] == "M") {
5408                    x = +p[1];
5409                    y = +p[2];
5410                } else {
5411                    l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
5412                    if (len + l > length) {
5413                        if (subpath && !subpaths.start) {
5414                            point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
5415                            sp += [
5416                                "C" + O(point.start.x),
5417                                O(point.start.y),
5418                                O(point.m.x),
5419                                O(point.m.y),
5420                                O(point.x),
5421                                O(point.y)
5422                            ];
5423                            if (onlystart) {return sp;}
5424                            subpaths.start = sp;
5425                            sp = [
5426                                "M" + O(point.x),
5427                                O(point.y) + "C" + O(point.n.x),
5428                                O(point.n.y),
5429                                O(point.end.x),
5430                                O(point.end.y),
5431                                O(p[5]),
5432                                O(p[6])
5433                            ].join();
5434                            len += l;
5435                            x = +p[5];
5436                            y = +p[6];
5437                            continue;
5438                        }
5439                        if (!istotal && !subpath) {
5440                            point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
5441                            return point;
5442                        }
5443                    }
5444                    len += l;
5445                    x = +p[5];
5446                    y = +p[6];
5447                }
5448                sp += p.shift() + p;
5449            }
5450            subpaths.end = sp;
5451            point = istotal ? len : subpath ? subpaths : findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
5452            return point;
5453        }, null, Snap._.clone);
5454    }
5455    var getTotalLength = getLengthFactory(1),
5456        getPointAtLength = getLengthFactory(),
5457        getSubpathsAtLength = getLengthFactory(0, 1);
5458    function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
5459        var t1 = 1 - t,
5460            t13 = pow(t1, 3),
5461            t12 = pow(t1, 2),
5462            t2 = t * t,
5463            t3 = t2 * t,
5464            x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x,
5465            y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y,
5466            mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x),
5467            my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y),
5468            nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x),
5469            ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y),
5470            ax = t1 * p1x + t * c1x,
5471            ay = t1 * p1y + t * c1y,
5472            cx = t1 * c2x + t * p2x,
5473            cy = t1 * c2y + t * p2y,
5474            alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI);
5475        // (mx > nx || my < ny) && (alpha += 180);
5476        return {
5477            x: x,
5478            y: y,
5479            m: {x: mx, y: my},
5480            n: {x: nx, y: ny},
5481            start: {x: ax, y: ay},
5482            end: {x: cx, y: cy},
5483            alpha: alpha
5484        };
5485    }
5486    function bezierBBox(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
5487        if (!Snap.is(p1x, "array")) {
5488            p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y];
5489        }
5490        var bbox = curveDim.apply(null, p1x);
5491        return box(
5492            bbox.min.x,
5493            bbox.min.y,
5494            bbox.max.x - bbox.min.x,
5495            bbox.max.y - bbox.min.y
5496        );
5497    }
5498    function isPointInsideBBox(bbox, x, y) {
5499        return  x >= bbox.x &&
5500                x <= bbox.x + bbox.width &&
5501                y >= bbox.y &&
5502                y <= bbox.y + bbox.height;
5503    }
5504    function isBBoxIntersect(bbox1, bbox2) {
5505        bbox1 = box(bbox1);
5506        bbox2 = box(bbox2);
5507        return isPointInsideBBox(bbox2, bbox1.x, bbox1.y)
5508            || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y)
5509            || isPointInsideBBox(bbox2, bbox1.x, bbox1.y2)
5510            || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y2)
5511            || isPointInsideBBox(bbox1, bbox2.x, bbox2.y)
5512            || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y)
5513            || isPointInsideBBox(bbox1, bbox2.x, bbox2.y2)
5514            || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y2)
5515            || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x
5516                || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x)
5517            && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y
5518                || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y);
5519    }
5520    function base3(t, p1, p2, p3, p4) {
5521        var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4,
5522            t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
5523        return t * t2 - 3 * p1 + 3 * p2;
5524    }
5525    function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) {
5526        if (z == null) {
5527            z = 1;
5528        }
5529        z = z > 1 ? 1 : z < 0 ? 0 : z;
5530        var z2 = z / 2,
5531            n = 12,
5532            Tvalues = [-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],
5533            Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472],
5534            sum = 0;
5535        for (var i = 0; i < n; i++) {
5536            var ct = z2 * Tvalues[i] + z2,
5537                xbase = base3(ct, x1, x2, x3, x4),
5538                ybase = base3(ct, y1, y2, y3, y4),
5539                comb = xbase * xbase + ybase * ybase;
5540            sum += Cvalues[i] * math.sqrt(comb);
5541        }
5542        return z2 * sum;
5543    }
5544    function getTotLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) {
5545        if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) {
5546            return;
5547        }
5548        var t = 1,
5549            step = t / 2,
5550            t2 = t - step,
5551            l,
5552            e = .01;
5553        l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
5554        while (abs(l - ll) > e) {
5555            step /= 2;
5556            t2 += (l < ll ? 1 : -1) * step;
5557            l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
5558        }
5559        return t2;
5560    }
5561    function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {
5562        if (
5563            mmax(x1, x2) < mmin(x3, x4) ||
5564            mmin(x1, x2) > mmax(x3, x4) ||
5565            mmax(y1, y2) < mmin(y3, y4) ||
5566            mmin(y1, y2) > mmax(y3, y4)
5567        ) {
5568            return;
5569        }
5570        var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4),
5571            ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4),
5572            denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
5573
5574        if (!denominator) {
5575            return;
5576        }
5577        var px = nx / denominator,
5578            py = ny / denominator,
5579            px2 = +px.toFixed(2),
5580            py2 = +py.toFixed(2);
5581        if (
5582            px2 < +mmin(x1, x2).toFixed(2) ||
5583            px2 > +mmax(x1, x2).toFixed(2) ||
5584            px2 < +mmin(x3, x4).toFixed(2) ||
5585            px2 > +mmax(x3, x4).toFixed(2) ||
5586            py2 < +mmin(y1, y2).toFixed(2) ||
5587            py2 > +mmax(y1, y2).toFixed(2) ||
5588            py2 < +mmin(y3, y4).toFixed(2) ||
5589            py2 > +mmax(y3, y4).toFixed(2)
5590        ) {
5591            return;
5592        }
5593        return {x: px, y: py};
5594    }
5595    function inter(bez1, bez2) {
5596        return interHelper(bez1, bez2);
5597    }
5598    function interCount(bez1, bez2) {
5599        return interHelper(bez1, bez2, 1);
5600    }
5601    function interHelper(bez1, bez2, justCount) {
5602        var bbox1 = bezierBBox(bez1),
5603            bbox2 = bezierBBox(bez2);
5604        if (!isBBoxIntersect(bbox1, bbox2)) {
5605            return justCount ? 0 : [];
5606        }
5607        var l1 = bezlen.apply(0, bez1),
5608            l2 = bezlen.apply(0, bez2),
5609            n1 = ~~(l1 / 8),
5610            n2 = ~~(l2 / 8),
5611            dots1 = [],
5612            dots2 = [],
5613            xy = {},
5614            res = justCount ? 0 : [];
5615        for (var i = 0; i < n1 + 1; i++) {
5616            var p = findDotsAtSegment.apply(0, bez1.concat(i / n1));
5617            dots1.push({x: p.x, y: p.y, t: i / n1});
5618        }
5619        for (i = 0; i < n2 + 1; i++) {
5620            p = findDotsAtSegment.apply(0, bez2.concat(i / n2));
5621            dots2.push({x: p.x, y: p.y, t: i / n2});
5622        }
5623        for (i = 0; i < n1; i++) {
5624            for (var j = 0; j < n2; j++) {
5625                var di = dots1[i],
5626                    di1 = dots1[i + 1],
5627                    dj = dots2[j],
5628                    dj1 = dots2[j + 1],
5629                    ci = abs(di1.x - di.x) < .001 ? "y" : "x",
5630                    cj = abs(dj1.x - dj.x) < .001 ? "y" : "x",
5631                    is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y);
5632                if (is) {
5633                    if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) {
5634                        continue;
5635                    }
5636                    xy[is.x.toFixed(4)] = is.y.toFixed(4);
5637                    var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t),
5638                        t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t);
5639                    if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {
5640                        if (justCount) {
5641                            res++;
5642                        } else {
5643                            res.push({
5644                                x: is.x,
5645                                y: is.y,
5646                                t1: t1,
5647                                t2: t2
5648                            });
5649                        }
5650                    }
5651                }
5652            }
5653        }
5654        return res;
5655    }
5656    function pathIntersection(path1, path2) {
5657        return interPathHelper(path1, path2);
5658    }
5659    function pathIntersectionNumber(path1, path2) {
5660        return interPathHelper(path1, path2, 1);
5661    }
5662    function interPathHelper(path1, path2, justCount) {
5663        path1 = path2curve(path1);
5664        path2 = path2curve(path2);
5665        var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2,
5666            res = justCount ? 0 : [];
5667        for (var i = 0, ii = path1.length; i < ii; i++) {
5668            var pi = path1[i];
5669            if (pi[0] == "M") {
5670                x1 = x1m = pi[1];
5671                y1 = y1m = pi[2];
5672            } else {
5673                if (pi[0] == "C") {
5674                    bez1 = [x1, y1].concat(pi.slice(1));
5675                    x1 = bez1[6];
5676                    y1 = bez1[7];
5677                } else {
5678                    bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m];
5679                    x1 = x1m;
5680                    y1 = y1m;
5681                }
5682                for (var j = 0, jj = path2.length; j < jj; j++) {
5683                    var pj = path2[j];
5684                    if (pj[0] == "M") {
5685                        x2 = x2m = pj[1];
5686                        y2 = y2m = pj[2];
5687                    } else {
5688                        if (pj[0] == "C") {
5689                            bez2 = [x2, y2].concat(pj.slice(1));
5690                            x2 = bez2[6];
5691                            y2 = bez2[7];
5692                        } else {
5693                            bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m];
5694                            x2 = x2m;
5695                            y2 = y2m;
5696                        }
5697                        var intr = interHelper(bez1, bez2, justCount);
5698                        if (justCount) {
5699                            res += intr;
5700                        } else {
5701                            for (var k = 0, kk = intr.length; k < kk; k++) {
5702                                intr[k].segment1 = i;
5703                                intr[k].segment2 = j;
5704                                intr[k].bez1 = bez1;
5705                                intr[k].bez2 = bez2;
5706                            }
5707                            res = res.concat(intr);
5708                        }
5709                    }
5710                }
5711            }
5712        }
5713        return res;
5714    }
5715    function isPointInsidePath(path, x, y) {
5716        var bbox = pathBBox(path);
5717        return isPointInsideBBox(bbox, x, y) &&
5718               interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1;
5719    }
5720    function pathBBox(path) {
5721        var pth = paths(path);
5722        if (pth.bbox) {
5723            return clone(pth.bbox);
5724        }
5725        if (!path) {
5726            return box();
5727        }
5728        path = path2curve(path);
5729        var x = 0,
5730            y = 0,
5731            X = [],
5732            Y = [],
5733            p;
5734        for (var i = 0, ii = path.length; i < ii; i++) {
5735            p = path[i];
5736            if (p[0] == "M") {
5737                x = p[1];
5738                y = p[2];
5739                X.push(x);
5740                Y.push(y);
5741            } else {
5742                var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
5743                X = X.concat(dim.min.x, dim.max.x);
5744                Y = Y.concat(dim.min.y, dim.max.y);
5745                x = p[5];
5746                y = p[6];
5747            }
5748        }
5749        var xmin = mmin.apply(0, X),
5750            ymin = mmin.apply(0, Y),
5751            xmax = mmax.apply(0, X),
5752            ymax = mmax.apply(0, Y),
5753            bb = box(xmin, ymin, xmax - xmin, ymax - ymin);
5754        pth.bbox = clone(bb);
5755        return bb;
5756    }
5757    function rectPath(x, y, w, h, r) {
5758        if (r) {
5759            return [
5760                ["M", +x + (+r), y],
5761                ["l", w - r * 2, 0],
5762                ["a", r, r, 0, 0, 1, r, r],
5763                ["l", 0, h - r * 2],
5764                ["a", r, r, 0, 0, 1, -r, r],
5765                ["l", r * 2 - w, 0],
5766                ["a", r, r, 0, 0, 1, -r, -r],
5767                ["l", 0, r * 2 - h],
5768                ["a", r, r, 0, 0, 1, r, -r],
5769                ["z"]
5770            ];
5771        }
5772        var res = [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]];
5773        res.toString = toString;
5774        return res;
5775    }
5776    function ellipsePath(x, y, rx, ry, a) {
5777        if (a == null && ry == null) {
5778            ry = rx;
5779        }
5780        x = +x;
5781        y = +y;
5782        rx = +rx;
5783        ry = +ry;
5784        if (a != null) {
5785            var rad = Math.PI / 180,
5786                x1 = x + rx * Math.cos(-ry * rad),
5787                x2 = x + rx * Math.cos(-a * rad),
5788                y1 = y + rx * Math.sin(-ry * rad),
5789                y2 = y + rx * Math.sin(-a * rad),
5790                res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]];
5791        } else {
5792            res = [
5793                ["M", x, y],
5794                ["m", 0, -ry],
5795                ["a", rx, ry, 0, 1, 1, 0, 2 * ry],
5796                ["a", rx, ry, 0, 1, 1, 0, -2 * ry],
5797                ["z"]
5798            ];
5799        }
5800        res.toString = toString;
5801        return res;
5802    }
5803    var unit2px = Snap._unit2px,
5804        getPath = {
5805        path: function (el) {
5806            return el.attr("path");
5807        },
5808        circle: function (el) {
5809            var attr = unit2px(el);
5810            return ellipsePath(attr.cx, attr.cy, attr.r);
5811        },
5812        ellipse: function (el) {
5813            var attr = unit2px(el);
5814            return ellipsePath(attr.cx || 0, attr.cy || 0, attr.rx, attr.ry);
5815        },
5816        rect: function (el) {
5817            var attr = unit2px(el);
5818            return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height, attr.rx, attr.ry);
5819        },
5820        image: function (el) {
5821            var attr = unit2px(el);
5822            return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height);
5823        },
5824        line: function (el) {
5825            return "M" + [el.attr("x1") || 0, el.attr("y1") || 0, el.attr("x2"), el.attr("y2")];
5826        },
5827        polyline: function (el) {
5828            return "M" + el.attr("points");
5829        },
5830        polygon: function (el) {
5831            return "M" + el.attr("points") + "z";
5832        },
5833        deflt: function (el) {
5834            var bbox = el.node.getBBox();
5835            return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
5836        }
5837    };
5838    function pathToRelative(pathArray) {
5839        var pth = paths(pathArray),
5840            lowerCase = String.prototype.toLowerCase;
5841        if (pth.rel) {
5842            return pathClone(pth.rel);
5843        }
5844        if (!Snap.is(pathArray, "array") || !Snap.is(pathArray && pathArray[0], "array")) {
5845            pathArray = Snap.parsePathString(pathArray);
5846        }
5847        var res = [],
5848            x = 0,
5849            y = 0,
5850            mx = 0,
5851            my = 0,
5852            start = 0;
5853        if (pathArray[0][0] == "M") {
5854            x = pathArray[0][1];
5855            y = pathArray[0][2];
5856            mx = x;
5857            my = y;
5858            start++;
5859            res.push(["M", x, y]);
5860        }
5861        for (var i = start, ii = pathArray.length; i < ii; i++) {
5862            var r = res[i] = [],
5863                pa = pathArray[i];
5864            if (pa[0] != lowerCase.call(pa[0])) {
5865                r[0] = lowerCase.call(pa[0]);
5866                switch (r[0]) {
5867                    case "a":
5868                        r[1] = pa[1];
5869                        r[2] = pa[2];
5870                        r[3] = pa[3];
5871                        r[4] = pa[4];
5872                        r[5] = pa[5];
5873                        r[6] = +(pa[6] - x).toFixed(3);
5874                        r[7] = +(pa[7] - y).toFixed(3);
5875                        break;
5876                    case "v":
5877                        r[1] = +(pa[1] - y).toFixed(3);
5878                        break;
5879                    case "m":
5880                        mx = pa[1];
5881                        my = pa[2];
5882                    default:
5883                        for (var j = 1, jj = pa.length; j < jj; j++) {
5884                            r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
5885                        }
5886                }
5887            } else {
5888                r = res[i] = [];
5889                if (pa[0] == "m") {
5890                    mx = pa[1] + x;
5891                    my = pa[2] + y;
5892                }
5893                for (var k = 0, kk = pa.length; k < kk; k++) {
5894                    res[i][k] = pa[k];
5895                }
5896            }
5897            var len = res[i].length;
5898            switch (res[i][0]) {
5899                case "z":
5900                    x = mx;
5901                    y = my;
5902                    break;
5903                case "h":
5904                    x += +res[i][len - 1];
5905                    break;
5906                case "v":
5907                    y += +res[i][len - 1];
5908                    break;
5909                default:
5910                    x += +res[i][len - 2];
5911                    y += +res[i][len - 1];
5912            }
5913        }
5914        res.toString = toString;
5915        pth.rel = pathClone(res);
5916        return res;
5917    }
5918    function pathToAbsolute(pathArray) {
5919        var pth = paths(pathArray);
5920        if (pth.abs) {
5921            return pathClone(pth.abs);
5922        }
5923        if (!is(pathArray, "array") || !is(pathArray && pathArray[0], "array")) { // rough assumption
5924            pathArray = Snap.parsePathString(pathArray);
5925        }
5926        if (!pathArray || !pathArray.length) {
5927            return [["M", 0, 0]];
5928        }
5929        var res = [],
5930            x = 0,
5931            y = 0,
5932            mx = 0,
5933            my = 0,
5934            start = 0,
5935            pa0;
5936        if (pathArray[0][0] == "M") {
5937            x = +pathArray[0][1];
5938            y = +pathArray[0][2];
5939            mx = x;
5940            my = y;
5941            start++;
5942            res[0] = ["M", x, y];
5943        }
5944        var crz = pathArray.length == 3 &&
5945            pathArray[0][0] == "M" &&
5946            pathArray[1][0].toUpperCase() == "R" &&
5947            pathArray[2][0].toUpperCase() == "Z";
5948        for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) {
5949            res.push(r = []);
5950            pa = pathArray[i];
5951            pa0 = pa[0];
5952            if (pa0 != pa0.toUpperCase()) {
5953                r[0] = pa0.toUpperCase();
5954                switch (r[0]) {
5955                    case "A":
5956                        r[1] = pa[1];
5957                        r[2] = pa[2];
5958                        r[3] = pa[3];
5959                        r[4] = pa[4];
5960                        r[5] = pa[5];
5961                        r[6] = +pa[6] + x;
5962                        r[7] = +pa[7] + y;
5963                        break;
5964                    case "V":
5965                        r[1] = +pa[1] + y;
5966                        break;
5967                    case "H":
5968                        r[1] = +pa[1] + x;
5969                        break;
5970                    case "R":
5971                        var dots = [x, y].concat(pa.slice(1));
5972                        for (var j = 2, jj = dots.length; j < jj; j++) {
5973                            dots[j] = +dots[j] + x;
5974                            dots[++j] = +dots[j] + y;
5975                        }
5976                        res.pop();
5977                        res = res.concat(catmullRom2bezier(dots, crz));
5978                        break;
5979                    case "O":
5980                        res.pop();
5981                        dots = ellipsePath(x, y, pa[1], pa[2]);
5982                        dots.push(dots[0]);
5983                        res = res.concat(dots);
5984                        break;
5985                    case "U":
5986                        res.pop();
5987                        res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
5988                        r = ["U"].concat(res[res.length - 1].slice(-2));
5989                        break;
5990                    case "M":
5991                        mx = +pa[1] + x;
5992                        my = +pa[2] + y;
5993                    default:
5994                        for (j = 1, jj = pa.length; j < jj; j++) {
5995                            r[j] = +pa[j] + ((j % 2) ? x : y);
5996                        }
5997                }
5998            } else if (pa0 == "R") {
5999                dots = [x, y].concat(pa.slice(1));
6000                res.pop();
6001                res = res.concat(catmullRom2bezier(dots, crz));
6002                r = ["R"].concat(pa.slice(-2));
6003            } else if (pa0 == "O") {
6004                res.pop();
6005                dots = ellipsePath(x, y, pa[1], pa[2]);
6006                dots.push(dots[0]);
6007                res = res.concat(dots);
6008            } else if (pa0 == "U") {
6009                res.pop();
6010                res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
6011                r = ["U"].concat(res[res.length - 1].slice(-2));
6012            } else {
6013                for (var k = 0, kk = pa.length; k < kk; k++) {
6014                    r[k] = pa[k];
6015                }
6016            }
6017            pa0 = pa0.toUpperCase();
6018            if (pa0 != "O") {
6019                switch (r[0]) {
6020                    case "Z":
6021                        x = +mx;
6022                        y = +my;
6023                        break;
6024                    case "H":
6025                        x = r[1];
6026                        break;
6027                    case "V":
6028                        y = r[1];
6029                        break;
6030                    case "M":
6031                        mx = r[r.length - 2];
6032                        my = r[r.length - 1];
6033                    default:
6034                        x = r[r.length - 2];
6035                        y = r[r.length - 1];
6036                }
6037            }
6038        }
6039        res.toString = toString;
6040        pth.abs = pathClone(res);
6041        return res;
6042    }
6043    function l2c(x1, y1, x2, y2) {
6044        return [x1, y1, x2, y2, x2, y2];
6045    }
6046    function q2c(x1, y1, ax, ay, x2, y2) {
6047        var _13 = 1 / 3,
6048            _23 = 2 / 3;
6049        return [
6050                _13 * x1 + _23 * ax,
6051                _13 * y1 + _23 * ay,
6052                _13 * x2 + _23 * ax,
6053                _13 * y2 + _23 * ay,
6054                x2,
6055                y2
6056            ];
6057    }
6058    function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
6059        // for more information of where this math came from visit:
6060        // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
6061        var _120 = PI * 120 / 180,
6062            rad = PI / 180 * (+angle || 0),
6063            res = [],
6064            xy,
6065            rotate = Snap._.cacher(function (x, y, rad) {
6066                var X = x * math.cos(rad) - y * math.sin(rad),
6067                    Y = x * math.sin(rad) + y * math.cos(rad);
6068                return {x: X, y: Y};
6069            });
6070        if (!recursive) {
6071            xy = rotate(x1, y1, -rad);
6072            x1 = xy.x;
6073            y1 = xy.y;
6074            xy = rotate(x2, y2, -rad);
6075            x2 = xy.x;
6076            y2 = xy.y;
6077            var cos = math.cos(PI / 180 * angle),
6078                sin = math.sin(PI / 180 * angle),
6079                x = (x1 - x2) / 2,
6080                y = (y1 - y2) / 2;
6081            var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
6082            if (h > 1) {
6083                h = math.sqrt(h);
6084                rx = h * rx;
6085                ry = h * ry;
6086            }
6087            var rx2 = rx * rx,
6088                ry2 = ry * ry,
6089                k = (large_arc_flag == sweep_flag ? -1 : 1) *
6090                    math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
6091                cx = k * rx * y / ry + (x1 + x2) / 2,
6092                cy = k * -ry * x / rx + (y1 + y2) / 2,
6093                f1 = math.asin(((y1 - cy) / ry).toFixed(9)),
6094                f2 = math.asin(((y2 - cy) / ry).toFixed(9));
6095
6096            f1 = x1 < cx ? PI - f1 : f1;
6097            f2 = x2 < cx ? PI - f2 : f2;
6098            f1 < 0 && (f1 = PI * 2 + f1);
6099            f2 < 0 && (f2 = PI * 2 + f2);
6100            if (sweep_flag && f1 > f2) {
6101                f1 = f1 - PI * 2;
6102            }
6103            if (!sweep_flag && f2 > f1) {
6104                f2 = f2 - PI * 2;
6105            }
6106        } else {
6107            f1 = recursive[0];
6108            f2 = recursive[1];
6109            cx = recursive[2];
6110            cy = recursive[3];
6111        }
6112        var df = f2 - f1;
6113        if (abs(df) > _120) {
6114            var f2old = f2,
6115                x2old = x2,
6116                y2old = y2;
6117            f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
6118            x2 = cx + rx * math.cos(f2);
6119            y2 = cy + ry * math.sin(f2);
6120            res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
6121        }
6122        df = f2 - f1;
6123        var c1 = math.cos(f1),
6124            s1 = math.sin(f1),
6125            c2 = math.cos(f2),
6126            s2 = math.sin(f2),
6127            t = math.tan(df / 4),
6128            hx = 4 / 3 * rx * t,
6129            hy = 4 / 3 * ry * t,
6130            m1 = [x1, y1],
6131            m2 = [x1 + hx * s1, y1 - hy * c1],
6132            m3 = [x2 + hx * s2, y2 - hy * c2],
6133            m4 = [x2, y2];
6134        m2[0] = 2 * m1[0] - m2[0];
6135        m2[1] = 2 * m1[1] - m2[1];
6136        if (recursive) {
6137            return [m2, m3, m4].concat(res);
6138        } else {
6139            res = [m2, m3, m4].concat(res).join().split(",");
6140            var newres = [];
6141            for (var i = 0, ii = res.length; i < ii; i++) {
6142                newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
6143            }
6144            return newres;
6145        }
6146    }
6147    function findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
6148        var t1 = 1 - t;
6149        return {
6150            x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,
6151            y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
6152        };
6153    }
6154
6155    // Returns bounding box of cubic bezier curve.
6156    // Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
6157    // Original version: NISHIO Hirokazu
6158    // Modifications: https://github.com/timo22345
6159    function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) {
6160        var tvalues = [],
6161            bounds = [[], []],
6162            a, b, c, t, t1, t2, b2ac, sqrtb2ac;
6163        for (var i = 0; i < 2; ++i) {
6164            if (i == 0) {
6165                b = 6 * x0 - 12 * x1 + 6 * x2;
6166                a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
6167                c = 3 * x1 - 3 * x0;
6168            } else {
6169                b = 6 * y0 - 12 * y1 + 6 * y2;
6170                a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
6171                c = 3 * y1 - 3 * y0;
6172            }
6173            if (abs(a) < 1e-12) {
6174                if (abs(b) < 1e-12) {
6175                    continue;
6176                }
6177                t = -c / b;
6178                if (0 < t && t < 1) {
6179                    tvalues.push(t);
6180                }
6181                continue;
6182            }
6183            b2ac = b * b - 4 * c * a;
6184            sqrtb2ac = math.sqrt(b2ac);
6185            if (b2ac < 0) {
6186                continue;
6187            }
6188            t1 = (-b + sqrtb2ac) / (2 * a);
6189            if (0 < t1 && t1 < 1) {
6190                tvalues.push(t1);
6191            }
6192            t2 = (-b - sqrtb2ac) / (2 * a);
6193            if (0 < t2 && t2 < 1) {
6194                tvalues.push(t2);
6195            }
6196        }
6197
6198        var x, y, j = tvalues.length,
6199            jlen = j,
6200            mt;
6201        while (j--) {
6202            t = tvalues[j];
6203            mt = 1 - t;
6204            bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
6205            bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
6206        }
6207
6208        bounds[0][jlen] = x0;
6209        bounds[1][jlen] = y0;
6210        bounds[0][jlen + 1] = x3;
6211        bounds[1][jlen + 1] = y3;
6212        bounds[0].length = bounds[1].length = jlen + 2;
6213
6214
6215        return {
6216          min: {x: mmin.apply(0, bounds[0]), y: mmin.apply(0, bounds[1])},
6217          max: {x: mmax.apply(0, bounds[0]), y: mmax.apply(0, bounds[1])}
6218        };
6219    }
6220
6221    function path2curve(path, path2) {
6222        var pth = !path2 && paths(path);
6223        if (!path2 && pth.curve) {
6224            return pathClone(pth.curve);
6225        }
6226        var p = pathToAbsolute(path),
6227            p2 = path2 && pathToAbsolute(path2),
6228            attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
6229            attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
6230            processPath = function (path, d, pcom) {
6231                var nx, ny;
6232                if (!path) {
6233                    return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
6234                }
6235                !(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null);
6236                switch (path[0]) {
6237                    case "M":
6238                        d.X = path[1];
6239                        d.Y = path[2];
6240                        break;
6241                    case "A":
6242                        path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1))));
6243                        break;
6244                    case "S":
6245                        if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S.
6246                            nx = d.x * 2 - d.bx;          // And reflect the previous
6247                            ny = d.y * 2 - d.by;          // command's control point relative to the current point.
6248                        }
6249                        else {                            // or some else or nothing
6250                            nx = d.x;
6251                            ny = d.y;
6252                        }
6253                        path = ["C", nx, ny].concat(path.slice(1));
6254                        break;
6255                    case "T":
6256                        if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T.
6257                            d.qx = d.x * 2 - d.qx;        // And make a reflection similar
6258                            d.qy = d.y * 2 - d.qy;        // to case "S".
6259                        }
6260                        else {                            // or something else or nothing
6261                            d.qx = d.x;
6262                            d.qy = d.y;
6263                        }
6264                        path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
6265                        break;
6266                    case "Q":
6267                        d.qx = path[1];
6268                        d.qy = path[2];
6269                        path = ["C"].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
6270                        break;
6271                    case "L":
6272                        path = ["C"].concat(l2c(d.x, d.y, path[1], path[2]));
6273                        break;
6274                    case "H":
6275                        path = ["C"].concat(l2c(d.x, d.y, path[1], d.y));
6276                        break;
6277                    case "V":
6278                        path = ["C"].concat(l2c(d.x, d.y, d.x, path[1]));
6279                        break;
6280                    case "Z":
6281                        path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y));
6282                        break;
6283                }
6284                return path;
6285            },
6286            fixArc = function (pp, i) {
6287                if (pp[i].length > 7) {
6288                    pp[i].shift();
6289                    var pi = pp[i];
6290                    while (pi.length) {
6291                        pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved
6292                        p2 && (pcoms2[i] = "A"); // the same as above
6293                        pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
6294                    }
6295                    pp.splice(i, 1);
6296                    ii = mmax(p.length, p2 && p2.length || 0);
6297                }
6298            },
6299            fixM = function (path1, path2, a1, a2, i) {
6300                if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
6301                    path2.splice(i, 0, ["M", a2.x, a2.y]);
6302                    a1.bx = 0;
6303                    a1.by = 0;
6304                    a1.x = path1[i][1];
6305                    a1.y = path1[i][2];
6306                    ii = mmax(p.length, p2 && p2.length || 0);
6307                }
6308            },
6309            pcoms1 = [], // path commands of original path p
6310            pcoms2 = [], // path commands of original path p2
6311            pfirst = "", // temporary holder for original path command
6312            pcom = ""; // holder for previous path command of original path
6313        for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) {
6314            p[i] && (pfirst = p[i][0]); // save current path command
6315
6316            if (pfirst != "C") // C is not saved yet, because it may be result of conversion
6317            {
6318                pcoms1[i] = pfirst; // Save current path command
6319                i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom
6320            }
6321            p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath
6322
6323            if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command
6324            // which may produce multiple C:s
6325            // so we have to make sure that C is also C in original path
6326
6327            fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1
6328
6329            if (p2) { // the same procedures is done to p2
6330                p2[i] && (pfirst = p2[i][0]);
6331                if (pfirst != "C") {
6332                    pcoms2[i] = pfirst;
6333                    i && (pcom = pcoms2[i - 1]);
6334                }
6335                p2[i] = processPath(p2[i], attrs2, pcom);
6336
6337                if (pcoms2[i] != "A" && pfirst == "C") {
6338                    pcoms2[i] = "C";
6339                }
6340
6341                fixArc(p2, i);
6342            }
6343            fixM(p, p2, attrs, attrs2, i);
6344            fixM(p2, p, attrs2, attrs, i);
6345            var seg = p[i],
6346                seg2 = p2 && p2[i],
6347                seglen = seg.length,
6348                seg2len = p2 && seg2.length;
6349            attrs.x = seg[seglen - 2];
6350            attrs.y = seg[seglen - 1];
6351            attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;
6352            attrs.by = toFloat(seg[seglen - 3]) || attrs.y;
6353            attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x);
6354            attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y);
6355            attrs2.x = p2 && seg2[seg2len - 2];
6356            attrs2.y = p2 && seg2[seg2len - 1];
6357        }
6358        if (!p2) {
6359            pth.curve = pathClone(p);
6360        }
6361        return p2 ? [p, p2] : p;
6362    }
6363    function mapPath(path, matrix) {
6364        if (!matrix) {
6365            return path;
6366        }
6367        var x, y, i, j, ii, jj, pathi;
6368        path = path2curve(path);
6369        for (i = 0, ii = path.length; i < ii; i++) {
6370            pathi = path[i];
6371            for (j = 1, jj = pathi.length; j < jj; j += 2) {
6372                x = matrix.x(pathi[j], pathi[j + 1]);
6373                y = matrix.y(pathi[j], pathi[j + 1]);
6374                pathi[j] = x;
6375                pathi[j + 1] = y;
6376            }
6377        }
6378        return path;
6379    }
6380
6381    // http://schepers.cc/getting-to-the-point
6382    function catmullRom2bezier(crp, z) {
6383        var d = [];
6384        for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
6385            var p = [
6386                        {x: +crp[i - 2], y: +crp[i - 1]},
6387                        {x: +crp[i],     y: +crp[i + 1]},
6388                        {x: +crp[i + 2], y: +crp[i + 3]},
6389                        {x: +crp[i + 4], y: +crp[i + 5]}
6390                    ];
6391            if (z) {
6392                if (!i) {
6393                    p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};
6394                } else if (iLen - 4 == i) {
6395                    p[3] = {x: +crp[0], y: +crp[1]};
6396                } else if (iLen - 2 == i) {
6397                    p[2] = {x: +crp[0], y: +crp[1]};
6398                    p[3] = {x: +crp[2], y: +crp[3]};
6399                }
6400            } else {
6401                if (iLen - 4 == i) {
6402                    p[3] = p[2];
6403                } else if (!i) {
6404                    p[0] = {x: +crp[i], y: +crp[i + 1]};
6405                }
6406            }
6407            d.push(["C",
6408                  (-p[0].x + 6 * p[1].x + p[2].x) / 6,
6409                  (-p[0].y + 6 * p[1].y + p[2].y) / 6,
6410                  (p[1].x + 6 * p[2].x - p[3].x) / 6,
6411                  (p[1].y + 6*p[2].y - p[3].y) / 6,
6412                  p[2].x,
6413                  p[2].y
6414            ]);
6415        }
6416
6417        return d;
6418    }
6419
6420    // export
6421    Snap.path = paths;
6422
6423    /*\
6424     * Snap.path.getTotalLength
6425     [ method ]
6426     **
6427     * Returns the length of the given path in pixels
6428     **
6429     - path (string) SVG path string
6430     **
6431     = (number) length
6432    \*/
6433    Snap.path.getTotalLength = getTotalLength;
6434    /*\
6435     * Snap.path.getPointAtLength
6436     [ method ]
6437     **
6438     * Returns the coordinates of the point located at the given length along the given path
6439     **
6440     - path (string) SVG path string
6441     - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps
6442     **
6443     = (object) representation of the point:
6444     o {
6445     o     x: (number) x coordinate,
6446     o     y: (number) y coordinate,
6447     o     alpha: (number) angle of derivative
6448     o }
6449    \*/
6450    Snap.path.getPointAtLength = getPointAtLength;
6451    /*\
6452     * Snap.path.getSubpath
6453     [ method ]
6454     **
6455     * Returns the subpath of a given path between given start and end lengths
6456     **
6457     - path (string) SVG path string
6458     - from (number) length, in pixels, from the start of the path to the start of the segment
6459     - to (number) length, in pixels, from the start of the path to the end of the segment
6460     **
6461     = (string) path string definition for the segment
6462    \*/
6463    Snap.path.getSubpath = function (path, from, to) {
6464        if (this.getTotalLength(path) - to < 1e-6) {
6465            return getSubpathsAtLength(path, from).end;
6466        }
6467        var a = getSubpathsAtLength(path, to, 1);
6468        return from ? getSubpathsAtLength(a, from).end : a;
6469    };
6470    /*\
6471     * Element.getTotalLength
6472     [ method ]
6473     **
6474     * Returns the length of the path in pixels (only works for `path` elements)
6475     = (number) length
6476    \*/
6477    elproto.getTotalLength = function () {
6478        if (this.node.getTotalLength) {
6479            return this.node.getTotalLength();
6480        }
6481    };
6482    // SIERRA Element.getPointAtLength()/Element.getTotalLength(): If a <path> is broken into different segments, is the jump distance to the new coordinates set by the _M_ or _m_ commands calculated as part of the path's total length?
6483    /*\
6484     * Element.getPointAtLength
6485     [ method ]
6486     **
6487     * Returns coordinates of the point located at the given length on the given path (only works for `path` elements)
6488     **
6489     - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps
6490     **
6491     = (object) representation of the point:
6492     o {
6493     o     x: (number) x coordinate,
6494     o     y: (number) y coordinate,
6495     o     alpha: (number) angle of derivative
6496     o }
6497    \*/
6498    elproto.getPointAtLength = function (length) {
6499        return getPointAtLength(this.attr("d"), length);
6500    };
6501    // SIERRA Element.getSubpath(): Similar to the problem for Element.getPointAtLength(). Unclear how this would work for a segmented path. Overall, the concept of _subpath_ and what I'm calling a _segment_ (series of non-_M_ or _Z_ commands) is unclear.
6502    /*\
6503     * Element.getSubpath
6504     [ method ]
6505     **
6506     * Returns subpath of a given element from given start and end lengths (only works for `path` elements)
6507     **
6508     - from (number) length, in pixels, from the start of the path to the start of the segment
6509     - to (number) length, in pixels, from the start of the path to the end of the segment
6510     **
6511     = (string) path string definition for the segment
6512    \*/
6513    elproto.getSubpath = function (from, to) {
6514        return Snap.path.getSubpath(this.attr("d"), from, to);
6515    };
6516    Snap._.box = box;
6517    /*\
6518     * Snap.path.findDotsAtSegment
6519     [ method ]
6520     **
6521     * Utility method
6522     **
6523     * Finds dot coordinates on the given cubic beziér curve at the given t
6524     - p1x (number) x of the first point of the curve
6525     - p1y (number) y of the first point of the curve
6526     - c1x (number) x of the first anchor of the curve
6527     - c1y (number) y of the first anchor of the curve
6528     - c2x (number) x of the second anchor of the curve
6529     - c2y (number) y of the second anchor of the curve
6530     - p2x (number) x of the second point of the curve
6531     - p2y (number) y of the second point of the curve
6532     - t (number) position on the curve (0..1)
6533     = (object) point information in format:
6534     o {
6535     o     x: (number) x coordinate of the point,
6536     o     y: (number) y coordinate of the point,
6537     o     m: {
6538     o         x: (number) x coordinate of the left anchor,
6539     o         y: (number) y coordinate of the left anchor
6540     o     },
6541     o     n: {
6542     o         x: (number) x coordinate of the right anchor,
6543     o         y: (number) y coordinate of the right anchor
6544     o     },
6545     o     start: {
6546     o         x: (number) x coordinate of the start of the curve,
6547     o         y: (number) y coordinate of the start of the curve
6548     o     },
6549     o     end: {
6550     o         x: (number) x coordinate of the end of the curve,
6551     o         y: (number) y coordinate of the end of the curve
6552     o     },
6553     o     alpha: (number) angle of the curve derivative at the point
6554     o }
6555    \*/
6556    Snap.path.findDotsAtSegment = findDotsAtSegment;
6557    /*\
6558     * Snap.path.bezierBBox
6559     [ method ]
6560     **
6561     * Utility method
6562     **
6563     * Returns the bounding box of a given cubic beziér curve
6564     - p1x (number) x of the first point of the curve
6565     - p1y (number) y of the first point of the curve
6566     - c1x (number) x of the first anchor of the curve
6567     - c1y (number) y of the first anchor of the curve
6568     - c2x (number) x of the second anchor of the curve
6569     - c2y (number) y of the second anchor of the curve
6570     - p2x (number) x of the second point of the curve
6571     - p2y (number) y of the second point of the curve
6572     * or
6573     - bez (array) array of six points for beziér curve
6574     = (object) bounding box
6575     o {
6576     o     x: (number) x coordinate of the left top point of the box,
6577     o     y: (number) y coordinate of the left top point of the box,
6578     o     x2: (number) x coordinate of the right bottom point of the box,
6579     o     y2: (number) y coordinate of the right bottom point of the box,
6580     o     width: (number) width of the box,
6581     o     height: (number) height of the box
6582     o }
6583    \*/
6584    Snap.path.bezierBBox = bezierBBox;
6585    /*\
6586     * Snap.path.isPointInsideBBox
6587     [ method ]
6588     **
6589     * Utility method
6590     **
6591     * Returns `true` if given point is inside bounding box
6592     - bbox (string) bounding box
6593     - x (string) x coordinate of the point
6594     - y (string) y coordinate of the point
6595     = (boolean) `true` if point is inside
6596    \*/
6597    Snap.path.isPointInsideBBox = isPointInsideBBox;
6598    Snap.closest = function (x, y, X, Y) {
6599        var r = 100,
6600            b = box(x - r / 2, y - r / 2, r, r),
6601            inside = [],
6602            getter = X[0].hasOwnProperty("x") ? function (i) {
6603                return {
6604                    x: X[i].x,
6605                    y: X[i].y
6606                };
6607            } : function (i) {
6608                return {
6609                    x: X[i],
6610                    y: Y[i]
6611                };
6612            },
6613            found = 0;
6614        while (r <= 1e6 && !found) {
6615            for (var i = 0, ii = X.length; i < ii; i++) {
6616                var xy = getter(i);
6617                if (isPointInsideBBox(b, xy.x, xy.y)) {
6618                    found++;
6619                    inside.push(xy);
6620                    break;
6621                }
6622            }
6623            if (!found) {
6624                r *= 2;
6625                b = box(x - r / 2, y - r / 2, r, r)
6626            }
6627        }
6628        if (r == 1e6) {
6629            return;
6630        }
6631        var len = Infinity,
6632            res;
6633        for (i = 0, ii = inside.length; i < ii; i++) {
6634            var l = Snap.len(x, y, inside[i].x, inside[i].y);
6635            if (len > l) {
6636                len = l;
6637                inside[i].len = l;
6638                res = inside[i];
6639            }
6640        }
6641        return res;
6642    };
6643    /*\
6644     * Snap.path.isBBoxIntersect
6645     [ method ]
6646     **
6647     * Utility method
6648     **
6649     * Returns `true` if two bounding boxes intersect
6650     - bbox1 (string) first bounding box
6651     - bbox2 (string) second bounding box
6652     = (boolean) `true` if bounding boxes intersect
6653    \*/
6654    Snap.path.isBBoxIntersect = isBBoxIntersect;
6655    /*\
6656     * Snap.path.intersection
6657     [ method ]
6658     **
6659     * Utility method
6660     **
6661     * Finds intersections of two paths
6662     - path1 (string) path string
6663     - path2 (string) path string
6664     = (array) dots of intersection
6665     o [
6666     o     {
6667     o         x: (number) x coordinate of the point,
6668     o         y: (number) y coordinate of the point,
6669     o         t1: (number) t value for segment of path1,
6670     o         t2: (number) t value for segment of path2,
6671     o         segment1: (number) order number for segment of path1,
6672     o         segment2: (number) order number for segment of path2,
6673     o         bez1: (array) eight coordinates representing beziér curve for the segment of path1,
6674     o         bez2: (array) eight coordinates representing beziér curve for the segment of path2
6675     o     }
6676     o ]
6677    \*/
6678    Snap.path.intersection = pathIntersection;
6679    Snap.path.intersectionNumber = pathIntersectionNumber;
6680    /*\
6681     * Snap.path.isPointInside
6682     [ method ]
6683     **
6684     * Utility method
6685     **
6686     * Returns `true` if given point is inside a given closed path.
6687     *
6688     * Note: fill mode doesn’t affect the result of this method.
6689     - path (string) path string
6690     - x (number) x of the point
6691     - y (number) y of the point
6692     = (boolean) `true` if point is inside the path
6693    \*/
6694    Snap.path.isPointInside = isPointInsidePath;
6695    /*\
6696     * Snap.path.getBBox
6697     [ method ]
6698     **
6699     * Utility method
6700     **
6701     * Returns the bounding box of a given path
6702     - path (string) path string
6703     = (object) bounding box
6704     o {
6705     o     x: (number) x coordinate of the left top point of the box,
6706     o     y: (number) y coordinate of the left top point of the box,
6707     o     x2: (number) x coordinate of the right bottom point of the box,
6708     o     y2: (number) y coordinate of the right bottom point of the box,
6709     o     width: (number) width of the box,
6710     o     height: (number) height of the box
6711     o }
6712    \*/
6713    Snap.path.getBBox = pathBBox;
6714    Snap.path.get = getPath;
6715    /*\
6716     * Snap.path.toRelative
6717     [ method ]
6718     **
6719     * Utility method
6720     **
6721     * Converts path coordinates into relative values
6722     - path (string) path string
6723     = (array) path string
6724    \*/
6725    Snap.path.toRelative = pathToRelative;
6726    /*\
6727     * Snap.path.toAbsolute
6728     [ method ]
6729     **
6730     * Utility method
6731     **
6732     * Converts path coordinates into absolute values
6733     - path (string) path string
6734     = (array) path string
6735    \*/
6736    Snap.path.toAbsolute = pathToAbsolute;
6737    /*\
6738     * Snap.path.toCubic
6739     [ method ]
6740     **
6741     * Utility method
6742     **
6743     * Converts path to a new path where all segments are cubic beziér curves
6744     - pathString (string|array) path string or array of segments
6745     = (array) array of segments
6746    \*/
6747    Snap.path.toCubic = path2curve;
6748    /*\
6749     * Snap.path.map
6750     [ method ]
6751     **
6752     * Transform the path string with the given matrix
6753     - path (string) path string
6754     - matrix (object) see @Matrix
6755     = (string) transformed path string
6756    \*/
6757    Snap.path.map = mapPath;
6758    Snap.path.toString = toString;
6759    Snap.path.clone = pathClone;
6760});
6761
6762// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
6763//
6764// Licensed under the Apache License, Version 2.0 (the "License");
6765// you may not use this file except in compliance with the License.
6766// You may obtain a copy of the License at
6767//
6768// http://www.apache.org/licenses/LICENSE-2.0
6769//
6770// Unless required by applicable law or agreed to in writing, software
6771// distributed under the License is distributed on an "AS IS" BASIS,
6772// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6773// See the License for the specific language governing permissions and
6774// limitations under the License.
6775Snap.plugin(function (Snap, Element, Paper, glob) {
6776    var mmax = Math.max,
6777        mmin = Math.min;
6778
6779    // Set
6780    var Set = function (items) {
6781        this.items = [];
6782	this.bindings = {};
6783        this.length = 0;
6784        this.type = "set";
6785        if (items) {
6786            for (var i = 0, ii = items.length; i < ii; i++) {
6787                if (items[i]) {
6788                    this[this.items.length] = this.items[this.items.length] = items[i];
6789                    this.length++;
6790                }
6791            }
6792        }
6793    },
6794    setproto = Set.prototype;
6795    /*\
6796     * Set.push
6797     [ method ]
6798     **
6799     * Adds each argument to the current set
6800     = (object) original element
6801    \*/
6802    setproto.push = function () {
6803        var item,
6804            len;
6805        for (var i = 0, ii = arguments.length; i < ii; i++) {
6806            item = arguments[i];
6807            if (item) {
6808                len = this.items.length;
6809                this[len] = this.items[len] = item;
6810                this.length++;
6811            }
6812        }
6813        return this;
6814    };
6815    /*\
6816     * Set.pop
6817     [ method ]
6818     **
6819     * Removes last element and returns it
6820     = (object) element
6821    \*/
6822    setproto.pop = function () {
6823        this.length && delete this[this.length--];
6824        return this.items.pop();
6825    };
6826    /*\
6827     * Set.forEach
6828     [ method ]
6829     **
6830     * Executes given function for each element in the set
6831     *
6832     * If the function returns `false`, the loop stops running.
6833     **
6834     - callback (function) function to run
6835     - thisArg (object) context object for the callback
6836     = (object) Set object
6837    \*/
6838    setproto.forEach = function (callback, thisArg) {
6839        for (var i = 0, ii = this.items.length; i < ii; i++) {
6840            if (callback.call(thisArg, this.items[i], i) === false) {
6841                return this;
6842            }
6843        }
6844        return this;
6845    };
6846    /*\
6847     * Set.animate
6848     [ method ]
6849     **
6850     * Animates each element in set in sync.
6851     *
6852     **
6853     - attrs (object) key-value pairs of destination attributes
6854     - duration (number) duration of the animation in milliseconds
6855     - easing (function) #optional easing function from @mina or custom
6856     - callback (function) #optional callback function that executes when the animation ends
6857     * or
6858     - animation (array) array of animation parameter for each element in set in format `[attrs, duration, easing, callback]`
6859     > Usage
6860     | // animate all elements in set to radius 10
6861     | set.animate({r: 10}, 500, mina.easein);
6862     | // or
6863     | // animate first element to radius 10, but second to radius 20 and in different time
6864     | set.animate([{r: 10}, 500, mina.easein], [{r: 20}, 1500, mina.easein]);
6865     = (Element) the current element
6866    \*/
6867    setproto.animate = function (attrs, ms, easing, callback) {
6868        if (typeof easing == "function" && !easing.length) {
6869            callback = easing;
6870            easing = mina.linear;
6871        }
6872        if (attrs instanceof Snap._.Animation) {
6873            callback = attrs.callback;
6874            easing = attrs.easing;
6875            ms = easing.dur;
6876            attrs = attrs.attr;
6877        }
6878        var args = arguments;
6879        if (Snap.is(attrs, "array") && Snap.is(args[args.length - 1], "array")) {
6880            var each = true;
6881        }
6882        var begin,
6883            handler = function () {
6884                if (begin) {
6885                    this.b = begin;
6886                } else {
6887                    begin = this.b;
6888                }
6889            },
6890            cb = 0,
6891            set = this,
6892            callbacker = callback && function () {
6893                if (++cb == set.length) {
6894                    callback.call(this);
6895                }
6896            };
6897        return this.forEach(function (el, i) {
6898            eve.once("snap.animcreated." + el.id, handler);
6899            if (each) {
6900                args[i] && el.animate.apply(el, args[i]);
6901            } else {
6902                el.animate(attrs, ms, easing, callbacker);
6903            }
6904        });
6905    };
6906    setproto.remove = function () {
6907        while (this.length) {
6908            this.pop().remove();
6909        }
6910        return this;
6911    };
6912    /*\
6913     * Set.bind
6914     [ method ]
6915     **
6916     * Specifies how to handle a specific attribute when applied
6917     * to a set.
6918     *
6919     **
6920     - attr (string) attribute name
6921     - callback (function) function to run
6922     * or
6923     - attr (string) attribute name
6924     - element (Element) specific element in the set to apply the attribute to
6925     * or
6926     - attr (string) attribute name
6927     - element (Element) specific element in the set to apply the attribute to
6928     - eattr (string) attribute on the element to bind the attribute to
6929     = (object) Set object
6930    \*/
6931    setproto.bind = function (attr, a, b) {
6932        var data = {};
6933        if (typeof a == "function") {
6934            this.bindings[attr] = a;
6935        } else {
6936            var aname = b || attr;
6937            this.bindings[attr] = function (v) {
6938                data[aname] = v;
6939                a.attr(data);
6940            };
6941        }
6942        return this;
6943    };
6944    setproto.attr = function (value) {
6945        var unbound = {};
6946        for (var k in value) {
6947            if (this.bindings[k]) {
6948                this.bindings[k](value[k]);
6949            } else {
6950                unbound[k] = value[k];
6951            }
6952        }
6953        for (var i = 0, ii = this.items.length; i < ii; i++) {
6954            this.items[i].attr(unbound);
6955        }
6956        return this;
6957    };
6958    /*\
6959     * Set.clear
6960     [ method ]
6961     **
6962     * Removes all elements from the set
6963    \*/
6964    setproto.clear = function () {
6965        while (this.length) {
6966            this.pop();
6967        }
6968    };
6969    /*\
6970     * Set.splice
6971     [ method ]
6972     **
6973     * Removes range of elements from the set
6974     **
6975     - index (number) position of the deletion
6976     - count (number) number of element to remove
6977     - insertion… (object) #optional elements to insert
6978     = (object) set elements that were deleted
6979    \*/
6980    setproto.splice = function (index, count, insertion) {
6981        index = index < 0 ? mmax(this.length + index, 0) : index;
6982        count = mmax(0, mmin(this.length - index, count));
6983        var tail = [],
6984            todel = [],
6985            args = [],
6986            i;
6987        for (i = 2; i < arguments.length; i++) {
6988            args.push(arguments[i]);
6989        }
6990        for (i = 0; i < count; i++) {
6991            todel.push(this[index + i]);
6992        }
6993        for (; i < this.length - index; i++) {
6994            tail.push(this[index + i]);
6995        }
6996        var arglen = args.length;
6997        for (i = 0; i < arglen + tail.length; i++) {
6998            this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen];
6999        }
7000        i = this.items.length = this.length -= count - arglen;
7001        while (this[i]) {
7002            delete this[i++];
7003        }
7004        return new Set(todel);
7005    };
7006    /*\
7007     * Set.exclude
7008     [ method ]
7009     **
7010     * Removes given element from the set
7011     **
7012     - element (object) element to remove
7013     = (boolean) `true` if object was found and removed from the set
7014    \*/
7015    setproto.exclude = function (el) {
7016        for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) {
7017            this.splice(i, 1);
7018            return true;
7019        }
7020        return false;
7021    };
7022    setproto.insertAfter = function (el) {
7023        var i = this.items.length;
7024        while (i--) {
7025            this.items[i].insertAfter(el);
7026        }
7027        return this;
7028    };
7029    setproto.getBBox = function () {
7030        var x = [],
7031            y = [],
7032            x2 = [],
7033            y2 = [];
7034        for (var i = this.items.length; i--;) if (!this.items[i].removed) {
7035            var box = this.items[i].getBBox();
7036            x.push(box.x);
7037            y.push(box.y);
7038            x2.push(box.x + box.width);
7039            y2.push(box.y + box.height);
7040        }
7041        x = mmin.apply(0, x);
7042        y = mmin.apply(0, y);
7043        x2 = mmax.apply(0, x2);
7044        y2 = mmax.apply(0, y2);
7045        return {
7046            x: x,
7047            y: y,
7048            x2: x2,
7049            y2: y2,
7050            width: x2 - x,
7051            height: y2 - y,
7052            cx: x + (x2 - x) / 2,
7053            cy: y + (y2 - y) / 2
7054        };
7055    };
7056    setproto.clone = function (s) {
7057        s = new Set;
7058        for (var i = 0, ii = this.items.length; i < ii; i++) {
7059            s.push(this.items[i].clone());
7060        }
7061        return s;
7062    };
7063    setproto.toString = function () {
7064        return "Snap\u2018s set";
7065    };
7066    setproto.type = "set";
7067    // export
7068    Snap.Set = Set;
7069    Snap.set = function () {
7070        var set = new Set;
7071        if (arguments.length) {
7072            set.push.apply(set, Array.prototype.slice.call(arguments, 0));
7073        }
7074        return set;
7075    };
7076});
7077
7078// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
7079//
7080// Licensed under the Apache License, Version 2.0 (the "License");
7081// you may not use this file except in compliance with the License.
7082// You may obtain a copy of the License at
7083//
7084// http://www.apache.org/licenses/LICENSE-2.0
7085//
7086// Unless required by applicable law or agreed to in writing, software
7087// distributed under the License is distributed on an "AS IS" BASIS,
7088// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7089// See the License for the specific language governing permissions and
7090// limitations under the License.
7091Snap.plugin(function (Snap, Element, Paper, glob) {
7092    var names = {},
7093        reUnit = /[a-z]+$/i,
7094        Str = String;
7095    names.stroke = names.fill = "colour";
7096    function getEmpty(item) {
7097        var l = item[0];
7098        switch (l.toLowerCase()) {
7099            case "t": return [l, 0, 0];
7100            case "m": return [l, 1, 0, 0, 1, 0, 0];
7101            case "r": if (item.length == 4) {
7102                return [l, 0, item[2], item[3]];
7103            } else {
7104                return [l, 0];
7105            }
7106            case "s": if (item.length == 5) {
7107                return [l, 1, 1, item[3], item[4]];
7108            } else if (item.length == 3) {
7109                return [l, 1, 1];
7110            } else {
7111                return [l, 1];
7112            }
7113        }
7114    }
7115    function equaliseTransform(t1, t2, getBBox) {
7116        t2 = Str(t2).replace(/\.{3}|\u2026/g, t1);
7117        t1 = Snap.parseTransformString(t1) || [];
7118        t2 = Snap.parseTransformString(t2) || [];
7119        var maxlength = Math.max(t1.length, t2.length),
7120            from = [],
7121            to = [],
7122            i = 0, j, jj,
7123            tt1, tt2;
7124        for (; i < maxlength; i++) {
7125            tt1 = t1[i] || getEmpty(t2[i]);
7126            tt2 = t2[i] || getEmpty(tt1);
7127            if ((tt1[0] != tt2[0]) ||
7128                (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) ||
7129                (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4]))
7130                ) {
7131                    t1 = Snap._.transform2matrix(t1, getBBox());
7132                    t2 = Snap._.transform2matrix(t2, getBBox());
7133                    from = [["m", t1.a, t1.b, t1.c, t1.d, t1.e, t1.f]];
7134                    to = [["m", t2.a, t2.b, t2.c, t2.d, t2.e, t2.f]];
7135                    break;
7136            }
7137            from[i] = [];
7138            to[i] = [];
7139            for (j = 0, jj = Math.max(tt1.length, tt2.length); j < jj; j++) {
7140                j in tt1 && (from[i][j] = tt1[j]);
7141                j in tt2 && (to[i][j] = tt2[j]);
7142            }
7143        }
7144        return {
7145            from: path2array(from),
7146            to: path2array(to),
7147            f: getPath(from)
7148        };
7149    }
7150    function getNumber(val) {
7151        return val;
7152    }
7153    function getUnit(unit) {
7154        return function (val) {
7155            return +val.toFixed(3) + unit;
7156        };
7157    }
7158    function getViewBox(val) {
7159        return val.join(" ");
7160    }
7161    function getColour(clr) {
7162        return Snap.rgb(clr[0], clr[1], clr[2]);
7163    }
7164    function getPath(path) {
7165        var k = 0, i, ii, j, jj, out, a, b = [];
7166        for (i = 0, ii = path.length; i < ii; i++) {
7167            out = "[";
7168            a = ['"' + path[i][0] + '"'];
7169            for (j = 1, jj = path[i].length; j < jj; j++) {
7170                a[j] = "val[" + (k++) + "]";
7171            }
7172            out += a + "]";
7173            b[i] = out;
7174        }
7175        return Function("val", "return Snap.path.toString.call([" + b + "])");
7176    }
7177    function path2array(path) {
7178        var out = [];
7179        for (var i = 0, ii = path.length; i < ii; i++) {
7180            for (var j = 1, jj = path[i].length; j < jj; j++) {
7181                out.push(path[i][j]);
7182            }
7183        }
7184        return out;
7185    }
7186    function isNumeric(obj) {
7187        return isFinite(parseFloat(obj));
7188    }
7189    function arrayEqual(arr1, arr2) {
7190        if (!Snap.is(arr1, "array") || !Snap.is(arr2, "array")) {
7191            return false;
7192        }
7193        return arr1.toString() == arr2.toString();
7194    }
7195    Element.prototype.equal = function (name, b) {
7196        return eve("snap.util.equal", this, name, b).firstDefined();
7197    };
7198    eve.on("snap.util.equal", function (name, b) {
7199        var A, B, a = Str(this.attr(name) || ""),
7200            el = this;
7201        if (isNumeric(a) && isNumeric(b)) {
7202            return {
7203                from: parseFloat(a),
7204                to: parseFloat(b),
7205                f: getNumber
7206            };
7207        }
7208        if (names[name] == "colour") {
7209            A = Snap.color(a);
7210            B = Snap.color(b);
7211            return {
7212                from: [A.r, A.g, A.b, A.opacity],
7213                to: [B.r, B.g, B.b, B.opacity],
7214                f: getColour
7215            };
7216        }
7217        if (name == "viewBox") {
7218            A = this.attr(name).vb.split(" ").map(Number);
7219            B = b.split(" ").map(Number);
7220            return {
7221                from: A,
7222                to: B,
7223                f: getViewBox
7224            };
7225        }
7226        if (name == "transform" || name == "gradientTransform" || name == "patternTransform") {
7227            if (b instanceof Snap.Matrix) {
7228                b = b.toTransformString();
7229            }
7230            if (!Snap._.rgTransform.test(b)) {
7231                b = Snap._.svgTransform2string(b);
7232            }
7233            return equaliseTransform(a, b, function () {
7234                return el.getBBox(1);
7235            });
7236        }
7237        if (name == "d" || name == "path") {
7238            A = Snap.path.toCubic(a, b);
7239            return {
7240                from: path2array(A[0]),
7241                to: path2array(A[1]),
7242                f: getPath(A[0])
7243            };
7244        }
7245        if (name == "points") {
7246            A = Str(a).split(Snap._.separator);
7247            B = Str(b).split(Snap._.separator);
7248            return {
7249                from: A,
7250                to: B,
7251                f: function (val) { return val; }
7252            };
7253        }
7254        var aUnit = a.match(reUnit),
7255            bUnit = Str(b).match(reUnit);
7256        if (aUnit && arrayEqual(aUnit, bUnit)) {
7257            return {
7258                from: parseFloat(a),
7259                to: parseFloat(b),
7260                f: getUnit(aUnit)
7261            };
7262        } else {
7263            return {
7264                from: this.asPX(name),
7265                to: this.asPX(name, b),
7266                f: getNumber
7267            };
7268        }
7269    });
7270});
7271
7272// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
7273//
7274// Licensed under the Apache License, Version 2.0 (the "License");
7275// you may not use this file except in compliance with the License.
7276// You may obtain a copy of the License at
7277//
7278// http://www.apache.org/licenses/LICENSE-2.0
7279//
7280// Unless required by applicable law or agreed to in writing, software
7281// distributed under the License is distributed on an "AS IS" BASIS,
7282// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7283// See the License for the specific language governing permissions and
7284// limitations under the License.
7285Snap.plugin(function (Snap, Element, Paper, glob) {
7286    var elproto = Element.prototype,
7287    has = "hasOwnProperty",
7288    supportsTouch = "createTouch" in glob.doc,
7289    events = [
7290        "click", "dblclick", "mousedown", "mousemove", "mouseout",
7291        "mouseover", "mouseup", "touchstart", "touchmove", "touchend",
7292        "touchcancel"
7293    ],
7294    touchMap = {
7295        mousedown: "touchstart",
7296        mousemove: "touchmove",
7297        mouseup: "touchend"
7298    },
7299    getScroll = function (xy, el) {
7300        var name = xy == "y" ? "scrollTop" : "scrollLeft",
7301            doc = el && el.node ? el.node.ownerDocument : glob.doc;
7302        return doc[name in doc.documentElement ? "documentElement" : "body"][name];
7303    },
7304    preventDefault = function () {
7305        this.returnValue = false;
7306    },
7307    preventTouch = function () {
7308        return this.originalEvent.preventDefault();
7309    },
7310    stopPropagation = function () {
7311        this.cancelBubble = true;
7312    },
7313    stopTouch = function () {
7314        return this.originalEvent.stopPropagation();
7315    },
7316    addEvent = function (obj, type, fn, element) {
7317        var realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
7318            f = function (e) {
7319                var scrollY = getScroll("y", element),
7320                    scrollX = getScroll("x", element);
7321                if (supportsTouch && touchMap[has](type)) {
7322                    for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
7323                        if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) {
7324                            var olde = e;
7325                            e = e.targetTouches[i];
7326                            e.originalEvent = olde;
7327                            e.preventDefault = preventTouch;
7328                            e.stopPropagation = stopTouch;
7329                            break;
7330                        }
7331                    }
7332                }
7333                var x = e.clientX + scrollX,
7334                    y = e.clientY + scrollY;
7335                return fn.call(element, e, x, y);
7336            };
7337
7338        if (type !== realName) {
7339            obj.addEventListener(type, f, false);
7340        }
7341
7342        obj.addEventListener(realName, f, false);
7343
7344        return function () {
7345            if (type !== realName) {
7346                obj.removeEventListener(type, f, false);
7347            }
7348
7349            obj.removeEventListener(realName, f, false);
7350            return true;
7351        };
7352    },
7353    drag = [],
7354    dragMove = function (e) {
7355        var x = e.clientX,
7356            y = e.clientY,
7357            scrollY = getScroll("y"),
7358            scrollX = getScroll("x"),
7359            dragi,
7360            j = drag.length;
7361        while (j--) {
7362            dragi = drag[j];
7363            if (supportsTouch) {
7364                var i = e.touches && e.touches.length,
7365                    touch;
7366                while (i--) {
7367                    touch = e.touches[i];
7368                    if (touch.identifier == dragi.el._drag.id || dragi.el.node.contains(touch.target)) {
7369                        x = touch.clientX;
7370                        y = touch.clientY;
7371                        (e.originalEvent ? e.originalEvent : e).preventDefault();
7372                        break;
7373                    }
7374                }
7375            } else {
7376                e.preventDefault();
7377            }
7378            var node = dragi.el.node,
7379                o,
7380                next = node.nextSibling,
7381                parent = node.parentNode,
7382                display = node.style.display;
7383            // glob.win.opera && parent.removeChild(node);
7384            // node.style.display = "none";
7385            // o = dragi.el.paper.getElementByPoint(x, y);
7386            // node.style.display = display;
7387            // glob.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
7388            // o && eve("snap.drag.over." + dragi.el.id, dragi.el, o);
7389            x += scrollX;
7390            y += scrollY;
7391            eve("snap.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
7392        }
7393    },
7394    dragUp = function (e) {
7395        Snap.unmousemove(dragMove).unmouseup(dragUp);
7396        var i = drag.length,
7397            dragi;
7398        while (i--) {
7399            dragi = drag[i];
7400            dragi.el._drag = {};
7401            eve("snap.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
7402            eve.off("snap.drag.*." + dragi.el.id);
7403        }
7404        drag = [];
7405    };
7406    /*\
7407     * Element.click
7408     [ method ]
7409     **
7410     * Adds a click event handler to the element
7411     - handler (function) handler for the event
7412     = (object) @Element
7413    \*/
7414    /*\
7415     * Element.unclick
7416     [ method ]
7417     **
7418     * Removes a click event handler from the element
7419     - handler (function) handler for the event
7420     = (object) @Element
7421    \*/
7422
7423    /*\
7424     * Element.dblclick
7425     [ method ]
7426     **
7427     * Adds a double click event handler to the element
7428     - handler (function) handler for the event
7429     = (object) @Element
7430    \*/
7431    /*\
7432     * Element.undblclick
7433     [ method ]
7434     **
7435     * Removes a double click event handler from the element
7436     - handler (function) handler for the event
7437     = (object) @Element
7438    \*/
7439
7440    /*\
7441     * Element.mousedown
7442     [ method ]
7443     **
7444     * Adds a mousedown event handler to the element
7445     - handler (function) handler for the event
7446     = (object) @Element
7447    \*/
7448    /*\
7449     * Element.unmousedown
7450     [ method ]
7451     **
7452     * Removes a mousedown event handler from the element
7453     - handler (function) handler for the event
7454     = (object) @Element
7455    \*/
7456
7457    /*\
7458     * Element.mousemove
7459     [ method ]
7460     **
7461     * Adds a mousemove event handler to the element
7462     - handler (function) handler for the event
7463     = (object) @Element
7464    \*/
7465    /*\
7466     * Element.unmousemove
7467     [ method ]
7468     **
7469     * Removes a mousemove event handler from the element
7470     - handler (function) handler for the event
7471     = (object) @Element
7472    \*/
7473
7474    /*\
7475     * Element.mouseout
7476     [ method ]
7477     **
7478     * Adds a mouseout event handler to the element
7479     - handler (function) handler for the event
7480     = (object) @Element
7481    \*/
7482    /*\
7483     * Element.unmouseout
7484     [ method ]
7485     **
7486     * Removes a mouseout event handler from the element
7487     - handler (function) handler for the event
7488     = (object) @Element
7489    \*/
7490
7491    /*\
7492     * Element.mouseover
7493     [ method ]
7494     **
7495     * Adds a mouseover event handler to the element
7496     - handler (function) handler for the event
7497     = (object) @Element
7498    \*/
7499    /*\
7500     * Element.unmouseover
7501     [ method ]
7502     **
7503     * Removes a mouseover event handler from the element
7504     - handler (function) handler for the event
7505     = (object) @Element
7506    \*/
7507
7508    /*\
7509     * Element.mouseup
7510     [ method ]
7511     **
7512     * Adds a mouseup event handler to the element
7513     - handler (function) handler for the event
7514     = (object) @Element
7515    \*/
7516    /*\
7517     * Element.unmouseup
7518     [ method ]
7519     **
7520     * Removes a mouseup event handler from the element
7521     - handler (function) handler for the event
7522     = (object) @Element
7523    \*/
7524
7525    /*\
7526     * Element.touchstart
7527     [ method ]
7528     **
7529     * Adds a touchstart event handler to the element
7530     - handler (function) handler for the event
7531     = (object) @Element
7532    \*/
7533    /*\
7534     * Element.untouchstart
7535     [ method ]
7536     **
7537     * Removes a touchstart event handler from the element
7538     - handler (function) handler for the event
7539     = (object) @Element
7540    \*/
7541
7542    /*\
7543     * Element.touchmove
7544     [ method ]
7545     **
7546     * Adds a touchmove event handler to the element
7547     - handler (function) handler for the event
7548     = (object) @Element
7549    \*/
7550    /*\
7551     * Element.untouchmove
7552     [ method ]
7553     **
7554     * Removes a touchmove event handler from the element
7555     - handler (function) handler for the event
7556     = (object) @Element
7557    \*/
7558
7559    /*\
7560     * Element.touchend
7561     [ method ]
7562     **
7563     * Adds a touchend event handler to the element
7564     - handler (function) handler for the event
7565     = (object) @Element
7566    \*/
7567    /*\
7568     * Element.untouchend
7569     [ method ]
7570     **
7571     * Removes a touchend event handler from the element
7572     - handler (function) handler for the event
7573     = (object) @Element
7574    \*/
7575
7576    /*\
7577     * Element.touchcancel
7578     [ method ]
7579     **
7580     * Adds a touchcancel event handler to the element
7581     - handler (function) handler for the event
7582     = (object) @Element
7583    \*/
7584    /*\
7585     * Element.untouchcancel
7586     [ method ]
7587     **
7588     * Removes a touchcancel event handler from the element
7589     - handler (function) handler for the event
7590     = (object) @Element
7591    \*/
7592    for (var i = events.length; i--;) {
7593        (function (eventName) {
7594            Snap[eventName] = elproto[eventName] = function (fn, scope) {
7595                if (Snap.is(fn, "function")) {
7596                    this.events = this.events || [];
7597                    this.events.push({
7598                        name: eventName,
7599                        f: fn,
7600                        unbind: addEvent(this.node || document, eventName, fn, scope || this)
7601                    });
7602                } else {
7603                    for (var i = 0, ii = this.events.length; i < ii; i++) if (this.events[i].name == eventName) {
7604                        try {
7605                            this.events[i].f.call(this);
7606                        } catch (e) {}
7607                    }
7608                }
7609                return this;
7610            };
7611            Snap["un" + eventName] =
7612            elproto["un" + eventName] = function (fn) {
7613                var events = this.events || [],
7614                    l = events.length;
7615                while (l--) if (events[l].name == eventName &&
7616                               (events[l].f == fn || !fn)) {
7617                    events[l].unbind();
7618                    events.splice(l, 1);
7619                    !events.length && delete this.events;
7620                    return this;
7621                }
7622                return this;
7623            };
7624        })(events[i]);
7625    }
7626    /*\
7627     * Element.hover
7628     [ method ]
7629     **
7630     * Adds hover event handlers to the element
7631     - f_in (function) handler for hover in
7632     - f_out (function) handler for hover out
7633     - icontext (object) #optional context for hover in handler
7634     - ocontext (object) #optional context for hover out handler
7635     = (object) @Element
7636    \*/
7637    elproto.hover = function (f_in, f_out, scope_in, scope_out) {
7638        return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
7639    };
7640    /*\
7641     * Element.unhover
7642     [ method ]
7643     **
7644     * Removes hover event handlers from the element
7645     - f_in (function) handler for hover in
7646     - f_out (function) handler for hover out
7647     = (object) @Element
7648    \*/
7649    elproto.unhover = function (f_in, f_out) {
7650        return this.unmouseover(f_in).unmouseout(f_out);
7651    };
7652    var draggable = [];
7653    // SIERRA unclear what _context_ refers to for starting, ending, moving the drag gesture.
7654    // SIERRA Element.drag(): _x position of the mouse_: Where are the x/y values offset from?
7655    // SIERRA Element.drag(): much of this member's doc appears to be duplicated for some reason.
7656    // SIERRA Unclear about this sentence: _Additionally following drag events will be triggered: drag.start.<id> on start, drag.end.<id> on end and drag.move.<id> on every move._ Is there a global _drag_ object to which you can assign handlers keyed by an element's ID?
7657    /*\
7658     * Element.drag
7659     [ method ]
7660     **
7661     * Adds event handlers for an element's drag gesture
7662     **
7663     - onmove (function) handler for moving
7664     - onstart (function) handler for drag start
7665     - onend (function) handler for drag end
7666     - mcontext (object) #optional context for moving handler
7667     - scontext (object) #optional context for drag start handler
7668     - econtext (object) #optional context for drag end handler
7669     * Additionaly following `drag` events are triggered: `drag.start.<id>` on start,
7670     * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element is dragged over another element
7671     * `drag.over.<id>` fires as well.
7672     *
7673     * Start event and start handler are called in specified context or in context of the element with following parameters:
7674     o x (number) x position of the mouse
7675     o y (number) y position of the mouse
7676     o event (object) DOM event object
7677     * Move event and move handler are called in specified context or in context of the element with following parameters:
7678     o dx (number) shift by x from the start point
7679     o dy (number) shift by y from the start point
7680     o x (number) x position of the mouse
7681     o y (number) y position of the mouse
7682     o event (object) DOM event object
7683     * End event and end handler are called in specified context or in context of the element with following parameters:
7684     o event (object) DOM event object
7685     = (object) @Element
7686    \*/
7687    elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
7688        var el = this;
7689        if (!arguments.length) {
7690            var origTransform;
7691            return el.drag(function (dx, dy) {
7692                this.attr({
7693                    transform: origTransform + (origTransform ? "T" : "t") + [dx, dy]
7694                });
7695            }, function () {
7696                origTransform = this.transform().local;
7697            });
7698        }
7699        function start(e, x, y) {
7700            (e.originalEvent || e).preventDefault();
7701            el._drag.x = x;
7702            el._drag.y = y;
7703            el._drag.id = e.identifier;
7704            !drag.length && Snap.mousemove(dragMove).mouseup(dragUp);
7705            drag.push({el: el, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope});
7706            onstart && eve.on("snap.drag.start." + el.id, onstart);
7707            onmove && eve.on("snap.drag.move." + el.id, onmove);
7708            onend && eve.on("snap.drag.end." + el.id, onend);
7709            eve("snap.drag.start." + el.id, start_scope || move_scope || el, x, y, e);
7710        }
7711        function init(e, x, y) {
7712            eve("snap.draginit." + el.id, el, e, x, y);
7713        }
7714        eve.on("snap.draginit." + el.id, start);
7715        el._drag = {};
7716        draggable.push({el: el, start: start, init: init});
7717        el.mousedown(init);
7718        return el;
7719    };
7720    /*
7721     * Element.onDragOver
7722     [ method ]
7723     **
7724     * Shortcut to assign event handler for `drag.over.<id>` event, where `id` is the element's `id` (see @Element.id)
7725     - f (function) handler for event, first argument would be the element you are dragging over
7726    \*/
7727    // elproto.onDragOver = function (f) {
7728    //     f ? eve.on("snap.drag.over." + this.id, f) : eve.unbind("snap.drag.over." + this.id);
7729    // };
7730    /*\
7731     * Element.undrag
7732     [ method ]
7733     **
7734     * Removes all drag event handlers from the given element
7735    \*/
7736    elproto.undrag = function () {
7737        var i = draggable.length;
7738        while (i--) if (draggable[i].el == this) {
7739            this.unmousedown(draggable[i].init);
7740            draggable.splice(i, 1);
7741            eve.unbind("snap.drag.*." + this.id);
7742            eve.unbind("snap.draginit." + this.id);
7743        }
7744        !draggable.length && Snap.unmousemove(dragMove).unmouseup(dragUp);
7745        return this;
7746    };
7747});
7748
7749// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
7750//
7751// Licensed under the Apache License, Version 2.0 (the "License");
7752// you may not use this file except in compliance with the License.
7753// You may obtain a copy of the License at
7754//
7755// http://www.apache.org/licenses/LICENSE-2.0
7756//
7757// Unless required by applicable law or agreed to in writing, software
7758// distributed under the License is distributed on an "AS IS" BASIS,
7759// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7760// See the License for the specific language governing permissions and
7761// limitations under the License.
7762Snap.plugin(function (Snap, Element, Paper, glob) {
7763    var elproto = Element.prototype,
7764        pproto = Paper.prototype,
7765        rgurl = /^\s*url\((.+)\)/,
7766        Str = String,
7767        $ = Snap._.$;
7768    Snap.filter = {};
7769    /*\
7770     * Paper.filter
7771     [ method ]
7772     **
7773     * Creates a `<filter>` element
7774     **
7775     - filstr (string) SVG fragment of filter provided as a string
7776     = (object) @Element
7777     * Note: It is recommended to use filters embedded into the page inside an empty SVG element.
7778     > Usage
7779     | var f = paper.filter('<feGaussianBlur stdDeviation="2"/>'),
7780     |     c = paper.circle(10, 10, 10).attr({
7781     |         filter: f
7782     |     });
7783    \*/
7784    pproto.filter = function (filstr) {
7785        var paper = this;
7786        if (paper.type != "svg") {
7787            paper = paper.paper;
7788        }
7789        var f = Snap.parse(Str(filstr)),
7790            id = Snap._.id(),
7791            width = paper.node.offsetWidth,
7792            height = paper.node.offsetHeight,
7793            filter = $("filter");
7794        $(filter, {
7795            id: id,
7796            filterUnits: "userSpaceOnUse"
7797        });
7798        filter.appendChild(f.node);
7799        paper.defs.appendChild(filter);
7800        return new Element(filter);
7801    };
7802
7803    eve.on("snap.util.getattr.filter", function () {
7804        eve.stop();
7805        var p = $(this.node, "filter");
7806        if (p) {
7807            var match = Str(p).match(rgurl);
7808            return match && Snap.select(match[1]);
7809        }
7810    });
7811    eve.on("snap.util.attr.filter", function (value) {
7812        if (value instanceof Element && value.type == "filter") {
7813            eve.stop();
7814            var id = value.node.id;
7815            if (!id) {
7816                $(value.node, {id: value.id});
7817                id = value.id;
7818            }
7819            $(this.node, {
7820                filter: Snap.url(id)
7821            });
7822        }
7823        if (!value || value == "none") {
7824            eve.stop();
7825            this.node.removeAttribute("filter");
7826        }
7827    });
7828    /*\
7829     * Snap.filter.blur
7830     [ method ]
7831     **
7832     * Returns an SVG markup string for the blur filter
7833     **
7834     - x (number) amount of horizontal blur, in pixels
7835     - y (number) #optional amount of vertical blur, in pixels
7836     = (string) filter representation
7837     > Usage
7838     | var f = paper.filter(Snap.filter.blur(5, 10)),
7839     |     c = paper.circle(10, 10, 10).attr({
7840     |         filter: f
7841     |     });
7842    \*/
7843    Snap.filter.blur = function (x, y) {
7844        if (x == null) {
7845            x = 2;
7846        }
7847        var def = y == null ? x : [x, y];
7848        return Snap.format('\<feGaussianBlur stdDeviation="{def}"/>', {
7849            def: def
7850        });
7851    };
7852    Snap.filter.blur.toString = function () {
7853        return this();
7854    };
7855    /*\
7856     * Snap.filter.shadow
7857     [ method ]
7858     **
7859     * Returns an SVG markup string for the shadow filter
7860     **
7861     - dx (number) #optional horizontal shift of the shadow, in pixels
7862     - dy (number) #optional vertical shift of the shadow, in pixels
7863     - blur (number) #optional amount of blur
7864     - color (string) #optional color of the shadow
7865     - opacity (number) #optional `0..1` opacity of the shadow
7866     * or
7867     - dx (number) #optional horizontal shift of the shadow, in pixels
7868     - dy (number) #optional vertical shift of the shadow, in pixels
7869     - color (string) #optional color of the shadow
7870     - opacity (number) #optional `0..1` opacity of the shadow
7871     * which makes blur default to `4`. Or
7872     - dx (number) #optional horizontal shift of the shadow, in pixels
7873     - dy (number) #optional vertical shift of the shadow, in pixels
7874     - opacity (number) #optional `0..1` opacity of the shadow
7875     = (string) filter representation
7876     > Usage
7877     | var f = paper.filter(Snap.filter.shadow(0, 2, 3)),
7878     |     c = paper.circle(10, 10, 10).attr({
7879     |         filter: f
7880     |     });
7881    \*/
7882    Snap.filter.shadow = function (dx, dy, blur, color, opacity) {
7883        if (typeof blur == "string") {
7884            color = blur;
7885            opacity = color;
7886            blur = 4;
7887        }
7888        if (typeof color != "string") {
7889            opacity = color;
7890            color = "#000";
7891        }
7892        color = color || "#000";
7893        if (blur == null) {
7894            blur = 4;
7895        }
7896        if (opacity == null) {
7897            opacity = 1;
7898        }
7899        if (dx == null) {
7900            dx = 0;
7901            dy = 2;
7902        }
7903        if (dy == null) {
7904            dy = dx;
7905        }
7906        color = Snap.color(color);
7907        return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', {
7908            color: color,
7909            dx: dx,
7910            dy: dy,
7911            blur: blur,
7912            opacity: opacity
7913        });
7914    };
7915    Snap.filter.shadow.toString = function () {
7916        return this();
7917    };
7918    /*\
7919     * Snap.filter.grayscale
7920     [ method ]
7921     **
7922     * Returns an SVG markup string for the grayscale filter
7923     **
7924     - amount (number) amount of filter (`0..1`)
7925     = (string) filter representation
7926    \*/
7927    Snap.filter.grayscale = function (amount) {
7928        if (amount == null) {
7929            amount = 1;
7930        }
7931        return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>', {
7932            a: 0.2126 + 0.7874 * (1 - amount),
7933            b: 0.7152 - 0.7152 * (1 - amount),
7934            c: 0.0722 - 0.0722 * (1 - amount),
7935            d: 0.2126 - 0.2126 * (1 - amount),
7936            e: 0.7152 + 0.2848 * (1 - amount),
7937            f: 0.0722 - 0.0722 * (1 - amount),
7938            g: 0.2126 - 0.2126 * (1 - amount),
7939            h: 0.0722 + 0.9278 * (1 - amount)
7940        });
7941    };
7942    Snap.filter.grayscale.toString = function () {
7943        return this();
7944    };
7945    /*\
7946     * Snap.filter.sepia
7947     [ method ]
7948     **
7949     * Returns an SVG markup string for the sepia filter
7950     **
7951     - amount (number) amount of filter (`0..1`)
7952     = (string) filter representation
7953    \*/
7954    Snap.filter.sepia = function (amount) {
7955        if (amount == null) {
7956            amount = 1;
7957        }
7958        return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>', {
7959            a: 0.393 + 0.607 * (1 - amount),
7960            b: 0.769 - 0.769 * (1 - amount),
7961            c: 0.189 - 0.189 * (1 - amount),
7962            d: 0.349 - 0.349 * (1 - amount),
7963            e: 0.686 + 0.314 * (1 - amount),
7964            f: 0.168 - 0.168 * (1 - amount),
7965            g: 0.272 - 0.272 * (1 - amount),
7966            h: 0.534 - 0.534 * (1 - amount),
7967            i: 0.131 + 0.869 * (1 - amount)
7968        });
7969    };
7970    Snap.filter.sepia.toString = function () {
7971        return this();
7972    };
7973    /*\
7974     * Snap.filter.saturate
7975     [ method ]
7976     **
7977     * Returns an SVG markup string for the saturate filter
7978     **
7979     - amount (number) amount of filter (`0..1`)
7980     = (string) filter representation
7981    \*/
7982    Snap.filter.saturate = function (amount) {
7983        if (amount == null) {
7984            amount = 1;
7985        }
7986        return Snap.format('<feColorMatrix type="saturate" values="{amount}"/>', {
7987            amount: 1 - amount
7988        });
7989    };
7990    Snap.filter.saturate.toString = function () {
7991        return this();
7992    };
7993    /*\
7994     * Snap.filter.hueRotate
7995     [ method ]
7996     **
7997     * Returns an SVG markup string for the hue-rotate filter
7998     **
7999     - angle (number) angle of rotation
8000     = (string) filter representation
8001    \*/
8002    Snap.filter.hueRotate = function (angle) {
8003        angle = angle || 0;
8004        return Snap.format('<feColorMatrix type="hueRotate" values="{angle}"/>', {
8005            angle: angle
8006        });
8007    };
8008    Snap.filter.hueRotate.toString = function () {
8009        return this();
8010    };
8011    /*\
8012     * Snap.filter.invert
8013     [ method ]
8014     **
8015     * Returns an SVG markup string for the invert filter
8016     **
8017     - amount (number) amount of filter (`0..1`)
8018     = (string) filter representation
8019    \*/
8020    Snap.filter.invert = function (amount) {
8021        if (amount == null) {
8022            amount = 1;
8023        }
8024//        <feColorMatrix type="matrix" values="-1 0 0 0 1  0 -1 0 0 1  0 0 -1 0 1  0 0 0 1 0" color-interpolation-filters="sRGB"/>
8025        return Snap.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>', {
8026            amount: amount,
8027            amount2: 1 - amount
8028        });
8029    };
8030    Snap.filter.invert.toString = function () {
8031        return this();
8032    };
8033    /*\
8034     * Snap.filter.brightness
8035     [ method ]
8036     **
8037     * Returns an SVG markup string for the brightness filter
8038     **
8039     - amount (number) amount of filter (`0..1`)
8040     = (string) filter representation
8041    \*/
8042    Snap.filter.brightness = function (amount) {
8043        if (amount == null) {
8044            amount = 1;
8045        }
8046        return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>', {
8047            amount: amount
8048        });
8049    };
8050    Snap.filter.brightness.toString = function () {
8051        return this();
8052    };
8053    /*\
8054     * Snap.filter.contrast
8055     [ method ]
8056     **
8057     * Returns an SVG markup string for the contrast filter
8058     **
8059     - amount (number) amount of filter (`0..1`)
8060     = (string) filter representation
8061    \*/
8062    Snap.filter.contrast = function (amount) {
8063        if (amount == null) {
8064            amount = 1;
8065        }
8066        return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>', {
8067            amount: amount,
8068            amount2: .5 - amount / 2
8069        });
8070    };
8071    Snap.filter.contrast.toString = function () {
8072        return this();
8073    };
8074});
8075
8076// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
8077//
8078// Licensed under the Apache License, Version 2.0 (the "License");
8079// you may not use this file except in compliance with the License.
8080// You may obtain a copy of the License at
8081//
8082// http://www.apache.org/licenses/LICENSE-2.0
8083//
8084// Unless required by applicable law or agreed to in writing, software
8085// distributed under the License is distributed on an "AS IS" BASIS,
8086// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8087// See the License for the specific language governing permissions and
8088// limitations under the License.
8089Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
8090    var box = Snap._.box,
8091        is = Snap.is,
8092        firstLetter = /^[^a-z]*([tbmlrc])/i,
8093        toString = function () {
8094            return "T" + this.dx + "," + this.dy;
8095        };
8096    /*\
8097     * Element.getAlign
8098     [ method ]
8099     **
8100     * Returns shift needed to align the element relatively to given element.
8101     * If no elements specified, parent `<svg>` container will be used.
8102     - el (object) @optional alignment element
8103     - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"`
8104     = (object|string) Object in format `{dx: , dy: }` also has a string representation as a transformation string
8105     > Usage
8106     | el.transform(el.getAlign(el2, "top"));
8107     * or
8108     | var dy = el.getAlign(el2, "top").dy;
8109    \*/
8110    Element.prototype.getAlign = function (el, way) {
8111        if (way == null && is(el, "string")) {
8112            way = el;
8113            el = null;
8114        }
8115        el = el || this.paper;
8116        var bx = el.getBBox ? el.getBBox() : box(el),
8117            bb = this.getBBox(),
8118            out = {};
8119        way = way && way.match(firstLetter);
8120        way = way ? way[1].toLowerCase() : "c";
8121        switch (way) {
8122            case "t":
8123                out.dx = 0;
8124                out.dy = bx.y - bb.y;
8125            break;
8126            case "b":
8127                out.dx = 0;
8128                out.dy = bx.y2 - bb.y2;
8129            break;
8130            case "m":
8131                out.dx = 0;
8132                out.dy = bx.cy - bb.cy;
8133            break;
8134            case "l":
8135                out.dx = bx.x - bb.x;
8136                out.dy = 0;
8137            break;
8138            case "r":
8139                out.dx = bx.x2 - bb.x2;
8140                out.dy = 0;
8141            break;
8142            default:
8143                out.dx = bx.cx - bb.cx;
8144                out.dy = 0;
8145            break;
8146        }
8147        out.toString = toString;
8148        return out;
8149    };
8150    /*\
8151     * Element.align
8152     [ method ]
8153     **
8154     * Aligns the element relatively to given one via transformation.
8155     * If no elements specified, parent `<svg>` container will be used.
8156     - el (object) @optional alignment element
8157     - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"`
8158     = (object) this element
8159     > Usage
8160     | el.align(el2, "top");
8161     * or
8162     | el.align("middle");
8163    \*/
8164    Element.prototype.align = function (el, way) {
8165        return this.transform("..." + this.getAlign(el, way));
8166    };
8167});
8168
8169return Snap;
8170}));
8171