text: /* svg.js v0.36 - svg regex default color array number viewbox bbox rbox element parent container fx event defs group arrange mask clip gradient doc shape use rect ellipse line poly path image text textpath nested hyperlink sugar set memory loader - svgjs.com/license */
  ;(function() {
  
    this.SVG = function(element) {
      if (SVG.supported)
        return new SVG.Doc(element)
    }
    
    // Default namespaces
    SVG.ns = 'http://www.w3.org/2000/svg'
    SVG.xlink = 'http://www.w3.org/1999/xlink'
    
    // Element id sequence
    SVG.did  = 1000
    
    // Get next named element id
    SVG.eid = function(name) {
      return 'Svgjs' + name.charAt(0).toUpperCase() + name.slice(1) + (SVG.did++)
    }
    
    // Method for element creation
    SVG.create = function(name) {
      /* create element */
      var element = document.createElementNS(this.ns, name)
      
      /* apply unique id */
      element.setAttribute('id', this.eid(name))
      
      return element
    }
    
    // Method for extending objects
    SVG.extend = function() {
      var modules, methods, key, i
      
      /* get list of modules */
      modules = [].slice.call(arguments)
      
      /* get object with extensions */
      methods = modules.pop()
      
      for (i = modules.length - 1; i >= 0; i--)
        if (modules[i])
          for (key in methods)
            modules[i].prototype[key] = methods[key]
    
      /* make sure SVG.Set inherits any newly added methods */
      if (SVG.Set && SVG.Set.inherit)
        SVG.Set.inherit()
    }
    
    // Method for getting an eleemnt by id
    SVG.get = function(id) {
      var node = document.getElementById(id)
      if (node) return node.instance
    }
    
    // svg support test
    SVG.supported = (function() {
      return !! document.createElementNS &&
             !! document.createElementNS(SVG.ns,'svg').createSVGRect
    })()
    
    if (!SVG.supported) return false
  
    SVG.regex = {
      /* test a given value */
      test: function(value, test) {
        return this[test].test(value)
      }
      
      /* parse unit value */
    , unit:         /^(-?[\d\.]+)([a-z%]{0,2})$/
      
      /* parse hex value */
    , hex:          /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i
      
      /* parse rgb value */
    , rgb:          /rgb\((\d+),(\d+),(\d+)\)/
    
      /* test hex value */
    , isHex:        /^#[a-f0-9]{3,6}$/i
      
      /* test rgb value */
    , isRgb:        /^rgb\(/
      
      /* test css declaration */
    , isCss:        /[^:]+:[^;]+;?/
      
      /* test css property */
    , isStyle:      /^font|text|leading|cursor/
      
      /* test for blank string */
    , isBlank:      /^(\s+)?$/
      
      /* test for numeric string */
    , isNumber:     /^-?[\d\.]+$/
    
      /* test for percent value */
    , isPercent:    /^-?[\d\.]+%$/
      
    }
  
    SVG.defaults = {
      // Default matrix
      matrix:       '1 0 0 1 0 0'
      
      // Default attribute values
    , attrs: {
        /* fill and stroke */
        'fill-opacity':     1
      , 'stroke-opacity':   1
      , 'stroke-width':     0
      , 'stroke-linejoin':  'miter'
      , 'stroke-linecap':   'butt'
      , fill:               '#000000'
      , stroke:             '#000000'
      , opacity:            1
        /* position */
      , x:                  0
      , y:                  0
      , cx:                 0
      , cy:                 0
        /* size */  
      , width:              0
      , height:             0
        /* radius */  
      , r:                  0
      , rx:                 0
      , ry:                 0
        /* gradient */  
      , offset:             0
      , 'stop-opacity':     1
      , 'stop-color':       '#000000'
      }
      
      // Default transformation values
    , trans: function() {
        return {
          /* translate */
          x:        0
        , y:        0
          /* scale */
        , scaleX:   1
        , scaleY:   1
          /* rotate */
        , rotation: 0
          /* skew */
        , skewX:    0
        , skewY:    0
          /* matrix */
        , matrix:   this.matrix
        , a:        1
        , b:        0
        , c:        0
        , d:        1
        , e:        0
        , f:        0
        }
      }
      
    }
  
    SVG.Color = function(color) {
      var match
      
      /* initialize defaults */
      this.r = 0
      this.g = 0
      this.b = 0
      
      /* parse color */
      if (typeof color == 'string') {
        if (SVG.regex.isRgb.test(color)) {
          /* get rgb values */
          match = SVG.regex.rgb.exec(color.replace(/\s/g,''))
          
          /* parse numeric values */
          this.r = parseInt(match[1])
          this.g = parseInt(match[2])
          this.b = parseInt(match[3])
          
        } else if (SVG.regex.isHex.test(color)) {
          /* get hex values */
          match = SVG.regex.hex.exec(this._fullHex(color))
    
          /* parse numeric values */
          this.r = parseInt(match[1], 16)
          this.g = parseInt(match[2], 16)
          this.b = parseInt(match[3], 16)
    
        }
        
      } else if (typeof color == 'object') {
        this.r = color.r
        this.g = color.g
        this.b = color.b
        
      }
        
    }
    
    SVG.extend(SVG.Color, {
      // Default to hex conversion
      toString: function() {
        return this.toHex()
      }
      // Build hex value
    , toHex: function() {
        return '#'
          + this._compToHex(this.r)
          + this._compToHex(this.g)
          + this._compToHex(this.b)
      }
      // Build rgb value
    , toRgb: function() {
        return 'rgb(' + [this.r, this.g, this.b].join() + ')'
      }
      // Calculate true brightness
    , brightness: function() {
        return (this.r / 255 * 0.30)
             + (this.g / 255 * 0.59)
             + (this.b / 255 * 0.11)
      }
      // Private: ensure to six-based hex 
    , _fullHex: function(hex) {
        return hex.length == 4 ?
          [ '#',
            hex.substring(1, 2), hex.substring(1, 2)
          , hex.substring(2, 3), hex.substring(2, 3)
          , hex.substring(3, 4), hex.substring(3, 4)
          ].join('') : hex
      }
      // Private: component to hex value
    , _compToHex: function(comp) {
        var hex = comp.toString(16)
        return hex.length == 1 ? '0' + hex : hex
      }
      
    })
    
    // Test if given value is a color string
    SVG.Color.test = function(color) {
      color += ''
      return SVG.regex.isHex.test(color)
          || SVG.regex.isRgb.test(color)
    }
    
    // Test if given value is a rgb object
    SVG.Color.isRgb = function(color) {
      return color && typeof color.r == 'number'
    }
  
    SVG.Array = function(array, fallback) {
      array = (array || []).valueOf()
    
      /* if array is empty and fallback is provided, use fallback */
      if (array.length == 0 && fallback)
        array = fallback.valueOf()
    
      /* parse array */
      this.value = this.parse(array)
    }
    
    SVG.extend(SVG.Array, {
      // Make array morphable
      morph: function(array) {
        this.destination = this.parse(array)
    
        /* normalize length of arrays */
        if (this.value.length != this.destination.length) {
          var lastValue       = this.value[this.value.length - 1]
            , lastDestination = this.destination[this.destination.length - 1]
    
          while(this.value.length > this.destination.length)
            this.destination.push(lastDestination)
          while(this.value.length < this.destination.length)
            this.value.push(lastValue)
        }
    
        return this
      }
      // Clean up any duplicate points
    , settle: function() {
        var i, seen = []
    
        /* find all unique values */
        for (i = this.value.length - 1; i >= 0; i--)
          if (seen.indexOf(this.value[i]) == -1)
            seen.push(this.value[i])
    
        /* set new value */
        return this.value = seen
      }
      // Get morphed array at given position
    , at: function(pos) {
        /* make sure a destination is defined */
        if (!this.destination) return this
    
        /* generate morphed array */
        for (var i = 0, il = this.value.length, array = []; i < il; i++)
          array.push(this.value[i] + (this.destination[i] - this.value[i]) * pos)
    
        return new SVG.Array(array)
      }
      // Convert array to string
    , toString: function() {
        return this.value.join(' ')
      }
      // Real value
    , valueOf: function() {
        return this.value
      }
      // Parse whitespace separated string
    , parse: function(array) {
        array = array.valueOf()
    
        /* if already is an array, no need to parse it */
        if (Array.isArray(array)) return array
    
        return this.split(array)
      }
      // Strip unnecessary whitespace
    , split: function(string) {
        return string.replace(/\s+/g, ' ').replace(/^\s+|\s+$/g,'').split(' ') 
      }
    
    })
    
    // Poly points array
    SVG.PointArray = function() {
      this.constructor.apply(this, arguments)
    }
    
    // Inherit from SVG.Array
    SVG.PointArray.prototype = new SVG.Array
    
    SVG.extend(SVG.PointArray, {
      // Convert array to string
      toString: function() {
        /* convert to a poly point string */
        for (var i = 0, il = this.value.length, array = []; i < il; i++)
          array.push(this.value[i].join(','))
    
        return array.join(' ')
      }
      // Get morphed array at given position
    , at: function(pos) {
        /* make sure a destination is defined */
        if (!this.destination) return this
    
        /* generate morphed point string */
        for (var i = 0, il = this.value.length, array = []; i < il; i++)
          array.push([
            this.value[i][0] + (this.destination[i][0] - this.value[i][0]) * pos
          , this.value[i][1] + (this.destination[i][1] - this.value[i][1]) * pos
          ])
    
        return new SVG.PointArray(array)
      }
      // Parse point string
    , parse: function(array) {
        array = array.valueOf()
    
        /* if already is an array, no need to parse it */
        if (Array.isArray(array)) return array
    
        /* split points */
        array = this.split(array)
    
        /* parse points */
        for (var i = 0, il = array.length, p, points = []; i < il; i++) {
          p = array[i].split(',')
          points.push([parseFloat(p[0]), parseFloat(p[1])])
        }
    
        return points
      }
      // Move point string
    , move: function(x, y) {
        var box = this.bbox()
    
        /* get relative offset */
        x -= box.x
        y -= box.y
    
        /* move every point */
        if (!isNaN(x) && !isNaN(y))
          for (var i = this.value.length - 1; i >= 0; i--)
            this.value[i] = [this.value[i][0] + x, this.value[i][1] + y]
    
        return this
      }
      // Resize poly string
    , size: function(width, height) {
        var i, box = this.bbox()
    
        /* recalculate position of all points according to new size */
        for (i = this.value.length - 1; i >= 0; i--) {
          this.value[i][0] = ((this.value[i][0] - box.x) * width)  / box.width  + box.x
          this.value[i][1] = ((this.value[i][1] - box.y) * height) / box.height + box.x
        }
    
        return this
      }
      // Get bounding box of points
    , bbox: function() {
        if (this.value.length == 0)
          return { x: 0, y: 0, width: 0, height: 0 }
    
        var i
        , x = this.value[0][0]
        , y = this.value[0][1]
        , box = { x: x, y: y }
        
        /* find position */
        for (i = this.value.length - 1; i >= 0; i--) {
          if (this.value[i][0] < box.x)
            box.x = this.value[i][0]
          if (this.value[i][1] < box.y)
            box.y = this.value[i][1]
          if (this.value[i][0] > x)
            x = this.value[i][0]
          if (this.value[i][1] > y)
            y = this.value[i][1]
        }
    
        /* calculate size */
        box.width  = x - box.x
        box.height = y - box.y
    
        return box
      }
    
    })
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  
  
    SVG.Number = function(value) {
    
      /* initialize defaults */
      this.value = 0
      this.unit = ''
    
      /* parse value */
      switch(typeof value) {
        case 'number':
          /* ensure a valid numeric value */
          this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value
        break
        case 'string':
          var match = value.match(SVG.regex.unit)
    
          if (match) {
            /* make value numeric */
            this.value = parseFloat(match[1])
        
            /* normalize percent value */
            if (match[2] == '%')
              this.value /= 100
        
            /* store unit */
            this.unit = match[2]
          }
          
        break
        default:
          if (value instanceof SVG.Number) {
            this.value = value.value
            this.unit  = value.unit
          }
        break
      }
    }
    
    SVG.extend(SVG.Number, {
      // Stringalize
      toString: function() {
        return (this.unit == '%' ? ~~(this.value * 1e8) / 1e6 : this.value) + this.unit
      }
    , // Convert to primitive
      valueOf: function() {
        return this.value
      }
      // Convert to different unit
    , to: function(unit) {
        if (typeof unit === 'string')
          this.unit = unit
    
        return this
      }
      // Add number
    , plus: function(number) {
        this.value = this + new SVG.Number(number)
    
        return this
      }
      // Subtract number
    , minus: function(number) {
        return this.plus(-new SVG.Number(number))
      }
      // Multiply number
    , times: function(number) {
        this.value = this * new SVG.Number(number)
    
        return this
      }
      // Divide number
    , divide: function(number) {
        this.value = this / new SVG.Number(number)
    
        return this
      }
    
    })
  
    SVG.ViewBox = function(element) {
      var x, y, width, height
        , wm   = 1 /* width multiplier */
        , hm   = 1 /* height multiplier */
        , box  = element.bbox()
        , view = (element.attr('viewBox') || '').match(/-?[\d\.]+/g)
    
      /* get dimensions of current node */
      width  = new SVG.Number(element.width())
      height = new SVG.Number(element.height())
    
      /* find nearest non-percentual dimensions */
      while (width.unit == '%') {
        wm *= width.value
        width = new SVG.Number(element instanceof SVG.Doc ? element.parent.offsetWidth : element.width())
      }
      while (height.unit == '%') {
        hm *= height.value
        height = new SVG.Number(element instanceof SVG.Doc ? element.parent.offsetHeight : element.height())
      }
      
      /* ensure defaults */
      this.x      = box.x
      this.y      = box.y
      this.width  = width  * wm
      this.height = height * hm
      this.zoom   = 1
      
      if (view) {
        /* get width and height from viewbox */
        x      = parseFloat(view[0])
        y      = parseFloat(view[1])
        width  = parseFloat(view[2])
        height = parseFloat(view[3])
        
        /* calculate zoom accoring to viewbox */
        this.zoom = ((this.width / this.height) > (width / height)) ?
          this.height / height :
          this.width  / width
    
        /* calculate real pixel dimensions on parent SVG.Doc element */
        this.x      = x
        this.y      = y
        this.width  = width
        this.height = height
        
      }
      
    }
    
    //
    SVG.extend(SVG.ViewBox, {
      // Parse viewbox to string
      toString: function() {
        return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height
      }
      
    })
  
    SVG.BBox = function(element) {
      var box
    
      /* initialize zero box */
      this.x      = 0
      this.y      = 0
      this.width  = 0
      this.height = 0
      
      /* get values if element is given */
      if (element) {
        try {
          /* actual, native bounding box */
          box = element.node.getBBox()
        } catch(e) {
          /* fallback for some browsers */
          box = {
            x:      element.node.clientLeft
          , y:      element.node.clientTop
          , width:  element.node.clientWidth
          , height: element.node.clientHeight
          }
        }
        
        /* include translations on x an y */
        this.x = box.x + element.trans.x
        this.y = box.y + element.trans.y
        
        /* plain width and height */
        this.width  = box.width  * element.trans.scaleX
        this.height = box.height * element.trans.scaleY
      }
      
      /* add the center */
      this.cx = this.x + this.width / 2
      this.cy = this.y + this.height / 2
      
    }
    
    //
    SVG.extend(SVG.BBox, {
      // merge bounding box with another, return a new instance
      merge: function(box) {
        var b = new SVG.BBox()
    
        /* merge box */
        b.x      = Math.min(this.x, box.x)
        b.y      = Math.min(this.y, box.y)
        b.width  = Math.max(this.x + this.width,  box.x + box.width)  - b.x
        b.height = Math.max(this.y + this.height, box.y + box.height) - b.y
    
        /* add the center */
        b.cx = b.x + b.width / 2
        b.cy = b.y + b.height / 2
    
        return b
      }
    
    })
  
    SVG.RBox = function(element) {
      var e, zoom
        , box = {}
    
      /* initialize zero box */
      this.x      = 0
      this.y      = 0
      this.width  = 0
      this.height = 0
      
      if (element) {
        e = element.doc().parent
        zoom = element.doc().viewbox().zoom
        
        /* actual, native bounding box */
        box = element.node.getBoundingClientRect()
        
        /* get screen offset */
        this.x = box.left
        this.y = box.top
        
        /* subtract parent offset */
        this.x -= e.offsetLeft
        this.y -= e.offsetTop
        
        while (e = e.offsetParent) {
          this.x -= e.offsetLeft
          this.y -= e.offsetTop
        }
        
        /* calculate cumulative zoom from svg documents */
        e = element
        while (e = e.parent) {
          if (e.type == 'svg' && e.viewbox) {
            zoom *= e.viewbox().zoom
            this.x -= e.x() || 0
            this.y -= e.y() || 0
          }
        }
      }
      
      /* recalculate viewbox distortion */
      this.x /= zoom
      this.y /= zoom
      this.width  = box.width  /= zoom
      this.height = box.height /= zoom
      
      /* add the center */
      this.cx = this.x + this.width  / 2
      this.cy = this.y + this.height / 2
      
    }
    
    //
    SVG.extend(SVG.RBox, {
      // merge rect box with another, return a new instance
      merge: function(box) {
        var b = new SVG.RBox()
    
        /* merge box */
        b.x      = Math.min(this.x, box.x)
        b.y      = Math.min(this.y, box.y)
        b.width  = Math.max(this.x + this.width,  box.x + box.width)  - b.x
        b.height = Math.max(this.y + this.height, box.y + box.height) - b.y
    
        /* add the center */
        b.cx = b.x + b.width / 2
        b.cy = b.y + b.height / 2
    
        return b
      }
    
    })
  
    SVG.Element = function(node) {
      /* make stroke value accessible dynamically */
      this._stroke = SVG.defaults.attrs.stroke
      
      /* initialize style store */
      this.styles = {}
      
      /* initialize transformation store with defaults */
      this.trans = SVG.defaults.trans()
      
      /* keep reference to the element node */
      if (this.node = node) {
        this.type = node.nodeName
        this.node.instance = this
      }
    }
    
    //
    SVG.extend(SVG.Element, {
      // Move over x-axis
      x: function(x) {
        if (x) {
          x = new SVG.Number(x)
          x.value /= this.trans.scaleX
        }
        return this.attr('x', x)
      }
      // Move over y-axis
    , y: function(y) {
        if (y) {
          y = new SVG.Number(y)
          y.value /= this.trans.scaleY
        }
        return this.attr('y', y)
      }
      // Move by center over x-axis
    , cx: function(x) {
        return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2)
      }
      // Move by center over y-axis
    , cy: function(y) {
        return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2)
      }
      // Move element to given x and y values
    , move: function(x, y) {
        return this.x(x).y(y)
      }
      // Move element by its center
    , center: function(x, y) {
        return this.cx(x).cy(y)
      }
      // Set width of element
    , width: function(width) {
        return this.attr('width', width)
      }
      // Set height of element
    , height: function(height) {
        return this.attr('height', height)
      }
      // Set element size to given width and height
    , size: function(width, height) {
        return this.attr({
          width:  new SVG.Number(width)
        , height: new SVG.Number(height)
        })
      }
      // Clone element
    , clone: function() {
        var clone , attr
          , type = this.type
        
        /* invoke shape method with shape-specific arguments */
        clone = type == 'rect' || type == 'ellipse' ?
          this.parent[type](0,0) :
        type == 'line' ?
          this.parent[type](0,0,0,0) :
        type == 'image' ?
          this.parent[type](this.src) :
        type == 'text' ?
          this.parent[type](this.content) :
        type == 'path' ?
          this.parent[type](this.attr('d')) :
        type == 'polyline' || type == 'polygon' ?
          this.parent[type](this.attr('points')) :
        type == 'g' ?
          this.parent.group() :
          this.parent[type]()
        
        /* apply attributes attributes */
        attr = this.attr()
        delete attr.id
        clone.attr(attr)
        
        /* copy transformations */
        clone.trans = this.trans
        
        /* apply attributes and translations */
        return clone.transform({})
      }
      // Remove element
    , remove: function() {
        if (this.parent)
          this.parent.removeElement(this)
        
        return this
      }
      // Replace element
    , replace: function(element) {
        this.after(element).remove()
    
        return element
      }
      // Add element to given container and return self
    , addTo: function(parent) {
        return parent.put(this)
      }
      // Add element to given container and return container
    , putIn: function(parent) {
        return parent.add(this)
      }
      // Get parent document
    , doc: function(type) {
        return this._parent(type || SVG.Doc)
      }
      // Set svg element attribute
    , attr: function(a, v, n) {
        if (a == null) {
          /* get an object of attributes */
          a = {}
          v = this.node.attributes
          for (n = v.length - 1; n >= 0; n--)
            a[v[n].nodeName] = SVG.regex.test(v[n].nodeValue, 'isNumber') ? parseFloat(v[n].nodeValue) : v[n].nodeValue
          
          return a
          
        } else if (typeof a == 'object') {
          /* apply every attribute individually if an object is passed */
          for (v in a) this.attr(v, a[v])
          
        } else if (v === null) {
            /* remove value */
            this.node.removeAttribute(a)
          
        } else if (v == null) {
          /* act as a getter for style attributes */
          if (this._isStyle(a)) {
            return a == 'text' ?
                     this.content :
                   a == 'leading' && this.leading ?
                     this.leading() :
                     this.style(a)
          
          /* act as a getter if the first and only argument is not an object */
          } else {
            v = this.node.getAttribute(a)
            return v == null ? 
              SVG.defaults.attrs[a] :
            SVG.regex.test(v, 'isNumber') ?
              parseFloat(v) : v
          }
        
        } else if (a == 'style') {
          /* redirect to the style method */
          return this.style(v)
        
        } else {
          /* treat x differently on text elements */
          if (a == 'x' && Array.isArray(this.lines))
            for (n = this.lines.length - 1; n >= 0; n--)
              this.lines[n].attr(a, v)
          
          /* BUG FIX: some browsers will render a stroke if a color is given even though stroke width is 0 */
          if (a == 'stroke-width')
            this.attr('stroke', parseFloat(v) > 0 ? this._stroke : null)
          else if (a == 'stroke')
            this._stroke = v
          
          /* ensure full hex color */
          if (SVG.Color.test(v) || SVG.Color.isRgb(v))
            v = new SVG.Color(v)
    
          /* ensure correct numeric values */
          else if (typeof v === 'number')
            v = new SVG.Number(v)
    
          /* parse array values */
          else if (Array.isArray(v))
            v = new SVG.Array(v)
    
          /* set give attribute on node */
          n != null ?
            this.node.setAttributeNS(n, a, v.toString()) :
            this.node.setAttribute(a, v.toString())
          
          /* if the passed argument belongs in the style as well, add it there */
          if (this._isStyle(a)) {
            a == 'text' ?
              this.text(v) :
            a == 'leading' && this.leading ?
              this.leading(v) :
              this.style(a, v)
            
            /* rebuild if required */
            if (this.rebuild)
              this.rebuild(a, v)
          }
        }
        
        return this
      }
      // Manage transformations
    , transform: function(o, v) {
        
        if (arguments.length == 0) {
          /* act as a getter if no argument is given */
          return this.trans
          
        } else if (typeof o === 'string') {
          /* act as a getter if only one string argument is given */
          if (arguments.length < 2)
            return this.trans[o]
          
          /* apply transformations as object if key value arguments are given*/
          var transform = {}
          transform[o] = v
          
          return this.transform(transform)
        }
        
        /* ... otherwise continue as a setter */
        var transform = []
        
        /* parse matrix */
        o = this._parseMatrix(o)
        
        /* merge values */
        for (v in o)
          if (o[v] != null)
            this.trans[v] = o[v]
        
        /* compile matrix */
        this.trans.matrix = this.trans.a
                    + ' ' + this.trans.b
                    + ' ' + this.trans.c
                    + ' ' + this.trans.d
                    + ' ' + this.trans.e
                    + ' ' + this.trans.f
        
        /* alias current transformations */
        o = this.trans
        
        /* add matrix */
        if (o.matrix != SVG.defaults.matrix)
          transform.push('matrix(' + o.matrix + ')')
        
        /* add rotation */
        if (o.rotation != 0)
          transform.push('rotate(' + o.rotation + ' ' + (o.cx == null ? this.bbox().cx : o.cx) + ' ' + (o.cy == null ? this.bbox().cy : o.cy) + ')')
        
        /* add scale */
        if (o.scaleX != 1 || o.scaleY != 1)
          transform.push('scale(' + o.scaleX + ' ' + o.scaleY + ')')
        
        /* add skew on x axis */
        if (o.skewX != 0)
          transform.push('skewX(' + o.skewX + ')')
        
        /* add skew on y axis */
        if (o.skewY != 0)
          transform.push('skewY(' + o.skewY + ')')
        
        /* add translation */
        if (o.x != 0 || o.y != 0)
          transform.push('translate(' + new SVG.Number(o.x / o.scaleX) + ' ' + new SVG.Number(o.y / o.scaleY) + ')')
        
        /* add offset translation */
         if (this._offset && this._offset.x != 0 && this._offset.y != 0)
           transform.push('translate(' + (-this._offset.x) + ' ' + (-this._offset.y) + ')')
        
        /* update transformations, even if there are none */
        if (transform.length == 0)
          this.node.removeAttribute('transform')
        else
          this.node.setAttribute('transform', transform.join(' '))
        
        return this
      }
      // Dynamic style generator
    , style: function(s, v) {
        if (arguments.length == 0) {
          /* get full style */
          return this.attr('style') || ''
        
        } else if (arguments.length < 2) {
          /* apply every style individually if an object is passed */
          if (typeof s == 'object') {
            for (v in s) this.style(v, s[v])
          
          } else if (SVG.regex.isCss.test(s)) {
            /* parse css string */
            s = s.split(';')
    
            /* apply every definition individually */
            for (var i = 0; i < s.length; i++) {
              v = s[i].split(':')
    
              if (v.length == 2)
                this.style(v[0].replace(/\s+/g, ''), v[1].replace(/^\s+/,'').replace(/\s+$/,''))
            }
          } else {
            /* act as a getter if the first and only argument is not an object */
            return this.styles[s]
          }
        
        } else if (v === null || SVG.regex.test(v, 'isBlank')) {
          /* remove value */
          delete this.styles[s]
          
        } else {
          /* store value */
          this.styles[s] = v
        }
        
        /* rebuild style string */
        s = ''
        for (v in this.styles)
          s += v + ':' + this.styles[v] + ';'
        
        /* apply style */
        if (s == '')
          this.node.removeAttribute('style')
        else
          this.node.setAttribute('style', s)
        
        return this
      }
      // Store data values on svg nodes
    , data: function(a, v, r) {
        if (arguments.length < 2) {
          try {
            return JSON.parse(this.attr('data-' + a))
          } catch(e) {
            return this.attr('data-' + a)
          }
          
        } else {
          this.attr(
            'data-' + a
          , v === null ?
              null :
            r === true || typeof v === 'string' || typeof v === 'number' ?
              v :
              JSON.stringify(v)
          )
        }
        
        return this
      }
      // Get bounding box
    , bbox: function() {
        return new SVG.BBox(this)
      }
      // Get rect box
    , rbox: function() {
        return new SVG.RBox(this)
      }
      // Checks whether the given point inside the bounding box of the element
    , inside: function(x, y) {
        var box = this.bbox()
        
        return x > box.x
            && y > box.y
            && x < box.x + box.width
            && y < box.y + box.height
      }
      // Show element
    , show: function() {
        return this.style('display', '')
      }
      // Hide element
    , hide: function() {
        return this.style('display', 'none')
      }
      // Is element visible?
    , visible: function() {
        return this.style('display') != 'none'
      }
      // Return id on string conversion
    , toString: function() {
        return this.attr('id')
      }
      // Private: find svg parent by instance
    , _parent: function(parent) {
        var element = this
        
        while (element != null && !(element instanceof parent))
          element = element.parent
    
        return element
      }
      // Private: tester method for style detection
    , _isStyle: function(a) {
        return typeof a == 'string' ? SVG.regex.test(a, 'isStyle') : false
      }
      // Private: parse a matrix string
    , _parseMatrix: function(o) {
        if (o.matrix) {
          /* split matrix string */
          var m = o.matrix.replace(/\s/g, '').split(',')
          
          /* pasrse values */
          if (m.length == 6) {
            o.a = parseFloat(m[0])
            o.b = parseFloat(m[1])
            o.c = parseFloat(m[2])
            o.d = parseFloat(m[3])
            o.e = parseFloat(m[4])
            o.f = parseFloat(m[5])
          }
        }
        
        return o
      }
      
    })
  
    SVG.Parent = function(element) {
      this.constructor.call(this, element)
    }
    
    // Inherit from SVG.Element
    SVG.Parent.prototype = new SVG.Element
    
    //
    SVG.extend(SVG.Parent, {
    	// Returns all child elements
      children: function() {
        return this._children || (this._children = [])
      }
      // Add given element at a position
    , add: function(element, i) {
        if (!this.has(element)) {
          /* define insertion index if none given */
          i = i == null ? this.children().length : i
          
          /* remove references from previous parent */
          if (element.parent) {
            var index = element.parent.children().indexOf(element)
            element.parent.children().splice(index, 1)
          }
          
          /* add element references */
          this.children().splice(i, 0, element)
          this.node.insertBefore(element.node, this.node.childNodes[i] || null)
          element.parent = this
        }
    
        /* reposition defs */
        if (this._defs) {
          this.node.removeChild(this._defs.node)
          this.node.appendChild(this._defs.node)
        }
        
        return this
      }
      // Basically does the same as `add()` but returns the added element instead
    , put: function(element, i) {
        this.add(element, i)
        return element
      }
      // Checks if the given element is a child
    , has: function(element) {
        return this.children().indexOf(element) >= 0
      }
      // Get a element at the given index
    , get: function(i) {
        return this.children()[i]
      }
      // Get first child, skipping the defs node
    , first: function() {
        return this.children()[0]
      }
      // Get the last child
    , last: function() {
        return this.children()[this.children().length - 1]
      }
      // Iterates over all children and invokes a given block
    , each: function(block, deep) {
        var i, il
          , children = this.children()
        
        for (i = 0, il = children.length; i < il; i++) {
          if (children[i] instanceof SVG.Element)
            block.apply(children[i], [i, children])
    
          if (deep && (children[i] instanceof SVG.Container))
            children[i].each(block, deep)
        }
      
        return this
      }
      // Remove a child element at a position
    , removeElement: function(element) {
        var i = this.children().indexOf(element)
    
        this.children().splice(i, 1)
        this.node.removeChild(element.node)
        element.parent = null
        
        return this
      }
      // Remove all elements in this container
    , clear: function() {
        /* remove children */
        for (var i = this.children().length - 1; i >= 0; i--)
          this.removeElement(this.children()[i])
    
        /* remove defs node */
        if (this._defs)
          this._defs.clear()
    
        return this
      }
     , // Get defs
      defs: function() {
        return this.doc().defs()
      }
    })
  
    SVG.Container = function(element) {
      this.constructor.call(this, element)
    }
    
    // Inherit from SVG.Parent
    SVG.Container.prototype = new SVG.Parent
    
    //
    SVG.extend(SVG.Container, {
      // Get the viewBox and calculate the zoom value
      viewbox: function(v) {
        if (arguments.length == 0)
          /* act as a getter if there are no arguments */
          return new SVG.ViewBox(this)
        
        /* otherwise act as a setter */
        v = arguments.length == 1 ?
          [v.x, v.y, v.width, v.height] :
          [].slice.call(arguments)
        
        return this.attr('viewBox', v)
      }
      
    })
  
    SVG.FX = function(element) {
      /* store target element */
      this.target = element
    }
    
    //
    SVG.extend(SVG.FX, {
      // Add animation parameters and start animation
      animate: function(d, ease, delay) {
        var akeys, tkeys, skeys, key
          , element = this.target
          , fx = this
        
        /* dissect object if one is passed */
        if (typeof d == 'object') {
          delay = d.delay
          ease = d.ease
          d = d.duration
        }
    
        /* ensure default duration and easing */
        d = d == null ? 1000 : d
        ease = ease || '<>'
    
        /* process values */
        fx.to = function(pos) {
          var i
    
          /* normalise pos */
          pos = pos < 0 ? 0 : pos > 1 ? 1 : pos
    
          /* collect attribute keys */
          if (akeys == null) {
            akeys = []
            for (key in fx.attrs)
              akeys.push(key)
    
            /* make sure morphable elements are scaled, translated and morphed all together */
            if (element.morphArray) {
              /* get destination */
              var box
                , p = new element.morphArray(fx._plot || element.points.toString())
    
              /* add size */
              if (fx._size) p.size(fx._size.width.to, fx._size.height.to)
    
              /* add movement */
              box = p.bbox()
              if (fx._x) p.move(fx._x.to, box.y)
              else if (fx._cx) p.move(fx._cx.to - box.width / 2, box.y)
    
              box = p.bbox()
              if (fx._y) p.move(box.x, fx._y.to)
              else if (fx._cy) p.move(box.x, fx._cy.to - box.height / 2)
    
              /* delete element oriented changes */
              delete fx._x
              delete fx._y
              delete fx._cx
              delete fx._cy
              delete fx._size
    
              fx._plot = element.points.morph(p)
            }
          }
    
          /* collect transformation keys */
          if (tkeys == null) {
            tkeys = []
            for (key in fx.trans)
              tkeys.push(key)
          }
    
          /* collect style keys */
          if (skeys == null) {
            skeys = []
            for (key in fx.styles)
              skeys.push(key)
          }
    
          /* apply easing */
          pos = ease == '<>' ?
            (-Math.cos(pos * Math.PI) / 2) + 0.5 :
          ease == '>' ?
            Math.sin(pos * Math.PI / 2) :
          ease == '<' ?
            -Math.cos(pos * Math.PI / 2) + 1 :
          ease == '-' ?
            pos :
          typeof ease == 'function' ?
            ease(pos) :
            pos
    
          /* run all x-position properties */
          if (fx._x)
            element.x(fx._at(fx._x, pos))
          else if (fx._cx)
            element.cx(fx._at(fx._cx, pos))
    
          /* run all y-position properties */
          if (fx._y)
            element.y(fx._at(fx._y, pos))
          else if (fx._cy)
            element.cy(fx._at(fx._cy, pos))
    
          /* run all size properties */
          if (fx._size)
            element.size(fx._at(fx._size.width, pos), fx._at(fx._size.height, pos))
    
          /* run plot function */
          if (fx._plot)
            element.plot(fx._plot.at(pos))
    
          /* run all viewbox properties */
          if (fx._viewbox)
            element.viewbox(
              fx._at(fx._viewbox.x, pos)
            , fx._at(fx._viewbox.y, pos)
            , fx._at(fx._viewbox.width, pos)
            , fx._at(fx._viewbox.height, pos)
            )
    
          /* animate attributes */
          for (i = akeys.length - 1; i >= 0; i--)
            element.attr(akeys[i], fx._at(fx.attrs[akeys[i]], pos))
    
          /* animate transformations */
          for (i = tkeys.length - 1; i >= 0; i--)
            element.transform(tkeys[i], fx._at(fx.trans[tkeys[i]], pos))
    
          /* animate styles */
          for (i = skeys.length - 1; i >= 0; i--)
            element.style(skeys[i], fx._at(fx.styles[skeys[i]], pos))
    
          /* callback for each keyframe */
          if (fx._during)
            fx._during.call(element, pos, function(from, to) {
              return fx._at({ from: from, to: to }, pos)
            })
        }
        
        if (typeof d === 'number') {
          /* delay animation */
          this.timeout = setTimeout(function() {
            var start = new Date().getTime()
    
            /* initialize situation object */
            fx.situation = {
              interval: 1000 / 60
            , start:    start
            , play:     true
            , finish:   start + d
            , duration: d
            }
    
            /* start animation */
            fx.interval = setInterval(function(){
    
              if (fx.situation.play === true) {
                // This code was borrowed from the emile.js micro framework by Thomas Fuchs, aka MadRobby.
                var time = new Date().getTime()
                  , pos = time > fx.situation.finish ? 1 : (time - fx.situation.start) / d
                
                /* process values */
                fx.to(pos)
                
                /* finish off animation */
                if (time > fx.situation.finish) {
                  if (fx._plot)
                    element.plot(new SVG.PointArray(fx._plot.destination).settle())
    
                  clearInterval(fx.interval)
                  fx._after ? fx._after.apply(element, [fx]) : fx.stop()
                }
              }
              
            }, d > fx.situation.interval ? fx.situation.interval : d)
            
          }, delay || 0)
        }
        
        return this
      }
      // Get bounding box of target element
    , bbox: function() {
        return this.target.bbox()
      }
      // Add animatable attributes
    , attr: function(a, v, n) {
        if (typeof a == 'object')
          for (var key in a)
            this.attr(key, a[key])
        
        else
          this.attrs[a] = { from: this.target.attr(a), to: v }
        
        return this
      }
      // Add animatable transformations
    , transform: function(o, v) {
        if (arguments.length == 1) {
          /* parse matrix string */
          o = this.target._parseMatrix(o)
          
          /* dlete matrixstring from object */
          delete o.matrix
          
          /* store matrix values */
          for (v in o)
            this.trans[v] = { from: this.target.trans[v], to: o[v] }
          
        } else {
          /* apply transformations as object if key value arguments are given*/
          var transform = {}
          transform[o] = v
          
          this.transform(transform)
        }
        
        return this
      }
      // Add animatable styles
    , style: function(s, v) {
        if (typeof s == 'object')
          for (var key in s)
            this.style(key, s[key])
        
        else
          this.styles[s] = { from: this.target.style(s), to: v }
        
        return this
      }
      // Animatable x-axis
    , x: function(x) {
        this._x = { from: this.target.x(), to: x }
        
        return this
      }
      // Animatable y-axis
    , y: function(y) {
        this._y = { from: this.target.y(), to: y }
        
        return this
      }
      // Animatable center x-axis
    , cx: function(x) {
        this._cx = { from: this.target.cx(), to: x }
        
        return this
      }
      // Animatable center y-axis
    , cy: function(y) {
        this._cy = { from: this.target.cy(), to: y }
        
        return this
      }
      // Add animatable move
    , move: function(x, y) {
        return this.x(x).y(y)
      }
      // Add animatable center
    , center: function(x, y) {
        return this.cx(x).cy(y)
      }
      // Add animatable size
    , size: function(width, height) {
        if (this.target instanceof SVG.Text) {
          /* animate font size for Text elements */
          this.attr('font-size', width)
          
        } else {
          /* animate bbox based size for all other elements */
          var box = this.target.bbox()
    
          this._size = {
            width:  { from: box.width,  to: width  }
          , height: { from: box.height, to: height }
          }
        }
        
        return this
      }
      // Add animatable plot
    , plot: function(p) {
        this._plot = p
    
        return this
      }
      // Add animatable viewbox
    , viewbox: function(x, y, width, height) {
        if (this.target instanceof SVG.Container) {
          var box = this.target.viewbox()
          
          this._viewbox = {
            x:      { from: box.x,      to: x      }
          , y:      { from: box.y,      to: y      }
          , width:  { from: box.width,  to: width  }
          , height: { from: box.height, to: height }
          }
        }
        
        return this
      }
      // Add animateable gradient update
    , update: function(o) {
        if (this.target instanceof SVG.Stop) {
          if (o.opacity != null) this.attr('stop-opacity', o.opacity)
          if (o.color   != null) this.attr('stop-color', o.color)
          if (o.offset  != null) this.attr('offset', new SVG.Number(o.offset))
        }
    
        return this
      }
      // Add callback for each keyframe
    , during: function(during) {
        this._during = during
        
        return this
      }
      // Callback after animation
    , after: function(after) {
        this._after = after
        
        return this
      }
      // Stop running animation
    , stop: function() {
        /* stop current animation */
        clearTimeout(this.timeout)
        clearInterval(this.interval)
        
        /* reset storage for properties that need animation */
        this.attrs     = {}
        this.trans     = {}
        this.styles    = {}
        this.situation = {}
    
        delete this._x
        delete this._y
        delete this._cx
        delete this._cy
        delete this._size
        delete this._plot
        delete this._after
        delete this._during
        delete this._viewbox
    
        return this
      }
      // Pause running animation
    , pause: function() {
        if (this.situation.play === true) {
          this.situation.play  = false
          this.situation.pause = new Date().getTime()
        }
    
        return this
      }
      // Play running animation
    , play: function() {
        if (this.situation.play === false) {
          var pause = new Date().getTime() - this.situation.pause
          
          this.situation.finish += pause
          this.situation.start  += pause
          this.situation.play    = true
        }
    
        return this
      }
      // Private: calculate position according to from and to
    , _at: function(o, pos) {
        /* number recalculation */
        return typeof o.from == 'number' ?
          o.from + (o.to - o.from) * pos :
        
        /* unit recalculation */
        SVG.regex.unit.test(o.to) ?
          new SVG.Number(o.to)
            .minus(new SVG.Number(o.from))
            .times(pos)
            .plus(new SVG.Number(o.from)) :
        
        /* color recalculation */
        o.to && (o.to.r || SVG.Color.test(o.to)) ?
          this._color(o, pos) :
        
        /* for all other values wait until pos has reached 1 to return the final value */
        pos < 1 ? o.from : o.to
      }
      // Private: tween color
    , _color: function(o, pos) {
        var from, to
        
        /* normalise pos */
        pos = pos < 0 ? 0 : pos > 1 ? 1 : pos
        
        /* convert FROM */
        from = new SVG.Color(o.from)
        
        /* convert TO hex to rgb */
        to = new SVG.Color(o.to)
        
        /* tween color and return hex */
        return new SVG.Color({
          r: ~~(from.r + (to.r - from.r) * pos)
        , g: ~~(from.g + (to.g - from.g) * pos)
        , b: ~~(from.b + (to.b - from.b) * pos)
        }).toHex()
      }
      
    })
    
    //
    SVG.extend(SVG.Element, {
      // Get fx module or create a new one, then animate with given duration and ease
      animate: function(d, ease, delay) {
        return (this.fx || (this.fx = new SVG.FX(this))).stop().animate(d, ease, delay)
      }
      // Stop current animation; this is an alias to the fx instance
    , stop: function() {
        if (this.fx)
          this.fx.stop()
        
        return this
      }
      // Pause current animation
    , pause: function() {
        if (this.fx)
          this.fx.pause()
    
        return this
      }
      // Play paused current animation
    , play: function() {
        if (this.fx)
          this.fx.play()
    
        return this
      }
    
      
    })
    // Usage:
    
    //     rect.animate(1500, '>').move(200, 300).after(function() {
    //       this.fill({ color: '#f06' })
    //     })
  
  
    ;[  'click'
      , 'dblclick'
      , 'mousedown'
      , 'mouseup'
      , 'mouseover'
      , 'mouseout'
      , 'mousemove'
      , 'mouseenter'
      , 'mouseleave' ].forEach(function(event) {
      
      /* add event to SVG.Element */
      SVG.Element.prototype[event] = function(f) {
        var self = this
        
        /* bind event to element rather than element node */
        this.node['on' + event] = typeof f == 'function' ?
          function() { return f.apply(self, arguments) } : null
        
        return this
      }
      
    })
    
    // Add event binder in the SVG namespace
    SVG.on = function(node, event, listener) {
      if (node.addEventListener)
        node.addEventListener(event, listener, false)
      else
        node.attachEvent('on' + event, listener)
    }
    
    // Add event unbinder in the SVG namespace
    SVG.off = function(node, event, listener) {
      if (node.removeEventListener)
        node.removeEventListener(event, listener, false)
      else
        node.detachEvent('on' + event, listener)
    }
    
    //
    SVG.extend(SVG.Element, {
      // Bind given event to listener
      on: function(event, listener) {
        SVG.on(this.node, event, listener)
        
        return this
      }
      // Unbind event from listener
    , off: function(event, listener) {
        SVG.off(this.node, event, listener)
        
        return this
      }
    })
  
    SVG.Defs = function() {
      this.constructor.call(this, SVG.create('defs'))
    }
    
    // Inherits from SVG.Container
    SVG.Defs.prototype = new SVG.Container
  
    SVG.G = function() {
      this.constructor.call(this, SVG.create('g'))
    }
    
    // Inherit from SVG.Container
    SVG.G.prototype = new SVG.Container
    
    //
    SVG.extend(SVG.G, {
      // Move over x-axis
      x: function(x) {
        return x == null ? this.trans.x : this.transform('x', x)
      }
      // Move over y-axis
    , y: function(y) {
        return y == null ? this.trans.y : this.transform('y', y)
      }
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create a group element
      group: function() {
        return this.put(new SVG.G)
      }
      
    })
  
    SVG.extend(SVG.Element, {
      // Get all siblings, including myself
      siblings: function() {
        return this.parent.children()
      }
      // Get the curent position siblings
    , position: function() {
        var siblings = this.siblings()
    
        return siblings.indexOf(this)
      }
      // Get the next element (will return null if there is none)
    , next: function() {
        return this.siblings()[this.position() + 1]
      }
      // Get the next element (will return null if there is none)
    , previous: function() {
        return this.siblings()[this.position() - 1]
      }
      // Send given element one step forward
    , forward: function() {
        var i = this.position()
        return this.parent.removeElement(this).put(this, i + 1)
      }
      // Send given element one step backward
    , backward: function() {
        var i = this.position()
        
        if (i > 0)
          this.parent.removeElement(this).add(this, i - 1)
    
        return this
      }
      // Send given element all the way to the front
    , front: function() {
        return this.parent.removeElement(this).put(this)
      }
      // Send given element all the way to the back
    , back: function() {
        if (this.position() > 0)
          this.parent.removeElement(this).add(this, 0)
        
        return this
      }
      // Inserts a given element before the targeted element
    , before: function(element) {
        element.remove()
    
        var i = this.position()
        
        this.parent.add(element, i)
    
        return this
      }
      // Insters a given element after the targeted element
    , after: function(element) {
        element.remove()
        
        var i = this.position()
        
        this.parent.add(element, i + 1)
    
        return this
      }
    
    })
  
    SVG.Mask = function() {
      this.constructor.call(this, SVG.create('mask'))
    
      /* keep references to masked elements */
      this.targets = []
    }
    
    // Inherit from SVG.Container
    SVG.Mask.prototype = new SVG.Container
    
    //
    SVG.extend(SVG.Mask, {
      // Unmask all masked elements and remove itself
      remove: function() {
        /* unmask all targets */
        for (var i = this.targets.length - 1; i >= 0; i--)
          if (this.targets[i])
            this.targets[i].unmask()
        delete this.targets
    
        /* remove mask from parent */
        this.parent.removeElement(this)
        
        return this
      }
    })
    
    //
    SVG.extend(SVG.Element, {
      // Distribute mask to svg element
      maskWith: function(element) {
        /* use given mask or create a new one */
        this.masker = element instanceof SVG.Mask ? element : this.parent.mask().add(element)
    
        /* store reverence on self in mask */
        this.masker.targets.push(this)
        
        /* apply mask */
        return this.attr('mask', 'url("#' + this.masker.attr('id') + '")')
      }
      // Unmask element
    , unmask: function() {
        delete this.masker
        return this.attr('mask', null)
      }
      
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create masking element
      mask: function() {
        return this.defs().put(new SVG.Mask)
      }
      
    })
  
    SVG.Clip = function() {
      this.constructor.call(this, SVG.create('clipPath'))
    
      /* keep references to clipped elements */
      this.targets = []
    }
    
    // Inherit from SVG.Container
    SVG.Clip.prototype = new SVG.Container
    
    //
    SVG.extend(SVG.Clip, {
      // Unclip all clipped elements and remove itself
      remove: function() {
        /* unclip all targets */
        for (var i = this.targets.length - 1; i >= 0; i--)
          if (this.targets[i])
            this.targets[i].unclip()
        delete this.targets
    
        /* remove clipPath from parent */
        this.parent.removeElement(this)
        
        return this
      }
    })
    
    //
    SVG.extend(SVG.Element, {
      // Distribute clipPath to svg element
      clipWith: function(element) {
        /* use given clip or create a new one */
        this.clipper = element instanceof SVG.Clip ? element : this.parent.clip().add(element)
    
        /* store reverence on self in mask */
        this.clipper.targets.push(this)
        
        /* apply mask */
        return this.attr('clip-path', 'url("#' + this.clipper.attr('id') + '")')
      }
      // Unclip element
    , unclip: function() {
        delete this.clipper
        return this.attr('clip-path', null)
      }
      
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create clipping element
      clip: function() {
        return this.defs().put(new SVG.Clip)
      }
    
    })
  
    SVG.Gradient = function(type) {
      this.constructor.call(this, SVG.create(type + 'Gradient'))
      
      /* store type */
      this.type = type
    }
    
    // Inherit from SVG.Container
    SVG.Gradient.prototype = new SVG.Container
    
    //
    SVG.extend(SVG.Gradient, {
      // From position
      from: function(x, y) {
        return this.type == 'radial' ?
          this.attr({ fx: new SVG.Number(x), fy: new SVG.Number(y) }) :
          this.attr({ x1: new SVG.Number(x), y1: new SVG.Number(y) })
      }
      // To position
    , to: function(x, y) {
        return this.type == 'radial' ?
          this.attr({ cx: new SVG.Number(x), cy: new SVG.Number(y) }) :
          this.attr({ x2: new SVG.Number(x), y2: new SVG.Number(y) })
      }
      // Radius for radial gradient
    , radius: function(r) {
        return this.type == 'radial' ?
          this.attr({ r: new SVG.Number(r) }) :
          this
      }
      // Add a color stop
    , at: function(stop) {
        return this.put(new SVG.Stop(stop))
      }
      // Update gradient
    , update: function(block) {
        /* remove all stops */
        this.clear()
        
        /* invoke passed block */
        block(this)
        
        return this
      }
      // Return the fill id
    , fill: function() {
        return 'url(#' + this.attr('id') + ')'
      }
      // Alias string convertion to fill
    , toString: function() {
        return this.fill()
      }
      
    })
    
    //
    SVG.extend(SVG.Defs, {
      // define gradient
      gradient: function(type, block) {
        var element = this.put(new SVG.Gradient(type))
        
        /* invoke passed block */
        block(element)
        
        return element
      }
      
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create gradient element in defs
      gradient: function(type, block) {
        return this.defs().gradient(type, block)
      }
      
    })
    
    
    SVG.Stop = function(stop) {
      this.constructor.call(this, SVG.create('stop'))
      
      /* immediatelly build stop */
      this.update(stop)
    }
    
    // Inherit from SVG.Element
    SVG.Stop.prototype = new SVG.Element
    
    //
    SVG.extend(SVG.Stop, {
      // add color stops
      update: function(o) {
        /* set attributes */
        if (o.opacity != null) this.attr('stop-opacity', o.opacity)
        if (o.color   != null) this.attr('stop-color', o.color)
        if (o.offset  != null) this.attr('offset', new SVG.Number(o.offset))
    
        return this
      }
      
    })
    
  
  
    SVG.Doc = function(element) {
      /* ensure the presence of a html element */
      this.parent = typeof element == 'string' ?
        document.getElementById(element) :
        element
      
      /* If the target is an svg element, use that element as the main wrapper.
         This allows svg.js to work with svg documents as well. */
      this.constructor
        .call(this, this.parent.nodeName == 'svg' ? this.parent : SVG.create('svg'))
      
      /* set svg element attributes */
      this
        .attr({ xmlns: SVG.ns, version: '1.1', width: '100%', height: '100%' })
        .attr('xlink', SVG.xlink, SVG.ns)
      
      /* create the <defs> node */
      this._defs = new SVG.Defs
      this._defs.parent = this
      this.node.appendChild(this._defs.node)
    
      /* turno of sub pixel offset by default */
      this.doSubPixelOffsetFix = false
      
      /* ensure correct rendering */
      if (this.parent.nodeName != 'svg')
        this.stage()
    }
    
    // Inherits from SVG.Container
    SVG.Doc.prototype = new SVG.Container
    
    //
    SVG.extend(SVG.Doc, {
      // Hack for safari preventing text to be rendered in one line.
      // Basically it sets the position of the svg node to absolute
      // when the dom is loaded, and resets it to relative a few milliseconds later.
      // It also handles sub-pixel offset rendering properly.
      stage: function() {
        var check
          , element = this
          , wrapper = document.createElement('div')
    
        /* set temporary wrapper to position relative */
        wrapper.style.cssText = 'position:relative;height:100%;'
    
        /* put element into wrapper */
        element.parent.appendChild(wrapper)
        wrapper.appendChild(element.node)
    
        /* check for dom:ready */
        check = function() {
          if (document.readyState === 'complete') {
            element.style('position:absolute;')
            setTimeout(function() {
              /* set position back to relative */
              element.style('position:relative;overflow:hidden;')
    
              /* remove temporary wrapper */
              element.parent.removeChild(element.node.parentNode)
              element.node.parentNode.removeChild(element.node)
              element.parent.appendChild(element.node)
    
              /* after wrapping is done, fix sub-pixel offset */
              element.subPixelOffsetFix()
              
              /* make sure sub-pixel offset is fixed every time the window is resized */
              SVG.on(window, 'resize', function() {
                element.subPixelOffsetFix()
              })
              
            }, 5)
          } else {
            setTimeout(check, 10)
          }
        }
    
        check()
    
        return this
      }
    
      // Creates and returns defs element
    , defs: function() {
        return this._defs
      }
    
      // Fix for possible sub-pixel offset. See:
      // https://bugzilla.mozilla.org/show_bug.cgi?id=608812
    , subPixelOffsetFix: function() {
        if (this.doSubPixelOffsetFix) {
          var pos = this.node.getScreenCTM()
          
          if (pos)
            this
              .style('left', (-pos.e % 1) + 'px')
              .style('top',  (-pos.f % 1) + 'px')
        }
        
        return this
      }
    
    , fixSubPixelOffset: function() {
        this.doSubPixelOffsetFix = true
    
        return this
      }
      
    })
  
    SVG.Shape = function(element) {
      this.constructor.call(this, element)
    }
    
    // Inherit from SVG.Element
    SVG.Shape.prototype = new SVG.Element
  
    SVG.Use = function() {
      this.constructor.call(this, SVG.create('use'))
    }
    
    // Inherit from SVG.Shape
    SVG.Use.prototype = new SVG.Shape
    
    //
    SVG.extend(SVG.Use, {
      // Use element as a reference
      element: function(element) {
        /* store target element */
        this.target = element
    
        /* set lined element */
        return this.attr('href', '#' + element, SVG.xlink)
      }
      
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create a use element
      use: function(element) {
        return this.put(new SVG.Use).element(element)
      }
    
    })
  
    SVG.Rect = function() {
      this.constructor.call(this, SVG.create('rect'))
    }
    
    // Inherit from SVG.Shape
    SVG.Rect.prototype = new SVG.Shape
    
    //
    SVG.extend(SVG.Container, {
      // Create a rect element
      rect: function(width, height) {
        return this.put(new SVG.Rect().size(width, height))
      }
    
    })
  
    SVG.Ellipse = function() {
      this.constructor.call(this, SVG.create('ellipse'))
    }
    
    // Inherit from SVG.Shape
    SVG.Ellipse.prototype = new SVG.Shape
    
    //
    SVG.extend(SVG.Ellipse, {
      // Move over x-axis
      x: function(x) {
        return x == null ? this.cx() - this.attr('rx') : this.cx(x + this.attr('rx'))
      }
      // Move over y-axis
    , y: function(y) {
        return y == null ? this.cy() - this.attr('ry') : this.cy(y + this.attr('ry'))
      }
      // Move by center over x-axis
    , cx: function(x) {
        return x == null ? this.attr('cx') : this.attr('cx', new SVG.Number(x).divide(this.trans.scaleX))
      }
      // Move by center over y-axis
    , cy: function(y) {
        return y == null ? this.attr('cy') : this.attr('cy', new SVG.Number(y).divide(this.trans.scaleY))
      }
      // Set width of element
    , width: function(width) {
        return width == null ? this.attr('rx') * 2 : this.attr('rx', new SVG.Number(width).divide(2))
      }
      // Set height of element
    , height: function(height) {
        return height == null ? this.attr('ry') * 2 : this.attr('ry', new SVG.Number(height).divide(2))
      }
      // Custom size function
    , size: function(width, height) {
        return this.attr({
          rx: new SVG.Number(width).divide(2)
        , ry: new SVG.Number(height).divide(2)
        })
      }
      
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create circle element, based on ellipse
      circle: function(size) {
        return this.ellipse(size, size)
      }
      // Create an ellipse
    , ellipse: function(width, height) {
        return this.put(new SVG.Ellipse).size(width, height).move(0, 0)
      }
      
    })
    
    // Usage:
    
    //     draw.ellipse(200, 100)
  
    SVG.Line = function() {
      this.constructor.call(this, SVG.create('line'))
    }
    
    // Inherit from SVG.Shape
    SVG.Line.prototype = new SVG.Shape
    
    // Add required methods
    SVG.extend(SVG.Line, {
      // Move over x-axis
      x: function(x) {
        var b = this.bbox()
        
        return x == null ? b.x : this.attr({
          x1: this.attr('x1') - b.x + x
        , x2: this.attr('x2') - b.x + x
        })
      }
      // Move over y-axis
    , y: function(y) {
        var b = this.bbox()
        
        return y == null ? b.y : this.attr({
          y1: this.attr('y1') - b.y + y
        , y2: this.attr('y2') - b.y + y
        })
      }
      // Move by center over x-axis
    , cx: function(x) {
        var half = this.bbox().width / 2
        return x == null ? this.x() + half : this.x(x - half)
      }
      // Move by center over y-axis
    , cy: function(y) {
        var half = this.bbox().height / 2
        return y == null ? this.y() + half : this.y(y - half)
      }
      // Set width of element
    , width: function(width) {
        var b = this.bbox()
    
        return width == null ? b.width : this.attr(this.attr('x1') < this.attr('x2') ? 'x2' : 'x1', b.x + width)
      }
      // Set height of element
    , height: function(height) {
        var b = this.bbox()
    
        return height == null ? b.height : this.attr(this.attr('y1') < this.attr('y2') ? 'y2' : 'y1', b.y + height)
      }
      // Set line size by width and height
    , size: function(width, height) {
        return this.width(width).height(height)
      }
      // Set path data
    , plot: function(x1, y1, x2, y2) {
        return this.attr({
          x1: x1
        , y1: y1
        , x2: x2
        , y2: y2
        })
      }
      
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create a line element
      line: function(x1, y1, x2, y2) {
        return this.put(new SVG.Line().plot(x1, y1, x2, y2))
      }
      
    })
  
  
    SVG.Polyline = function() {
      this.constructor.call(this, SVG.create('polyline'))
    }
    
    // Inherit from SVG.Shape
    SVG.Polyline.prototype = new SVG.Shape
    
    SVG.Polygon = function() {
      this.constructor.call(this, SVG.create('polygon'))
    }
    
    // Inherit from SVG.Shape
    SVG.Polygon.prototype = new SVG.Shape
    
    // Add polygon-specific functions
    SVG.extend(SVG.Polyline, SVG.Polygon, {
      // Define morphable array
      morphArray:  SVG.PointArray
      // Plot new path
    , plot: function(p) {
        return this.attr('points', (this.points = new SVG.PointArray(p, [[0,0]])))
      }
      // Move by left top corner
    , move: function(x, y) {
        return this.attr('points', this.points.move(x, y))
      }
      // Move by left top corner over x-axis
    , x: function(x) {
        return x == null ? this.bbox().x : this.move(x, this.bbox().y)
      }
      // Move by left top corner over y-axis
    , y: function(y) {
        return y == null ? this.bbox().y : this.move(this.bbox().x, y)
      }
      // Set width of element
    , width: function(width) {
        var b = this.bbox()
    
        return width == null ? b.width : this.size(width, b.height)
      }
      // Set height of element
    , height: function(height) {
        var b = this.bbox()
    
        return height == null ? b.height : this.size(b.width, height) 
      }
      // Set element size to given width and height
    , size: function(width, height) {
        return this.attr('points', this.points.size(width, height))
      }
    
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create a wrapped polyline element
      polyline: function(p) {
        return this.put(new SVG.Polyline).plot(p)
      }
      // Create a wrapped polygon element
    , polygon: function(p) {
        return this.put(new SVG.Polygon).plot(p)
      }
    
    })
  
    SVG.Path = function(unbiased) {
      this.constructor.call(this, SVG.create('path'))
      
      this.unbiased = !!unbiased
    }
    
    // Inherit from SVG.Shape
    SVG.Path.prototype = new SVG.Shape
    
    SVG.extend(SVG.Path, {
      // Move over x-axis
      x: function(x) {
        return x == null ? this.bbox().x : this.transform('x', x)
      }
      // Move over y-axis
    , y: function(y) {
        return y == null ? this.bbox().y : this.transform('y', y)
      }
      // Set width of element
    , width: function(width) {
        var b = this.bbox()
    
        return width == null ? b.width : this.size(width, b.height)
      }
      // Set height of element
    , height: function(height) {
        var b = this.bbox()
    
        return height == null ? b.height : this.size(b.width, height)
      }
      // Set the actual size in pixels
    , size: function(width, height) {
        var scale = width / this._offset.width
        
        return this.transform({
          scaleX: scale
        , scaleY: height != null ? height / this._offset.height : scale
        })
      }
      // Set path data
    , plot: function(data) {
        var x = this.trans.scaleX
          , y = this.trans.scaleY
        
        /* native plot */
        this._plot(data)
        
        /* store offset */
        this._offset = this.transform({ scaleX: 1, scaleY: 1 }).bbox()
        
        /* get and store the actual offset of the element */
        if (this.unbiased) {
          this._offset.x = this._offset.y = 0
        } else {
          this._offset.x -= this.trans.x
          this._offset.y -= this.trans.y
        }
        
        return this.transform({ scaleX: x, scaleY: y })
      }
      // Private: Native plot
    , _plot: function(data) {
        return this.attr('d', data || 'M0,0')
      }
      
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create a wrapped path element
      path: function(data, unbiased) {
        return this.put(new SVG.Path(unbiased)).plot(data)
      }
    
    })
  
    SVG.Image = function() {
      this.constructor.call(this, SVG.create('image'))
    }
    
    // Inherit from SVG.Element
    SVG.Image.prototype = new SVG.Shape
    
    //
    SVG.extend(SVG.Image, {
      // (re)load image
      load: function(url) {
        return (url ? this.attr('href', (this.src = url), SVG.xlink) : this)
      }
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create image element, load image and set its size
      image: function(source, width, height) {
        width = width != null ? width : 100
        return this.put(new SVG.Image().load(source).size(width, height != null ? height : width))
      }
    
    })
  
    var _styleAttr = ('size family weight stretch variant style').split(' ')
    
    SVG.Text = function() {
      this.constructor.call(this, SVG.create('text'))
      
      /* define default style */
      this.styles = {
        'font-size':    16
      , 'font-family':  'Helvetica, Arial, sans-serif'
      , 'text-anchor':  'start'
      }
      
      this._leading = new SVG.Number('1.2em')
      this._rebuild = true
    }
    
    // Inherit from SVG.Element
    SVG.Text.prototype = new SVG.Shape
    
    //
    SVG.extend(SVG.Text, {
      // Move over x-axis
      x: function(x, a) {
        /* act as getter */
        if (x == null)
          return a ? this.attr('x') : this.bbox().x
        
        /* set x taking anchor in mind */
        if (!a) {
          a = this.style('text-anchor')
          x = a == 'start' ? x : a == 'end' ? x + this.bbox().width : x + this.bbox().width / 2
        }
    
        /* move lines as well if no textPath si present */
        if (!this.textPath)
          this.lines.each(function() { if (this.newLined) this.x(x) })
    
        return this.attr('x', x)
      }
      // Move center over x-axis
    , cx: function(x, a) {
        return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2)
      }
      // Move center over y-axis
    , cy: function(y, a) {
        return y == null ? this.bbox().cy : this.y(a ? y : y - this.bbox().height / 2)
      }
      // Move element to given x and y values
    , move: function(x, y, a) {
        return this.x(x, a).y(y)
      }
      // Move element by its center
    , center: function(x, y, a) {
        return this.cx(x, a).cy(y, a)
      }
      // Set the text content
    , text: function(text) {
        /* act as getter */
        if (text == null)
          return this.content
        
        /* remove existing lines */
        this.clear()
        
        if (typeof text === 'function') {
          this._rebuild = false
    
          text(this)
    
        } else {
          this._rebuild = true
    
          /* make sure text is not blank */
          text = SVG.regex.isBlank.test(text) ? 'text' : text
          
          var i, il
            , lines = text.split('\n')
          
          /* build new lines */
          for (i = 0, il = lines.length; i < il; i++)
            this.tspan(lines[i]).newLine()
    
          this.rebuild()
        }
        
        return this
      }
      // Create a tspan
    , tspan: function(text) {
        var node  = this.textPath ? this.textPath.node : this.node
          , tspan = new SVG.TSpan().text(text)
          , style = this.style()
        
        /* add new tspan */
        node.appendChild(tspan.node)
        this.lines.add(tspan)
    
        /* add style if any */
        if (!SVG.regex.isBlank.test(style))
          tspan.style(style)
    
        /* store content */
        this.content += text
    
        /* store text parent */
        tspan.parent = this
    
        return tspan
      }
      // Set font size
    , size: function(size) {
        return this.attr('font-size', size)
      }
      // Set / get leading
    , leading: function(value) {
        /* act as getter */
        if (value == null)
          return this._leading
        
        /* act as setter */
        value = new SVG.Number(value)
        this._leading = value
        
        /* apply leading */
        this.lines.each(function() {
          if (this.newLined)
            this.attr('dy', value)
        })
    
        return this
      }
      // rebuild appearance type
    , rebuild: function() {
        var self = this
    
        /* define position of all lines */
        if (this._rebuild) {
          this.lines.attr({
            x:      this.attr('x')
          , dy:     this._leading
          , style:  this.style()
          })
        }
    
        return this
      }
      // Clear all lines
    , clear: function() {
        var node = this.textPath ? this.textPath.node : this.node
    
        /* remove existing child nodes */
        while (node.hasChildNodes())
          node.removeChild(node.lastChild)
        
        /* refresh lines */
        delete this.lines
        this.lines = new SVG.Set
        
        /* initialize content */
        this.content = ''
    
        return this
      }
      
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create text element
      text: function(text) {
        return this.put(new SVG.Text).text(text)
      }
      
    })
    
    // tspan class
    SVG.TSpan = function() {
      this.constructor.call(this, SVG.create('tspan'))
    }
    
    // Inherit from SVG.Shape
    SVG.TSpan.prototype = new SVG.Shape
    
    // Include the container object
    SVG.extend(SVG.TSpan, {
      // Set text content
      text: function(text) {
        this.node.appendChild(document.createTextNode(text))
        
        return this
      }
      // Shortcut dx
    , dx: function(dx) {
        return this.attr('dx', dx)
      }
      // Shortcut dy
    , dy: function(dy) {
        return this.attr('dy', dy)
      }
      // Create new line
    , newLine: function() {
        this.newLined = true
        this.parent.content += '\n'
        this.dy(this.parent._leading)
        return this.attr('x', this.parent.x())
      }
    
    })
  
  
    SVG.TextPath = function() {
      this.constructor.call(this, SVG.create('textPath'))
    }
    
    // Inherit from SVG.Element
    SVG.TextPath.prototype = new SVG.Element
    
    //
    SVG.extend(SVG.Text, {
      // Create path for text to run on
      path: function(d) {
        /* create textPath element */
        this.textPath = new SVG.TextPath
    
        /* move lines to textpath */
        while(this.node.hasChildNodes())
          this.textPath.node.appendChild(this.node.firstChild)
    
        /* add textPath element as child node */
        this.node.appendChild(this.textPath.node)
    
        /* create path in defs */
        this.track = this.doc().defs().path(d, true)
    
        /* create circular reference */
        this.textPath.parent = this
    
        /* link textPath to path and add content */
        this.textPath.attr('href', '#' + this.track, SVG.xlink)
    
        return this
      }
      // Plot path if any
    , plot: function(d) {
        if (this.track) this.track.plot(d)
        return this
      }
    
    })
  
    SVG.Nested = function() {
      this.constructor.call(this, SVG.create('svg'))
      
      this.style('overflow', 'visible')
    }
    
    // Inherit from SVG.Container
    SVG.Nested.prototype = new SVG.Container
    
    //
    SVG.extend(SVG.Container, {
      // Create nested svg document
      nested: function() {
        return this.put(new SVG.Nested)
      }
      
    })
  
    SVG.A = function() {
      this.constructor.call(this, SVG.create('a'))
    }
    
    // Inherit from SVG.Parent
    SVG.A.prototype = new SVG.Container
    
    //
    SVG.extend(SVG.A, {
      // Link url
      to: function(url) {
        return this.attr('href', url, SVG.xlink)
      }
      // Link show attribute
    , show: function(target) {
        return this.attr('show', target, SVG.xlink)
      }
      // Link target attribute
    , target: function(target) {
        return this.attr('target', target)
      }
    
    })
    
    //
    SVG.extend(SVG.Container, {
      // Create a hyperlink element
      link: function(url) {
        return this.put(new SVG.A).to(url)
      }
      
    })
    
    //
    SVG.extend(SVG.Element, {
      // Create a hyperlink element
      linkTo: function(url) {
        var link = new SVG.A
    
        if (typeof url == 'function')
          url.call(link, link)
        else
          link.to(url)
    
        return this.parent.put(link).put(this)
      }
      
    })
  
    SVG._stroke = ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset']
    SVG._fill   = ['color', 'opacity', 'rule']
    
    
    // Prepend correct color prefix
    var _colorPrefix = function(type, attr) {
      return attr == 'color' ? type : type + '-' + attr
    }
    
    /* Add sugar for fill and stroke */
    ;['fill', 'stroke'].forEach(function(method) {
      var extension = {}
      
      extension[method] = function(o) {
        var indexOf
        
        if (typeof o == 'string' || SVG.Color.isRgb(o) || (o && typeof o.fill === 'function'))
          this.attr(method, o)
    
        else
          /* set all attributes from _fillAttr and _strokeAttr list */
          for (index = SVG['_' + method].length - 1; index >= 0; index--)
            if (o[SVG['_' + method][index]] != null)
              this.attr(_colorPrefix(method, SVG['_' + method][index]), o[SVG['_' + method][index]])
        
        return this
      }
      
      SVG.extend(SVG.Element, SVG.FX, extension)
      
    })
    
    SVG.extend(SVG.Element, SVG.FX, {
      // Rotation
      rotate: function(deg, x, y) {
        return this.transform({
          rotation: deg || 0
        , cx: x
        , cy: y
        })
      }
      // Skew
    , skew: function(x, y) {
        return this.transform({
          skewX: x || 0
        , skewY: y || 0
        })
      }
      // Scale
    , scale: function(x, y) {
        return this.transform({
          scaleX: x
        , scaleY: y == null ? x : y
        })
      }
      // Translate
    , translate: function(x, y) {
        return this.transform({
          x: x
        , y: y
        })
      }
      // Matrix
    , matrix: function(m) {
        return this.transform({ matrix: m })
      }
      // Opacity
    , opacity: function(value) {
        return this.attr('opacity', value)
      }
    
    })
    
    //
    SVG.extend(SVG.Rect, SVG.Ellipse, {
      // Add x and y radius
      radius: function(x, y) {
        return this.attr({ rx: x, ry: y || x })
      }
    
    })
    
    
    if (SVG.Text) {
      SVG.extend(SVG.Text, SVG.FX, {
        // Set font 
        font: function(o) {
          for (var key in o)
            key == 'anchor' ?
              this.attr('text-anchor', o[key]) :
            _styleAttr.indexOf(key) > -1 ?
              this.attr('font-'+ key, o[key]) :
              this.attr(key, o[key])
          
          return this
        }
        
      })
    }
    
  
  
    SVG.Set = function() {
      /* set initial state */
      this.clear()
    }
    
    // Set FX class
    SVG.SetFX = function(set) {
      /* store reference to set */
      this.set = set
    }
    
    //
    SVG.extend(SVG.Set, {
      // Add element to set
      add: function() {
        var i, il, elements = [].slice.call(arguments)
    
        for (i = 0, il = elements.length; i < il; i++)
          this.members.push(elements[i])
        
        return this
      }
      // Remove element from set
    , remove: function(element) {
        var i = this.members.indexOf(element)
        
        /* remove given child */
        if (i > -1)
          this.members.splice(i, 1)
    
        return this
      }
      // Iterate over all members
    , each: function(block) {
        for (var i = 0, il = this.members.length; i < il; i++)
          block.apply(this.members[i], [i, this.members])
    
        return this
      }
      // Restore to defaults
    , clear: function() {
        /* initialize store */
        this.members = []
    
        return this
      }
      // Default value
    , valueOf: function() {
        return this.members
      }
    
    })
    
    
    
    // Alias methods
    SVG.Set.inherit = function() {
      var m
        , methods = []
      
      /* gather shape methods */
      for(var m in SVG.Shape.prototype)
        if (typeof SVG.Shape.prototype[m] == 'function' && typeof SVG.Set.prototype[m] != 'function')
          methods.push(m)
    
      /* apply shape aliasses */
      methods.forEach(function(method) {
        SVG.Set.prototype[method] = function() {
          for (var i = 0, il = this.members.length; i < il; i++)
            if (this.members[i] && typeof this.members[i][method] == 'function')
              this.members[i][method].apply(this.members[i], arguments)
    
          return method == 'animate' ? (this.fx || (this.fx = new SVG.SetFX(this))) : this
        }
      })
    
      /* clear methods for the next round */
      methods = []
    
      /* gather fx methods */
      for(var m in SVG.FX.prototype)
        if (typeof SVG.FX.prototype[m] == 'function' && typeof SVG.SetFX.prototype[m] != 'function')
          methods.push(m)
    
      /* apply fx aliasses */
      methods.forEach(function(method) {
        SVG.SetFX.prototype[method] = function() {
          for (var i = 0, il = this.set.members.length; i < il; i++)
            this.set.members[i].fx[method].apply(this.set.members[i].fx, arguments)
    
          return this
        }
      })
    }
    
    //
    SVG.extend(SVG.Container, {
      // Create a new set
      set: function() {
        return new SVG.Set
      }
    
    })
    
    
    
  
  
    SVG.extend(SVG.Element, {
      // Remember arbitrary data
      remember: function(k, v) {
        /* remember every item in an object individually */
        if (typeof arguments[0] == 'object')
          for (var v in k)
            this.remember(v, k[v])
    
        /* retrieve memory */
        else if (arguments.length == 1)
          return this.memory()[k]
    
        /* store memory */
        else
          this.memory()[k] = v
    
        return this
      }
    
      // Erase a given memory
    , forget: function() {
        if (arguments.length == 0)
          this._memory = {}
        else
          for (var i = arguments.length - 1; i >= 0; i--)
            delete this.memory()[arguments[i]]
    
        return this
      }
    
      // Initialize or return local memory object
    , memory: function() {
        return this._memory || (this._memory = {})
      }
    
    })
  
    if (typeof define === 'function' && define.amd)
      define(function() { return SVG })
    else if (typeof exports !== 'undefined')
      exports.SVG = SVG
  
  }).call(this);
  