]> source.dussan.org Git - svg.js.git/commitdiff
removed `size()` from `SVG.Text` to avoid name clash
authorUlrich-Matthias Schäfer <ulima.ums@googlemail.com>
Sat, 3 Mar 2018 11:00:22 +0000 (12:00 +0100)
committerUlrich-Matthias Schäfer <ulima.ums@googlemail.com>
Sat, 3 Mar 2018 11:00:22 +0000 (12:00 +0100)
CHANGELOG.md
dist/svg.js
dist/svg.min.js
spec/spec/text.js
src/text.js

index e6a8a71e3590585f45ef32d52c1465179740d2a5..ecdc10051b3ce4a4d88a80bbea75339d2504e2b3 100644 (file)
@@ -29,6 +29,8 @@ The document follows the conventions described in [“Keep a CHANGELOG”](http:
 - removed `loaded()` and `error()` method on `SVG.Image` (#706)
 - removed sub-pixel offset fix
 - removed `SVG.Nested` (#809)
+- removed `show()` from `SVG.A` to avoid name clash (#802)
+- removed `size()` from `SVG.Text` to avoid name clash (#799)
 
 ### Changed
 - gradients now have there corresponding node as type and not only radial/linear
index 26ddbc79b2911f855f5a35fa56605da62d81eb0d..01c2c45490b56c438eef61dd1060fb2d036ff794 100644 (file)
 * @copyright Wout Fierens <wout@mick-wout.com>
 * @license MIT
 *
-* BUILT: Tue Feb 27 2018 03:37:50 GMT+1100 (AEDT)
+* BUILT: Sat Mar 03 2018 11:57:42 GMT+0100 (Mitteleuropäische Zeit)
 */;
-
-(function(root, factory) {
-  /* istanbul ignore next */
-  if (typeof define === 'function' && define.amd) {
-    define(function(){
-      return factory(root, root.document)
-    })
-  } else if (typeof exports === 'object') {
-    module.exports = root.document ? factory(root, root.document) : function(w){ return factory(w, w.document) }
-  } else {
-    root.SVG = factory(root, root.document)
-  }
-}(typeof window !== "undefined" ? window : this, function(window, document) {
-
-// Check that our browser supports svg
-var supported = !! document.createElementNS &&
-  !! document.createElementNS('http://www.w3.org/2000/svg','svg').createSVGRect
-
-// If we don't support svg, just exit without doing anything
-if (!supported)
-  return {supported: false}
-
-// Otherwise, the library will be here
-/* global createElement, capitalize */
-/* eslint-disable new-cap */
-
-// The main wrapping element
-var SVG = this.SVG = function (element) {
-  if (SVG.supported) {
-    element = createElement(element)
-    return element
-  }
-}
-
-// Svg must be supported if we reached this stage
-SVG.supported = true
-
-// Default namespaces
-SVG.ns = 'http://www.w3.org/2000/svg'
-SVG.xmlns = 'http://www.w3.org/2000/xmlns/'
-SVG.xlink = 'http://www.w3.org/1999/xlink'
-SVG.svgjs = 'http://svgjs.com/svgjs'
-
-// Element id sequence
-SVG.did = 1000
-
-// Get next named element id
-SVG.eid = function (name) {
-  return 'Svgjs' + capitalize(name) + (SVG.did++)
-}
-
-// Method for element creation
-SVG.create = function (name) {
-  // create element
-  return document.createElementNS(this.ns, name)
-}
-
-// Method for extending objects
-SVG.extend = function (modules, methods) {
-  var key, i
-
-  modules = Array.isArray(modules) ? modules : [modules]
-
-  for (i = modules.length - 1; i >= 0; i--) {
-    if (modules[i]) {
-      for (key in methods) {
-        modules[i].prototype[key] = methods[key]
-      }
-    }
-  }
-}
-
-// Invent new element
-SVG.invent = function (config) {
-  // Create element initializer
-  var initializer = typeof config.create === 'function' ? config.create
-    : function (node) {
-      this.constructor(node || SVG.create(config.create))
-    }
-
-  // Inherit prototype
-  if (config.inherit) {
-    initializer.prototype = new config.inherit()
-  }
-
-  // Extend with methods
-  if (config.extend) {
-    SVG.extend(initializer, config.extend)
-  }
-
-  // Attach construct method to parent
-  if (config.construct) { SVG.extend(config.parent || SVG.Container, config.construct) }
-
-  return initializer
-}
-
-// Adopt existing svg elements
-SVG.adopt = function (node) {
-  // check for presence of node
-  if (!node) return null
-
-  // make sure a node isn't already adopted
-  if (node.instance) return node.instance
-
-  if (!(node instanceof window.SVGElement)) {
-    return new SVG.HtmlNode(node)
-  }
-
-  // initialize variables
-  var element
-
-  // adopt with element-specific settings
-  if (node.nodeName === 'svg') {
-    element = node.parentNode instanceof window.SVGElement ? new SVG.Nested(node) : new SVG.Doc(node)
-  } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') {
-    element = new SVG.Gradient(node)
-  } else if (SVG[capitalize(node.nodeName)]) {
-    element = new SVG[capitalize(node.nodeName)](node)
-  } else { element = new SVG.Parent(node) }
-
-  return element
-}
-
-// Storage for regular expressions
-SVG.regex = {
-  // Parse unit value
-  numberAndUnit: /^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,
-
-  // 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+)\)/,
-
-  // Parse reference id
-  reference: /#([a-z0-9\-_]+)/i,
-
-  // splits a transformation chain
-  transforms: /\)\s*,?\s*/,
-
-  // Whitespace
-  whitespace: /\s/g,
-
-  // Test hex value
-  isHex: /^#[a-f0-9]{3,6}$/i,
-
-  // Test rgb value
-  isRgb: /^rgb\(/,
-
-  // Test css declaration
-  isCss: /[^:]+:[^;]+;?/,
-
-  // Test for blank string
-  isBlank: /^(\s+)?$/,
-
-  // Test for numeric string
-  isNumber: /^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,
-
-  // Test for percent value
-  isPercent: /^-?[\d.]+%$/,
-
-  // Test for image url
-  isImage: /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,
-
-  // split at whitespace and comma
-  delimiter: /[\s,]+/,
-
-  // The following regex are used to parse the d attribute of a path
-
-  // Matches all hyphens which are not after an exponent
-  hyphen: /([^e])-/gi,
-
-  // Replaces and tests for all path letters
-  pathLetters: /[MLHVCSQTAZ]/gi,
-
-  // yes we need this one, too
-  isPathLetter: /[MLHVCSQTAZ]/i,
-
-  // matches 0.154.23.45
-  numbersWithDots: /((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,
-
-  // matches .
-  dots: /\./g
-}
-
-SVG.utils = {
-  // Map function
-  map: function (array, block) {
-    var i
-    var il = array.length
-    var result = []
-
-    for (i = 0; i < il; i++) {
-      result.push(block(array[i]))
-    }
-
-    return result
-  },
-
-  // Filter function
-  filter: function (array, block) {
-    var i
-    var il = array.length
-    var result = []
-
-    for (i = 0; i < il; i++) {
-      if (block(array[i])) { result.push(array[i]) }
-    }
-
-    return result
-  },
-
-  // Degrees to radians
-  radians: function (d) {
-    return d % 360 * Math.PI / 180
-  },
-
-  // Radians to degrees
-  degrees: function (r) {
-    return r * 180 / Math.PI % 360
-  },
-
-  filterSVGElements: function (nodes) {
-    return this.filter(nodes, function (el) { return el instanceof window.SVGElement })
-  }
-
-}
-
-
-SVG.defaults = {
-
-  // 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',
-
-    // text
-    'font-size': 16,
-    'font-family': 'Helvetica, Arial, sans-serif',
-    'text-anchor': 'start'
-  }
-}
-
-/* globals fullHex, compToHex */
-
-// Module for color convertions
-SVG.Color = function (color) {
-  var match
-
-  // initialize defaults
-  this.r = 0
-  this.g = 0
-  this.b = 0
-
-  if (!color) return
-
-  // parse color
-  if (typeof color === 'string') {
-    if (SVG.regex.isRgb.test(color)) {
-      // get rgb values
-      match = SVG.regex.rgb.exec(color.replace(SVG.regex.whitespace, ''))
-
-      // 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(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 '#' +
-      compToHex(this.r) +
-      compToHex(this.g) +
-      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)
-  },
-  // Make color morphable
-  morph: function (color) {
-    this.destination = new SVG.Color(color)
-
-    return this
-  },
-  // Get morphed color at given position
-  at: function (pos) {
-    // make sure a destination is defined
-    if (!this.destination) return this
-
-    // normalise pos
-    pos = pos < 0 ? 0 : pos > 1 ? 1 : pos
-
-    // generate morphed color
-    return new SVG.Color({
-      r: ~~(this.r + (this.destination.r - this.r) * pos),
-      g: ~~(this.g + (this.destination.g - this.g) * pos),
-      b: ~~(this.b + (this.destination.b - this.b) * pos)
-    })
-  }
-
-})
-
-// Testers
-
-// 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' &&
-    typeof color.g === 'number' &&
-    typeof color.b === 'number'
-}
-
-// Test if given value is a color
-SVG.Color.isColor = function (color) {
-  return SVG.Color.isRgb(color) || SVG.Color.test(color)
-}
-
-/* global arrayClone */
-
-// Module for array conversion
-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]
-      var 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 () {
-    // find all unique values
-    for (var i = 0, il = this.value.length, seen = []; i < il; i++) {
-      if (seen.indexOf(this.value[i]) === -1) {
-        seen.push(this.value[i])
-      }
-    }
-
-    // set new value
-    this.value = seen
-    return 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 array.trim().split(SVG.regex.delimiter).map(parseFloat)
-  },
-  // Reverse array
-  reverse: function () {
-    this.value.reverse()
-
-    return this
-  },
-  clone: function () {
-    var clone = new this.constructor()
-    clone.value = arrayClone(this.value)
-    return clone
-  }
-})
-
-
-// Poly points array
-SVG.PointArray = function (array, fallback) {
-  SVG.Array.call(this, array, fallback || [[0, 0]])
-}
-
-// Inherit from SVG.Array
-SVG.PointArray.prototype = new SVG.Array()
-SVG.PointArray.prototype.constructor = SVG.PointArray
-
-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(' ')
-  },
-
-  // Convert array to line object
-  toLine: function () {
-    return {
-      x1: this.value[0][0],
-      y1: this.value[0][1],
-      x2: this.value[1][0],
-      y2: this.value[1][1]
-    }
-  },
-
-  // 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 and flat array
-  parse: function (array) {
-    var points = []
-
-    array = array.valueOf()
-
-    // if it is an array
-    if (Array.isArray(array)) {
-      // and it is not flat, there is no need to parse it
-      if (Array.isArray(array[0])) {
-        return array
-      }
-    } else { // Else, it is considered as a string
-      // parse points
-      array = array.trim().split(SVG.regex.delimiter).map(parseFloat)
-    }
-
-    // validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints
-    // Odd number of coordinates is an error. In such cases, drop the last odd coordinate.
-    if (array.length % 2 !== 0) array.pop()
-
-    // wrap points in two-tuples and parse points as floats
-    for (var i = 0, len = array.length; i < len; i = i + 2) {
-      points.push([ array[i], array[i + 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
-    var box = this.bbox()
-
-    // recalculate position of all points according to new size
-    for (i = this.value.length - 1; i >= 0; i--) {
-      if (box.width) this.value[i][0] = ((this.value[i][0] - box.x) * width) / box.width + box.x
-      if (box.height) this.value[i][1] = ((this.value[i][1] - box.y) * height) / box.height + box.y
-    }
-
-    return this
-  },
-
-  // Get bounding box of points
-  bbox: function () {
-    var maxX = -Infinity
-    var maxY = -Infinity
-    var minX = Infinity
-    var minY = Infinity
-    this.value.forEach(function (el) {
-      maxX = Math.max(el[0], maxX)
-      maxY = Math.max(el[1], maxY)
-      minX = Math.min(el[0], minX)
-      minY = Math.min(el[1], minY)
-    })
-    return {x: minX, y: minY, width: maxX - minX, height: maxY - minY}
-  }
-})
-
-/* globals arrayToString, pathRegReplace */
-
-var pathHandlers = {
-  M: function (c, p, p0) {
-    p.x = p0.x = c[0]
-    p.y = p0.y = c[1]
-
-    return ['M', p.x, p.y]
-  },
-  L: function (c, p) {
-    p.x = c[0]
-    p.y = c[1]
-    return ['L', c[0], c[1]]
-  },
-  H: function (c, p) {
-    p.x = c[0]
-    return ['H', c[0]]
-  },
-  V: function (c, p) {
-    p.y = c[0]
-    return ['V', c[0]]
-  },
-  C: function (c, p) {
-    p.x = c[4]
-    p.y = c[5]
-    return ['C', c[0], c[1], c[2], c[3], c[4], c[5]]
-  },
-  S: function (c, p) {
-    p.x = c[2]
-    p.y = c[3]
-    return ['S', c[0], c[1], c[2], c[3]]
-  },
-  Q: function (c, p) {
-    p.x = c[2]
-    p.y = c[3]
-    return ['Q', c[0], c[1], c[2], c[3]]
-  },
-  T: function (c, p) {
-    p.x = c[0]
-    p.y = c[1]
-    return ['T', c[0], c[1]]
-  },
-  Z: function (c, p, p0) {
-    p.x = p0.x
-    p.y = p0.y
-    return ['Z']
-  },
-  A: function (c, p) {
-    p.x = c[5]
-    p.y = c[6]
-    return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]]
-  }
-}
-
-var mlhvqtcsaz = 'mlhvqtcsaz'.split('')
-
-for (var i = 0, il = mlhvqtcsaz.length; i < il; ++i) {
-  pathHandlers[mlhvqtcsaz[i]] = (function (i) {
-    return function (c, p, p0) {
-      if (i === 'H') c[0] = c[0] + p.x
-      else if (i === 'V') c[0] = c[0] + p.y
-      else if (i === 'A') {
-        c[5] = c[5] + p.x
-        c[6] = c[6] + p.y
-      } else {
-        for (var j = 0, jl = c.length; j < jl; ++j) {
-          c[j] = c[j] + (j % 2 ? p.y : p.x)
-        }
-      }
-
-      return pathHandlers[i](c, p, p0)
-    }
-  })(mlhvqtcsaz[i].toUpperCase())
-}
-
-// Path points array
-SVG.PathArray = function (array, fallback) {
-  SVG.Array.call(this, array, fallback || [['M', 0, 0]])
-}
-
-// Inherit from SVG.Array
-SVG.PathArray.prototype = new SVG.Array()
-SVG.PathArray.prototype.constructor = SVG.PathArray
-
-SVG.extend(SVG.PathArray, {
-  // Convert array to string
-  toString: function () {
-    return arrayToString(this.value)
-  },
-  // Move path string
-  move: function (x, y) {
-    // get bounding box of current situation
-    var box = this.bbox()
-
-    // get relative offset
-    x -= box.x
-    y -= box.y
-
-    if (!isNaN(x) && !isNaN(y)) {
-      // move every point
-      for (var l, i = this.value.length - 1; i >= 0; i--) {
-        l = this.value[i][0]
-
-        if (l === 'M' || l === 'L' || l === 'T') {
-          this.value[i][1] += x
-          this.value[i][2] += y
-        } else if (l === 'H') {
-          this.value[i][1] += x
-        } else if (l === 'V') {
-          this.value[i][1] += y
-        } else if (l === 'C' || l === 'S' || l === 'Q') {
-          this.value[i][1] += x
-          this.value[i][2] += y
-          this.value[i][3] += x
-          this.value[i][4] += y
-
-          if (l === 'C') {
-            this.value[i][5] += x
-            this.value[i][6] += y
-          }
-        } else if (l === 'A') {
-          this.value[i][6] += x
-          this.value[i][7] += y
-        }
-      }
-    }
-
-    return this
-  },
-  // Resize path string
-  size: function (width, height) {
-    // get bounding box of current situation
-    var box = this.bbox()
-    var i, l
-
-    // recalculate position of all points according to new size
-    for (i = this.value.length - 1; i >= 0; i--) {
-      l = this.value[i][0]
-
-      if (l === 'M' || l === 'L' || l === 'T') {
-        this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x
-        this.value[i][2] = ((this.value[i][2] - box.y) * height) / box.height + box.y
-      } else if (l === 'H') {
-        this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x
-      } else if (l === 'V') {
-        this.value[i][1] = ((this.value[i][1] - box.y) * height) / box.height + box.y
-      } else if (l === 'C' || l === 'S' || l === 'Q') {
-        this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x
-        this.value[i][2] = ((this.value[i][2] - box.y) * height) / box.height + box.y
-        this.value[i][3] = ((this.value[i][3] - box.x) * width) / box.width + box.x
-        this.value[i][4] = ((this.value[i][4] - box.y) * height) / box.height + box.y
-
-        if (l === 'C') {
-          this.value[i][5] = ((this.value[i][5] - box.x) * width) / box.width + box.x
-          this.value[i][6] = ((this.value[i][6] - box.y) * height) / box.height + box.y
-        }
-      } else if (l === 'A') {
-        // resize radii
-        this.value[i][1] = (this.value[i][1] * width) / box.width
-        this.value[i][2] = (this.value[i][2] * height) / box.height
-
-        // move position values
-        this.value[i][6] = ((this.value[i][6] - box.x) * width) / box.width + box.x
-        this.value[i][7] = ((this.value[i][7] - box.y) * height) / box.height + box.y
-      }
-    }
-
-    return this
-  },
-  // Test if the passed path array use the same path data commands as this path array
-  equalCommands: function (pathArray) {
-    var i, il, equalCommands
-
-    pathArray = new SVG.PathArray(pathArray)
-
-    equalCommands = this.value.length === pathArray.value.length
-    for (i = 0, il = this.value.length; equalCommands && i < il; i++) {
-      equalCommands = this.value[i][0] === pathArray.value[i][0]
-    }
-
-    return equalCommands
-  },
-  // Make path array morphable
-  morph: function (pathArray) {
-    pathArray = new SVG.PathArray(pathArray)
-
-    if (this.equalCommands(pathArray)) {
-      this.destination = pathArray
-    } else {
-      this.destination = null
-    }
-
-    return this
-  },
-  // Get morphed path array at given position
-  at: function (pos) {
-    // make sure a destination is defined
-    if (!this.destination) return this
-
-    var sourceArray = this.value
-    var destinationArray = this.destination.value
-    var array = []
-    var pathArray = new SVG.PathArray()
-    var i, il, j, jl
-
-    // Animate has specified in the SVG spec
-    // See: https://www.w3.org/TR/SVG11/paths.html#PathElement
-    for (i = 0, il = sourceArray.length; i < il; i++) {
-      array[i] = [sourceArray[i][0]]
-      for (j = 1, jl = sourceArray[i].length; j < jl; j++) {
-        array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos
-      }
-      // For the two flags of the elliptical arc command, the SVG spec say:
-      // Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true
-      // Elliptical arc command as an array followed by corresponding indexes:
-      // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
-      //   0    1   2        3                 4             5      6  7
-      if (array[i][0] === 'A') {
-        array[i][4] = +(array[i][4] !== 0)
-        array[i][5] = +(array[i][5] !== 0)
-      }
-    }
-
-    // Directly modify the value of a path array, this is done this way for performance
-    pathArray.value = array
-    return pathArray
-  },
-  // Absolutize and parse path to array
-  parse: function (array) {
-    // if it's already a patharray, no need to parse it
-    if (array instanceof SVG.PathArray) return array.valueOf()
-
-    // prepare for parsing
-    var s
-    var paramCnt = { 'M': 2, 'L': 2, 'H': 1, 'V': 1, 'C': 6, 'S': 4, 'Q': 4, 'T': 2, 'A': 7, 'Z': 0 }
-
-    if (typeof array === 'string') {
-      array = array
-        .replace(SVG.regex.numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
-        .replace(SVG.regex.pathLetters, ' $& ') // put some room between letters and numbers
-        .replace(SVG.regex.hyphen, '$1 -')      // add space before hyphen
-        .trim()                                 // trim
-        .split(SVG.regex.delimiter)   // split into array
-    } else {
-      array = array.reduce(function (prev, curr) {
-        return [].concat.call(prev, curr)
-      }, [])
-    }
-
-    // array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]
-    var result = []
-    var p = new SVG.Point()
-    var p0 = new SVG.Point()
-    var index = 0
-    var len = array.length
-
-    do {
-      // Test if we have a path letter
-      if (SVG.regex.isPathLetter.test(array[index])) {
-        s = array[index]
-        ++index
-      // If last letter was a move command and we got no new, it defaults to [L]ine
-      } else if (s === 'M') {
-        s = 'L'
-      } else if (s === 'm') {
-        s = 'l'
-      }
-
-      result.push(pathHandlers[s].call(null,
-          array.slice(index, (index = index + paramCnt[s.toUpperCase()])).map(parseFloat),
-          p, p0
-        )
-      )
-    } while (len > index)
-
-    return result
-  },
-  // Get bounding box of path
-  bbox: function () {
-    SVG.parser().path.setAttribute('d', this.toString())
-    return SVG.parser.nodes.path.getBBox()
-  }
-
-})
-
-
-// Module for unit convertions
-SVG.Number = SVG.invent({
-  // Initialize
-  create: function (value, unit) {
-    // initialize defaults
-    this.value = 0
-    this.unit = unit || ''
-
-    // parse value
-    if (typeof value === 'number') {
-      // ensure a valid numeric value
-      this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value
-    } else if (typeof value === 'string') {
-      unit = value.match(SVG.regex.numberAndUnit)
-
-      if (unit) {
-        // make value numeric
-        this.value = parseFloat(unit[1])
-
-        // normalize
-        if (unit[5] === '%') { this.value /= 100 } else if (unit[5] === 's') {
-          this.value *= 1000
-        }
-
-        // store unit
-        this.unit = unit[5]
-      }
-    } else {
-      if (value instanceof SVG.Number) {
-        this.value = value.valueOf()
-        this.unit = value.unit
-      }
-    }
-  },
-  // Add methods
-  extend: {
-    // Stringalize
-    toString: function () {
-      return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6
-        : this.unit === 's' ? this.value / 1e3
-        : this.value
-      ) + this.unit
-    },
-    toJSON: function () {
-      return this.toString()
-    },   // Convert to primitive
-    valueOf: function () {
-      return this.value
-    },
-    // Add number
-    plus: function (number) {
-      number = new SVG.Number(number)
-      return new SVG.Number(this + number, this.unit || number.unit)
-    },
-    // Subtract number
-    minus: function (number) {
-      number = new SVG.Number(number)
-      return new SVG.Number(this - number, this.unit || number.unit)
-    },
-    // Multiply number
-    times: function (number) {
-      number = new SVG.Number(number)
-      return new SVG.Number(this * number, this.unit || number.unit)
-    },
-    // Divide number
-    divide: function (number) {
-      number = new SVG.Number(number)
-      return new SVG.Number(this / number, this.unit || number.unit)
-    },
-    // Convert to different unit
-    to: function (unit) {
-      var number = new SVG.Number(this)
-
-      if (typeof unit === 'string') {
-        number.unit = unit
-      }
-
-      return number
-    },
-    // Make number morphable
-    morph: function (number) {
-      this.destination = new SVG.Number(number)
-
-      if (number.relative) {
-        this.destination.value += this.value
-      }
-
-      return this
-    },
-    // Get morphed number at given position
-    at: function (pos) {
-      // Make sure a destination is defined
-      if (!this.destination) return this
-
-      // Generate new morphed number
-      return new SVG.Number(this.destination)
-          .minus(this)
-          .times(pos)
-          .plus(this)
-    }
-
-  }
-})
-
-/* global createElement */
-
-SVG.HtmlNode = SVG.invent({
-  create: function (element) {
-    this.node = element
-  },
-
-  extend: {
-    add: function (element, i) {
-      element = createElement(element)
-      if (element instanceof SVG.Nested) {
-        element = new SVG.Doc(element.node)
-        element.setData(JSON.parse(element.node.getAttribute('svgjs:data')) || {})
-      }
-
-      if (i === null) {
-        this.node.appendChild(element.node)
-      } else if (element.node !== this.node.children[i]) {
-        this.node.insertBefore(element.node, this.node.children[i])
-      }
-
-      return this
-    },
-
-    put: function (element, i) {
-      this.add(element, i)
-      return element
-    }
-  }
-})
-
-/* global proportionalSize, assignNewId, createElement, matches, is */
-
-SVG.Element = SVG.invent({
-  // Initialize node
-  create: function (node) {
-    // last fired event on node
-    this._event = null
-
-    // initialize data object
-    this.dom = {}
-
-    // create circular reference
-    this.node = node
-    if (this.node) {
-      this.type = node.nodeName
-      this.node.instance = this
-
-      if (node.hasAttribute('svgjs:data')) {
-        // pull svgjs data from the dom (getAttributeNS doesn't work in html5)
-        this.setData(JSON.parse(node.getAttribute('svgjs:data')) || {})
-      }
-    }
-  },
-
-  // Add class methods
-  extend: {
-    // Move over x-axis
-    x: function (x) {
-      return this.attr('x', x)
-    },
-
-    // Move over y-axis
-    y: function (y) {
-      return this.attr('y', y)
-    },
-
-    // Move by center over x-axis
-    cx: function (x) {
-      return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2)
-    },
-
-    // Move by center over y-axis
-    cy: function (y) {
-      return y == null ? this.y() + this.height() / 2 : this.y(y - this.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) {
-      var p = proportionalSize(this, width, height)
-
-      return this
-        .width(new SVG.Number(p.width))
-        .height(new SVG.Number(p.height))
-    },
-
-    // Clone element
-    clone: function (parent) {
-      // write dom data to the dom so the clone can pickup the data
-      this.writeDataToDom()
-
-      // clone element and assign new id
-      var clone = assignNewId(this.node.cloneNode(true))
-
-      // insert the clone in the given parent or after myself
-      if (parent) parent.add(clone)
-      else this.after(clone)
-
-      return clone
-    },
-
-    // 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 createElement(parent).put(this)
-    },
-
-    // Add element to given container and return container
-    putIn: function (parent) {
-      return createElement(parent).add(this)
-    },
-
-    // Get / set id
-    id: function (id) {
-      // generate new id if no id set
-      if (typeof id === 'undefined' && !this.node.id) {
-        this.node.id = SVG.eid(this.type)
-      }
-
-      // dont't set directly width this.node.id to make `null` work correctly
-      return this.attr('id', id)
-    },
-
-    // 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.css('display', '')
-    },
-
-    // Hide element
-    hide: function () {
-      return this.css('display', 'none')
-    },
-
-    // Is element visible?
-    visible: function () {
-      return this.css('display') !== 'none'
-    },
-
-    // Return id on string conversion
-    toString: function () {
-      return this.id()
-    },
-
-    // Return array of classes on the node
-    classes: function () {
-      var attr = this.attr('class')
-      return attr == null ? [] : attr.trim().split(SVG.regex.delimiter)
-    },
-
-    // Return true if class exists on the node, false otherwise
-    hasClass: function (name) {
-      return this.classes().indexOf(name) !== -1
-    },
-
-    // Add class to the node
-    addClass: function (name) {
-      if (!this.hasClass(name)) {
-        var array = this.classes()
-        array.push(name)
-        this.attr('class', array.join(' '))
-      }
-
-      return this
-    },
-
-    // Remove class from the node
-    removeClass: function (name) {
-      if (this.hasClass(name)) {
-        this.attr('class', this.classes().filter(function (c) {
-          return c !== name
-        }).join(' '))
-      }
-
-      return this
-    },
-
-    // Toggle the presence of a class on the node
-    toggleClass: function (name) {
-      return this.hasClass(name) ? this.removeClass(name) : this.addClass(name)
-    },
-
-    // Get referenced element form attribute value
-    reference: function (attr) {
-      return SVG.get(this.attr(attr))
-    },
-
-    // Returns the parent element instance
-    parent: function (type) {
-      var parent = this
-
-      // check for parent
-      if (!parent.node.parentNode) return null
-
-      // get parent element
-      parent = SVG.adopt(parent.node.parentNode)
-
-      if (!type) return parent
-
-      // loop trough ancestors if type is given
-      while (parent && parent.node instanceof window.SVGElement) {
-        if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent
-        parent = SVG.adopt(parent.node.parentNode)
-      }
-    },
-
-    // Get parent document
-    doc: function () {
-      return this instanceof SVG.Doc ? this : this.parent(SVG.Doc)
-    },
-
-    // Get defs
-    defs: function () {
-      return this.doc().defs()
-    },
-
-    // return array of all ancestors of given type up to the root svg
-    parents: function (type) {
-      var parents = []
-      var parent = this
-
-      do {
-        parent = parent.parent(type)
-        if (!parent || !parent.node) break
-
-        parents.push(parent)
-      } while (parent.parent)
-
-      return parents
-    },
-
-    // matches the element vs a css selector
-    matches: function (selector) {
-      return matches(this.node, selector)
-    },
-
-    // Returns the svg node to call native svg methods on it
-    native: function () {
-      return this.node
-    },
-
-    // Import raw svg
-    svg: function (svg) {
-      var well, len
-
-      // act as a setter if svg is given
-      if (svg && this instanceof SVG.Parent) {
-        // create temporary holder
-        well = document.createElementNS(SVG.ns, 'svg')
-        // dump raw svg
-        well.innerHTML = svg
-
-        // transplant nodes
-        for (len = well.children.length; len--;) {
-          this.node.appendChild(well.firstElementChild)
-        }
-
-      // otherwise act as a getter
-      } else {
-        // write svgjs data to the dom
-        this.writeDataToDom()
-
-        return this.node.outerHTML
-      }
-
-      return this
-    },
-
-    // write svgjs data to the dom
-    writeDataToDom: function () {
-      // dump variables recursively
-      if (this.is(SVG.Parent)) {
-        this.each(function () {
-          this.writeDataToDom()
-        })
-      }
-
-      // remove previously set data
-      this.node.removeAttribute('svgjs:data')
-
-      if (Object.keys(this.dom).length) {
-        this.node.setAttribute('svgjs:data', JSON.stringify(this.dom)) // see #428
-      }
-      return this
-    },
-
-    // set given data to the elements data property
-    setData: function (o) {
-      this.dom = o
-      return this
-    },
-    is: function (obj) {
-      return is(this, obj)
-    }
-  }
-})
-
-SVG.easing = {
-  '-': function (pos) { return pos },
-  '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },
-  '>': function (pos) { return Math.sin(pos * Math.PI / 2) },
-  '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 }
-}
-
-SVG.morph = function (pos) {
-  return function (from, to) {
-    return new SVG.MorphObj(from, to).at(pos)
-  }
-}
-
-SVG.Situation = SVG.invent({
-
-  create: function (o) {
-    this.init = false
-    this.reversed = false
-    this.reversing = false
-
-    this.duration = new SVG.Number(o.duration).valueOf()
-    this.delay = new SVG.Number(o.delay).valueOf()
-
-    this.start = +new Date() + this.delay
-    this.finish = this.start + this.duration
-    this.ease = o.ease
-
-    // this.loop is incremented from 0 to this.loops
-    // it is also incremented when in an infinite loop (when this.loops is true)
-    this.loop = 0
-    this.loops = false
-
-    this.animations = {
-      // functionToCall: [list of morphable objects]
-      // e.g. move: [SVG.Number, SVG.Number]
-    }
-
-    this.attrs = {
-      // holds all attributes which are not represented from a function svg.js provides
-      // e.g. someAttr: SVG.Number
-    }
-
-    this.styles = {
-      // holds all styles which should be animated
-      // e.g. fill-color: SVG.Color
-    }
-
-    this.transforms = [
-      // holds all transformations as transformation objects
-      // e.g. [SVG.Rotate, SVG.Translate, SVG.Matrix]
-    ]
-
-    this.once = {
-      // functions to fire at a specific position
-      // e.g. "0.5": function foo(){}
-    }
-  }
-
-})
-
-SVG.FX = SVG.invent({
-
-  create: function (element) {
-    this._target = element
-    this.situations = []
-    this.active = false
-    this.situation = null
-    this.paused = false
-    this.lastPos = 0
-    this.pos = 0
-    // The absolute position of an animation is its position in the context of its complete duration (including delay and loops)
-    // When performing a delay, absPos is below 0 and when performing a loop, its value is above 1
-    this.absPos = 0
-    this._speed = 1
-  },
-
-  extend: {
-
-    /**
-     * sets or returns the target of this animation
-     * @param o object || number In case of Object it holds all parameters. In case of number its the duration of the animation
-     * @param ease function || string Function which should be used for easing or easing keyword
-     * @param delay Number indicating the delay before the animation starts
-     * @return target || this
-     */
-    animate: function (o, ease, delay) {
-      if (typeof o === 'object') {
-        ease = o.ease
-        delay = o.delay
-        o = o.duration
-      }
-
-      var situation = new SVG.Situation({
-        duration: o || 1000,
-        delay: delay || 0,
-        ease: SVG.easing[ease || '-'] || ease
-      })
-
-      this.queue(situation)
-
-      return this
-    },
-
-    /**
-     * sets a delay before the next element of the queue is called
-     * @param delay Duration of delay in milliseconds
-     * @return this.target()
-     */
-    delay: function (delay) {
-      // The delay is performed by an empty situation with its duration
-      // attribute set to the duration of the delay
-      var situation = new SVG.Situation({
-        duration: delay,
-        delay: 0,
-        ease: SVG.easing['-']
-      })
-
-      return this.queue(situation)
-    },
-
-    /**
-     * sets or returns the target of this animation
-     * @param null || target SVG.Element which should be set as new target
-     * @return target || this
-     */
-    target: function (target) {
-      if (target && target instanceof SVG.Element) {
-        this._target = target
-        return this
-      }
-
-      return this._target
-    },
-
-    // returns the absolute position at a given time
-    timeToAbsPos: function (timestamp) {
-      return (timestamp - this.situation.start) / (this.situation.duration / this._speed)
-    },
-
-    // returns the timestamp from a given absolute positon
-    absPosToTime: function (absPos) {
-      return this.situation.duration / this._speed * absPos + this.situation.start
-    },
-
-    // starts the animationloop
-    startAnimFrame: function () {
-      this.stopAnimFrame()
-      this.animationFrame = window.requestAnimationFrame(function () { this.step() }.bind(this))
-    },
-
-    // cancels the animationframe
-    stopAnimFrame: function () {
-      window.cancelAnimationFrame(this.animationFrame)
-    },
-
-    // kicks off the animation - only does something when the queue is currently not active and at least one situation is set
-    start: function () {
-      // dont start if already started
-      if (!this.active && this.situation) {
-        this.active = true
-        this.startCurrent()
-      }
-
-      return this
-    },
-
-    // start the current situation
-    startCurrent: function () {
-      this.situation.start = +new Date() + this.situation.delay / this._speed
-      this.situation.finish = this.situation.start + this.situation.duration / this._speed
-      return this.initAnimations().step()
-    },
-
-    /**
-     * adds a function / Situation to the animation queue
-     * @param fn function / situation to add
-     * @return this
-     */
-    queue: function (fn) {
-      if (typeof fn === 'function' || fn instanceof SVG.Situation) {
-        this.situations.push(fn)
-      }
-
-      if (!this.situation) this.situation = this.situations.shift()
-
-      return this
-    },
-
-    /**
-     * pulls next element from the queue and execute it
-     * @return this
-     */
-    dequeue: function () {
-      // stop current animation
-      this.stop()
-
-      // get next animation from queue
-      this.situation = this.situations.shift()
-
-      if (this.situation) {
-        if (this.situation instanceof SVG.Situation) {
-          this.start()
-        } else {
-          // If it is not a SVG.Situation, then it is a function, we execute it
-          this.situation(this)
-        }
-      }
-
-      return this
-    },
-
-    // updates all animations to the current state of the element
-    // this is important when one property could be changed from another property
-    initAnimations: function () {
-      var i, j, source
-      var s = this.situation
-
-      if (s.init) return this
-
-      for (i in s.animations) {
-        source = this.target()[i]()
-
-        if (!Array.isArray(source)) {
-          source = [source]
-        }
-
-        if (!Array.isArray(s.animations[i])) {
-          s.animations[i] = [s.animations[i]]
-        }
-
-        // if(s.animations[i].length > source.length) {
-        //  source.concat = source.concat(s.animations[i].slice(source.length, s.animations[i].length))
-        // }
-
-        for (j = source.length; j--;) {
-          // The condition is because some methods return a normal number instead
-          // of a SVG.Number
-          if (s.animations[i][j] instanceof SVG.Number) {
-            source[j] = new SVG.Number(source[j])
-          }
-
-          s.animations[i][j] = source[j].morph(s.animations[i][j])
-        }
-      }
-
-      for (i in s.attrs) {
-        s.attrs[i] = new SVG.MorphObj(this.target().attr(i), s.attrs[i])
-      }
-
-      for (i in s.styles) {
-        s.styles[i] = new SVG.MorphObj(this.target().css(i), s.styles[i])
-      }
-
-      s.initialTransformation = this.target().matrixify()
-
-      s.init = true
-      return this
-    },
-
-    clearQueue: function () {
-      this.situations = []
-      return this
-    },
-
-    clearCurrent: function () {
-      this.situation = null
-      return this
-    },
-
-    /** stops the animation immediately
-     * @param jumpToEnd A Boolean indicating whether to complete the current animation immediately.
-     * @param clearQueue A Boolean indicating whether to remove queued animation as well.
-     * @return this
-     */
-    stop: function (jumpToEnd, clearQueue) {
-      var active = this.active
-      this.active = false
-
-      if (clearQueue) {
-        this.clearQueue()
-      }
-
-      if (jumpToEnd && this.situation) {
-        // initialize the situation if it was not
-        !active && this.startCurrent()
-        this.atEnd()
-      }
-
-      this.stopAnimFrame()
-
-      return this.clearCurrent()
-    },
-
-    /** resets the element to the state where the current element has started
-     * @return this
-     */
-    reset: function () {
-      if (this.situation) {
-        var temp = this.situation
-        this.stop()
-        this.situation = temp
-        this.atStart()
-      }
-      return this
-    },
-
-    // Stop the currently-running animation, remove all queued animations, and complete all animations for the element.
-    finish: function () {
-      this.stop(true, false)
-
-      while (this.dequeue().situation && this.stop(true, false));
-
-      this.clearQueue().clearCurrent()
-
-      return this
-    },
-
-    // set the internal animation pointer at the start position, before any loops, and updates the visualisation
-    atStart: function () {
-      return this.at(0, true)
-    },
-
-    // set the internal animation pointer at the end position, after all the loops, and updates the visualisation
-    atEnd: function () {
-      if (this.situation.loops === true) {
-        // If in a infinite loop, we end the current iteration
-        this.situation.loops = this.situation.loop + 1
-      }
-
-      if (typeof this.situation.loops === 'number') {
-        // If performing a finite number of loops, we go after all the loops
-        return this.at(this.situation.loops, true)
-      } else {
-        // If no loops, we just go at the end
-        return this.at(1, true)
-      }
-    },
-
-    // set the internal animation pointer to the specified position and updates the visualisation
-    // if isAbsPos is true, pos is treated as an absolute position
-    at: function (pos, isAbsPos) {
-      var durDivSpd = this.situation.duration / this._speed
-
-      this.absPos = pos
-      // If pos is not an absolute position, we convert it into one
-      if (!isAbsPos) {
-        if (this.situation.reversed) this.absPos = 1 - this.absPos
-        this.absPos += this.situation.loop
-      }
-
-      this.situation.start = +new Date() - this.absPos * durDivSpd
-      this.situation.finish = this.situation.start + durDivSpd
-
-      return this.step(true)
-    },
-
-    /**
-     * sets or returns the speed of the animations
-     * @param speed null || Number The new speed of the animations
-     * @return Number || this
-     */
-    speed: function (speed) {
-      if (speed === 0) return this.pause()
-
-      if (speed) {
-        this._speed = speed
-        // We use an absolute position here so that speed can affect the delay before the animation
-        return this.at(this.absPos, true)
-      } else return this._speed
-    },
-
-    // Make loopable
-    loop: function (times, reverse) {
-      var c = this.last()
-
-      // store total loops
-      c.loops = (times != null) ? times : true
-      c.loop = 0
-
-      if (reverse) c.reversing = true
-      return this
-    },
-
-    // pauses the animation
-    pause: function () {
-      this.paused = true
-      this.stopAnimFrame()
-
-      return this
-    },
-
-    // unpause the animation
-    play: function () {
-      if (!this.paused) return this
-      this.paused = false
-      // We use an absolute position here so that the delay before the animation can be paused
-      return this.at(this.absPos, true)
-    },
-
-    /**
-     * toggle or set the direction of the animation
-     * true sets direction to backwards while false sets it to forwards
-     * @param reversed Boolean indicating whether to reverse the animation or not (default: toggle the reverse status)
-     * @return this
-     */
-    reverse: function (reversed) {
-      var c = this.last()
-
-      if (typeof reversed === 'undefined') c.reversed = !c.reversed
-      else c.reversed = reversed
-
-      return this
-    },
-
-    /**
-     * returns a float from 0-1 indicating the progress of the current animation
-     * @param eased Boolean indicating whether the returned position should be eased or not
-     * @return number
-     */
-    progress: function (easeIt) {
-      return easeIt ? this.situation.ease(this.pos) : this.pos
-    },
-
-    /**
-     * adds a callback function which is called when the current animation is finished
-     * @param fn Function which should be executed as callback
-     * @return number
-     */
-    after: function (fn) {
-      var c = this.last()
-      function wrapper (e) {
-        if (e.detail.situation === c) {
-          fn.call(this, c)
-          this.off('finished.fx', wrapper) // prevent memory leak
-        }
-      }
-
-      this.target().on('finished.fx', wrapper)
-
-      return this._callStart()
-    },
-
-    // adds a callback which is called whenever one animation step is performed
-    during: function (fn) {
-      var c = this.last()
-      function wrapper (e) {
-        if (e.detail.situation === c) {
-          fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, c)
-        }
-      }
-
-      // see above
-      this.target().off('during.fx', wrapper).on('during.fx', wrapper)
-
-      this.after(function () {
-        this.off('during.fx', wrapper)
-      })
-
-      return this._callStart()
-    },
-
-    // calls after ALL animations in the queue are finished
-    afterAll: function (fn) {
-      var wrapper = function wrapper (e) {
-        fn.call(this)
-        this.off('allfinished.fx', wrapper)
-      }
-
-      // see above
-      this.target().off('allfinished.fx', wrapper).on('allfinished.fx', wrapper)
-
-      return this._callStart()
-    },
-
-    // calls on every animation step for all animations
-    duringAll: function (fn) {
-      var wrapper = function (e) {
-        fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, e.detail.situation)
-      }
-
-      this.target().off('during.fx', wrapper).on('during.fx', wrapper)
-
-      this.afterAll(function () {
-        this.off('during.fx', wrapper)
-      })
-
-      return this._callStart()
-    },
-
-    last: function () {
-      return this.situations.length ? this.situations[this.situations.length - 1] : this.situation
-    },
-
-    // adds one property to the animations
-    add: function (method, args, type) {
-      this.last()[type || 'animations'][method] = args
-      return this._callStart()
-    },
-
-    /** perform one step of the animation
-     *  @param ignoreTime Boolean indicating whether to ignore time and use position directly or recalculate position based on time
-     *  @return this
-     */
-    step: function (ignoreTime) {
-      // convert current time to an absolute position
-      if (!ignoreTime) this.absPos = this.timeToAbsPos(+new Date())
-
-      // This part convert an absolute position to a position
-      if (this.situation.loops !== false) {
-        var absPos, absPosInt, lastLoop
-
-        // If the absolute position is below 0, we just treat it as if it was 0
-        absPos = Math.max(this.absPos, 0)
-        absPosInt = Math.floor(absPos)
-
-        if (this.situation.loops === true || absPosInt < this.situation.loops) {
-          this.pos = absPos - absPosInt
-          lastLoop = this.situation.loop
-          this.situation.loop = absPosInt
-        } else {
-          this.absPos = this.situation.loops
-          this.pos = 1
-          // The -1 here is because we don't want to toggle reversed when all the loops have been completed
-          lastLoop = this.situation.loop - 1
-          this.situation.loop = this.situation.loops
-        }
-
-        if (this.situation.reversing) {
-          // Toggle reversed if an odd number of loops as occured since the last call of step
-          this.situation.reversed = this.situation.reversed !== Boolean((this.situation.loop - lastLoop) % 2)
-        }
-      } else {
-        // If there are no loop, the absolute position must not be above 1
-        this.absPos = Math.min(this.absPos, 1)
-        this.pos = this.absPos
-      }
-
-      // while the absolute position can be below 0, the position must not be below 0
-      if (this.pos < 0) this.pos = 0
-
-      if (this.situation.reversed) this.pos = 1 - this.pos
-
-      // apply easing
-      var eased = this.situation.ease(this.pos)
-
-      // call once-callbacks
-      for (var i in this.situation.once) {
-        if (i > this.lastPos && i <= eased) {
-          this.situation.once[i].call(this.target(), this.pos, eased)
-          delete this.situation.once[i]
-        }
-      }
-
-      // fire during callback with position, eased position and current situation as parameter
-      if (this.active) this.target().fire('during', {pos: this.pos, eased: eased, fx: this, situation: this.situation})
-
-      // the user may call stop or finish in the during callback
-      // so make sure that we still have a valid situation
-      if (!this.situation) {
-        return this
-      }
-
-      // apply the actual animation to every property
-      this.eachAt()
-
-      // do final code when situation is finished
-      if ((this.pos === 1 && !this.situation.reversed) || (this.situation.reversed && this.pos === 0)) {
-        // stop animation callback
-        this.stopAnimFrame()
-
-        // fire finished callback with current situation as parameter
-        this.target().fire('finished', {fx: this, situation: this.situation})
-
-        if (!this.situations.length) {
-          this.target().fire('allfinished')
-
-          // Recheck the length since the user may call animate in the afterAll callback
-          if (!this.situations.length) {
-            this.target().off('.fx') // there shouldnt be any binding left, but to make sure...
-            this.active = false
-          }
-        }
-
-        // start next animation
-        if (this.active) this.dequeue()
-        else this.clearCurrent()
-      } else if (!this.paused && this.active) {
-        // we continue animating when we are not at the end
-        this.startAnimFrame()
-      }
-
-      // save last eased position for once callback triggering
-      this.lastPos = eased
-      return this
-    },
-
-    // calculates the step for every property and calls block with it
-    eachAt: function () {
-      var i, len, at
-      var self = this
-      var target = this.target()
-      var s = this.situation
-
-      // apply animations which can be called trough a method
-      for (i in s.animations) {
-        at = [].concat(s.animations[i]).map(function (el) {
-          return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el
-        })
-
-        target[i].apply(target, at)
-      }
-
-      // apply animation which has to be applied with attr()
-      for (i in s.attrs) {
-        at = [i].concat(s.attrs[i]).map(function (el) {
-          return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el
-        })
-
-        target.attr.apply(target, at)
-      }
-
-      // apply animation which has to be applied with css()
-      for (i in s.styles) {
-        at = [i].concat(s.styles[i]).map(function (el) {
-          return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el
-        })
-
-        target.css.apply(target, at)
-      }
-
-      // animate initialTransformation which has to be chained
-      if (s.transforms.length) {
-        // get initial initialTransformation
-        at = s.initialTransformation
-        for (i = 0, len = s.transforms.length; i < len; i++) {
-          // get next transformation in chain
-          var a = s.transforms[i]
-
-          // multiply matrix directly
-          if (a instanceof SVG.Matrix) {
-            if (a.relative) {
-              at = at.multiply(new SVG.Matrix().morph(a).at(s.ease(this.pos)))
-            } else {
-              at = at.morph(a).at(s.ease(this.pos))
-            }
-            continue
-          }
-
-          // when transformation is absolute we have to reset the needed transformation first
-          if (!a.relative) {
-            a.undo(at.extract())
-          }
-
-          // and reapply it after
-          at = at.multiply(a.at(s.ease(this.pos)))
-        }
-
-        // set new matrix on element
-        target.matrix(at)
-      }
-
-      return this
-    },
-
-    // adds an once-callback which is called at a specific position and never again
-    once: function (pos, fn, isEased) {
-      var c = this.last()
-      if (!isEased) pos = c.ease(pos)
-
-      c.once[pos] = fn
-
-      return this
-    },
-
-    _callStart: function () {
-      setTimeout(function () { this.start() }.bind(this), 0)
-      return this
-    }
-
-  },
-
-  parent: SVG.Element,
-
-  // Add method to parent elements
-  construct: {
-    // Get fx module or create a new one, then animate with given duration and ease
-    animate: function (o, ease, delay) {
-      return (this.fx || (this.fx = new SVG.FX(this))).animate(o, ease, delay)
-    },
-    delay: function (delay) {
-      return (this.fx || (this.fx = new SVG.FX(this))).delay(delay)
-    },
-    stop: function (jumpToEnd, clearQueue) {
-      if (this.fx) {
-        this.fx.stop(jumpToEnd, clearQueue)
-      }
-
-      return this
-    },
-    finish: function () {
-      if (this.fx) {
-        this.fx.finish()
-      }
-
-      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
-    },
-    // Set/Get the speed of the animations
-    speed: function (speed) {
-      if (this.fx) {
-        if (speed == null) { return this.fx.speed() } else { this.fx.speed(speed) }
-      }
-
-      return this
-    }
-  }
-
-})
-
-// MorphObj is used whenever no morphable object is given
-SVG.MorphObj = SVG.invent({
-
-  create: function (from, to) {
-    // prepare color for morphing
-    if (SVG.Color.isColor(to)) return new SVG.Color(from).morph(to)
-    // prepare value list for morphing
-    if (SVG.regex.delimiter.test(from)) return new SVG.Array(from).morph(to)
-    // prepare number for morphing
-    if (SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to)
-
-    // prepare for plain morphing
-    this.value = from
-    this.destination = to
-  },
-
-  extend: {
-    at: function (pos, real) {
-      return real < 1 ? this.value : this.destination
-    },
-
-    valueOf: function () {
-      return this.value
-    }
-  }
-
-})
-
-SVG.extend(SVG.FX, {
-  // Add animatable attributes
-  attr: function (a, v, relative) {
-    // apply attributes individually
-    if (typeof a === 'object') {
-      for (var key in a) {
-        this.attr(key, a[key])
-      }
-    } else {
-      this.add(a, v, 'attrs')
-    }
-
-    return this
-  },
-  // Add animatable styles
-  css: function (s, v) {
-    if (typeof s === 'object') {
-      for (var key in s) {
-        this.css(key, s[key])
-      }
-    } else {
-      this.add(s, v, 'styles')
-    }
-
-    return this
-  },
-  // Animatable x-axis
-  x: function (x, relative) {
-    if (this.target() instanceof SVG.G) {
-      this.transform({x: x}, relative)
-      return this
-    }
-
-    var num = new SVG.Number(x)
-    num.relative = relative
-    return this.add('x', num)
-  },
-  // Animatable y-axis
-  y: function (y, relative) {
-    if (this.target() instanceof SVG.G) {
-      this.transform({y: y}, relative)
-      return this
-    }
-
-    var num = new SVG.Number(y)
-    num.relative = relative
-    return this.add('y', num)
-  },
-  // Animatable center x-axis
-  cx: function (x) {
-    return this.add('cx', new SVG.Number(x))
-  },
-  // Animatable center y-axis
-  cy: function (y) {
-    return this.add('cy', new SVG.Number(y))
-  },
-  // 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
-
-      if (!width || !height) {
-        box = this.target().bbox()
-      }
-
-      if (!width) {
-        width = box.width / box.height * height
-      }
-
-      if (!height) {
-        height = box.height / box.width * width
-      }
-
-      this.add('width', new SVG.Number(width))
-          .add('height', new SVG.Number(height))
-    }
-
-    return this
-  },
-  // Add animatable width
-  width: function (width) {
-    return this.add('width', new SVG.Number(width))
-  },
-  // Add animatable height
-  height: function (height) {
-    return this.add('height', new SVG.Number(height))
-  },
-  // Add animatable plot
-  plot: function (a, b, c, d) {
-    // Lines can be plotted with 4 arguments
-    if (arguments.length === 4) {
-      return this.plot([a, b, c, d])
-    }
-
-    return this.add('plot', new (this.target().MorphArray)(a))
-  },
-  // Add leading method
-  leading: function (value) {
-    return this.target().leading
-      ? this.add('leading', new SVG.Number(value))
-      : this
-  },
-  // Add animatable viewbox
-  viewbox: function (x, y, width, height) {
-    if (this.target() instanceof SVG.Container) {
-      this.add('viewbox', new SVG.Box(x, y, width, height))
-    }
-
-    return this
-  },
-  update: function (o) {
-    if (this.target() instanceof SVG.Stop) {
-      if (typeof o === 'number' || o instanceof SVG.Number) {
-        return this.update({
-          offset: arguments[0],
-          color: arguments[1],
-          opacity: arguments[2]
-        })
-      }
-
-      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', o.offset)
-    }
-
-    return this
-  }
-})
-
-/* global abcdef, arrayToMatrix, deltaTransformPoint, parseMatrix */
-
-SVG.Matrix = SVG.invent({
-  // Initialize
-  create: function (source) {
-    var base = arrayToMatrix([1, 0, 0, 1, 0, 0])
-    var i
-
-    // ensure source as object
-    source = source instanceof SVG.Element ? source.matrixify()
-      : typeof source === 'string' ? arrayToMatrix(source.split(SVG.regex.delimiter).map(parseFloat))
-      : arguments.length === 6 ? arrayToMatrix([].slice.call(arguments))
-      : Array.isArray(source) ? arrayToMatrix(source)
-      : typeof source === 'object' ? source
-      : base
-
-    // merge source
-    for (i = abcdef.length - 1; i >= 0; --i) {
-      this[abcdef[i]] = source[abcdef[i]] != null
-        ? source[abcdef[i]]
-        : base[abcdef[i]]
-    }
-  },
-
-  // Add methods
-  extend: {
-    // Extract individual transformations
-    extract: function () {
-      // find delta transform points
-      var px = deltaTransformPoint(this, 0, 1)
-      var py = deltaTransformPoint(this, 1, 0)
-      var skewX = 180 / Math.PI * Math.atan2(px.y, px.x) - 90
-
-      return {
-        // translation
-        x: this.e,
-        y: this.f,
-        transformedX: (this.e * Math.cos(skewX * Math.PI / 180) + this.f * Math.sin(skewX * Math.PI / 180)) / Math.sqrt(this.a * this.a + this.b * this.b),
-        transformedY: (this.f * Math.cos(skewX * Math.PI / 180) + this.e * Math.sin(-skewX * Math.PI / 180)) / Math.sqrt(this.c * this.c + this.d * this.d),
-        // skew
-        skewX: -skewX,
-        skewY: 180 / Math.PI * Math.atan2(py.y, py.x),
-        // scale
-        scaleX: Math.sqrt(this.a * this.a + this.b * this.b),
-        scaleY: Math.sqrt(this.c * this.c + this.d * this.d),
-        // rotation
-        rotation: skewX,
-        a: this.a,
-        b: this.b,
-        c: this.c,
-        d: this.d,
-        e: this.e,
-        f: this.f,
-        matrix: new SVG.Matrix(this)
-      }
-    },
-    // Clone matrix
-    clone: function () {
-      return new SVG.Matrix(this)
-    },
-    // Morph one matrix into another
-    morph: function (matrix) {
-      // store new destination
-      this.destination = new SVG.Matrix(matrix)
-
-      return this
-    },
-    // Get morphed matrix at a given position
-    at: function (pos) {
-      // make sure a destination is defined
-      if (!this.destination) return this
-
-      // calculate morphed matrix at a given position
-      var matrix = new SVG.Matrix({
-        a: this.a + (this.destination.a - this.a) * pos,
-        b: this.b + (this.destination.b - this.b) * pos,
-        c: this.c + (this.destination.c - this.c) * pos,
-        d: this.d + (this.destination.d - this.d) * pos,
-        e: this.e + (this.destination.e - this.e) * pos,
-        f: this.f + (this.destination.f - this.f) * pos
-      })
-
-      return matrix
-    },
-    // Multiplies by given matrix
-    multiply: function (matrix) {
-      return new SVG.Matrix(this.native().multiply(parseMatrix(matrix).native()))
-    },
-    // Inverses matrix
-    inverse: function () {
-      return new SVG.Matrix(this.native().inverse())
-    },
-    // Translate matrix
-    translate: function (x, y) {
-      return new SVG.Matrix(this.native().translate(x || 0, y || 0))
-    },
-    // Scale matrix
-    scale: function (x, y, cx, cy) {
-      // support uniformal scale
-      if (arguments.length === 1) {
-        y = x
-      } else if (arguments.length === 3) {
-        cy = cx
-        cx = y
-        y = x
-      }
-
-      return this.around(cx, cy, new SVG.Matrix(x, 0, 0, y, 0, 0))
-    },
-    // Rotate matrix
-    rotate: function (r, cx, cy) {
-      // convert degrees to radians
-      r = SVG.utils.radians(r)
-
-      return this.around(cx, cy, new SVG.Matrix(Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0, 0))
-    },
-    // Flip matrix on x or y, at a given offset
-    flip: function (a, o) {
-      return a === 'x' ? this.scale(-1, 1, o, 0)
-        : a === 'y' ? this.scale(1, -1, 0, o)
-        : this.scale(-1, -1, a, o != null ? o : a)
-    },
-    // Skew
-    skew: function (x, y, cx, cy) {
-      // support uniformal skew
-      if (arguments.length === 1) {
-        y = x
-      } else if (arguments.length === 3) {
-        cy = cx
-        cx = y
-        y = x
-      }
-
-      // convert degrees to radians
-      x = SVG.utils.radians(x)
-      y = SVG.utils.radians(y)
-
-      return this.around(cx, cy, new SVG.Matrix(1, Math.tan(y), Math.tan(x), 1, 0, 0))
-    },
-    // SkewX
-    skewX: function (x, cx, cy) {
-      return this.skew(x, 0, cx, cy)
-    },
-    // SkewY
-    skewY: function (y, cx, cy) {
-      return this.skew(0, y, cx, cy)
-    },
-    // Transform around a center point
-    around: function (cx, cy, matrix) {
-      return this
-        .multiply(new SVG.Matrix(1, 0, 0, 1, cx || 0, cy || 0))
-        .multiply(matrix)
-        .multiply(new SVG.Matrix(1, 0, 0, 1, -cx || 0, -cy || 0))
-    },
-    // Convert to native SVGMatrix
-    native: function () {
-      // create new matrix
-      var matrix = SVG.parser.nodes.svg.node.createSVGMatrix()
-
-      // update with current values
-      for (var i = abcdef.length - 1; i >= 0; i--) {
-        matrix[abcdef[i]] = this[abcdef[i]]
-      }
-
-      return matrix
-    },
-    // Convert matrix to string
-    toString: function () {
-      return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')'
-    }
-  },
-
-  // Define parent
-  parent: SVG.Element,
-
-  // Add parent method
-  construct: {
-    // Get current matrix
-    ctm: function () {
-      return new SVG.Matrix(this.node.getCTM())
-    },
-    // Get current screen matrix
-    screenCTM: function () {
-      /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537
-         This is needed because FF does not return the transformation matrix
-         for the inner coordinate system when getScreenCTM() is called on nested svgs.
-         However all other Browsers do that */
-      if (this instanceof SVG.Nested) {
-        var rect = this.rect(1, 1)
-        var m = rect.node.getScreenCTM()
-        rect.remove()
-        return new SVG.Matrix(m)
-      }
-      return new SVG.Matrix(this.node.getScreenCTM())
-    }
-  }
-})
-
-
-SVG.Point = SVG.invent({
-  // Initialize
-  create: function (x, y) {
-    var base = {x: 0, y: 0}
-    var source
-
-    // ensure source as object
-    source = Array.isArray(x) ? {x: x[0], y: x[1]}
-      : typeof x === 'object' ? {x: x.x, y: x.y}
-      : x != null ? {x: x, y: (y != null ? y : x)}
-      : base // If y has no value, then x is used has its value
-
-    // merge source
-    this.x = source.x
-    this.y = source.y
-  },
-
-  // Add methods
-  extend: {
-    // Clone point
-    clone: function () {
-      return new SVG.Point(this)
-    },
-    // Morph one point into another
-    morph: function (x, y) {
-      // store new destination
-      this.destination = new SVG.Point(x, y)
-
-      return this
-    },
-    // Get morphed point at a given position
-    at: function (pos) {
-      // make sure a destination is defined
-      if (!this.destination) return this
-
-      // calculate morphed matrix at a given position
-      var point = new SVG.Point({
-        x: this.x + (this.destination.x - this.x) * pos,
-        y: this.y + (this.destination.y - this.y) * pos
-      })
-
-      return point
-    },
-    // Convert to native SVGPoint
-    native: function () {
-      // create new point
-      var point = SVG.parser.nodes.svg.node.createSVGPoint()
-
-      // update with current values
-      point.x = this.x
-      point.y = this.y
-
-      return point
-    },
-    // transform point with matrix
-    transform: function (matrix) {
-      return new SVG.Point(this.native().matrixTransform(matrix.native()))
-    }
-  }
-})
-
-SVG.extend(SVG.Element, {
-
-  // Get point
-  point: function (x, y) {
-    return new SVG.Point(x, y).transform(this.screenCTM().inverse())
-  }
-
-})
-
-SVG.extend(SVG.Element, {
-  // Set svg element attribute
-  attr: function (a, v, n) {
-    // act as full getter
-    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.isNumber.test(v[n].nodeValue)
-          ? 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 if the first and only argument is not an object
-      v = this.node.getAttribute(a)
-      return v == null ? SVG.defaults.attrs[a]
-        : SVG.regex.isNumber.test(v) ? parseFloat(v)
-        : v
-    } else {
-      // convert image fill and stroke to patterns
-      if (a === 'fill' || a === 'stroke') {
-        if (SVG.regex.isImage.test(v)) {
-          v = this.doc().defs().image(v)
-        }
-
-        if (v instanceof SVG.Image) {
-          v = this.doc().defs().pattern(0, 0, function () {
-            this.add(v)
-          })
-        }
-      }
-
-      // ensure correct numeric values (also accepts NaN and Infinity)
-      if (typeof v === 'number') {
-        v = new SVG.Number(v)
-      } else if (SVG.Color.isColor(v)) {
-        // ensure full hex color
-        v = new SVG.Color(v)
-      } else if (Array.isArray(v)) {
-        // parse array values
-        v = new SVG.Array(v)
-      }
-
-      // if the passed attribute is leading...
-      if (a === 'leading') {
-        // ... call the leading method instead
-        if (this.leading) {
-          this.leading(v)
-        }
-      } else {
-        // set given attribute on node
-        typeof n === 'string' ? this.node.setAttributeNS(n, a, v.toString())
-          : this.node.setAttribute(a, v.toString())
-      }
-
-      // rebuild if required
-      if (this.rebuild && (a === 'font-size' || a === 'x')) {
-        this.rebuild(a, v)
-      }
-    }
-
-    return this
-  }
-})
-
-/* global ensureCentre, capitalize, arrayToMatrix */
-
-SVG.extend(SVG.Element, {
-  // Add transformations
-  transform: function (o, relative) {
-    // get target in case of the fx module, otherwise reference this
-    var target = this
-    var matrix, bbox
-
-    // act as a getter
-    if (typeof o !== 'object') {
-      // get current matrix
-      matrix = new SVG.Matrix(target).extract()
-
-      return typeof o === 'string' ? matrix[o] : matrix
-    }
-
-    // get current matrix
-    matrix = new SVG.Matrix(target)
-
-    // ensure relative flag
-    relative = !!relative || !!o.relative
-
-    // act on matrix
-    if (o.a != null) {
-      matrix = relative
-        ? matrix.multiply(new SVG.Matrix(o))
-        : new SVG.Matrix(o)
-
-    // act on rotation
-    } else if (o.rotation != null) {
-      // ensure centre point
-      ensureCentre(o, target)
-
-      // apply transformation
-      matrix = relative
-        ? matrix.rotate(o.rotation, o.cx, o.cy)
-        : matrix.rotate(o.rotation - matrix.extract().rotation, o.cx, o.cy)
-
-    // act on scale
-    } else if (o.scale != null || o.scaleX != null || o.scaleY != null) {
-      // ensure centre point
-      ensureCentre(o, target)
-
-      // ensure scale values on both axes
-      o.scaleX = o.scale != null ? o.scale : o.scaleX != null ? o.scaleX : 1
-      o.scaleY = o.scale != null ? o.scale : o.scaleY != null ? o.scaleY : 1
-
-      if (!relative) {
-        // absolute; multiply inversed values
-        var e = matrix.extract()
-        o.scaleX = o.scaleX * 1 / e.scaleX
-        o.scaleY = o.scaleY * 1 / e.scaleY
-      }
-
-      matrix = matrix.scale(o.scaleX, o.scaleY, o.cx, o.cy)
-
-    // act on skew
-    } else if (o.skew != null || o.skewX != null || o.skewY != null) {
-      // ensure centre point
-      ensureCentre(o, target)
-
-      // ensure skew values on both axes
-      o.skewX = o.skew != null ? o.skew : o.skewX != null ? o.skewX : 0
-      o.skewY = o.skew != null ? o.skew : o.skewY != null ? o.skewY : 0
-
-      if (!relative) {
-        // absolute; reset skew values
-        var el = matrix.extract()
-        matrix = matrix.multiply(new SVG.Matrix().skew(el.skewX, el.skewY, el.cx, el.cy).inverse())
-      }
-
-      matrix = matrix.skew(o.skewX, o.skewY, o.cx, o.cy)
-
-    // act on flip
-    } else if (o.flip) {
-      if (o.flip === 'x' || o.flip === 'y') {
-        o.offset = o.offset == null ? target.bbox()['c' + o.flip] : o.offset
-      } else {
-        if (o.offset == null) {
-          bbox = target.bbox()
-          o.flip = bbox.cx
-          o.offset = bbox.cy
-        } else {
-          o.flip = o.offset
-        }
-      }
-
-      matrix = new SVG.Matrix().flip(o.flip, o.offset)
-
-    // act on translate
-    } else if (o.x != null || o.y != null) {
-      if (relative) {
-        // relative
-        matrix = matrix.translate(o.x, o.y)
-      } else {
-        // absolute
-        if (o.x != null) matrix.e = o.x
-        if (o.y != null) matrix.f = o.y
-      }
-    }
-
-    return this.attr('transform', matrix)
-  }
-})
-
-SVG.extend(SVG.FX, {
-  transform: function (o, relative) {
-    // get target in case of the fx module, otherwise reference this
-    var target = this.target()
-    var matrix, bbox
-
-    // act as a getter
-    if (typeof o !== 'object') {
-      // get current matrix
-      matrix = new SVG.Matrix(target).extract()
-      return typeof o === 'string' ? matrix[o] : matrix
-    }
-
-    // ensure relative flag
-    relative = !!relative || !!o.relative
-
-    // act on matrix
-    if (o.a != null) {
-      matrix = new SVG.Matrix(o)
-
-    // act on rotation
-    } else if (o.rotation != null) {
-      // ensure centre point
-      ensureCentre(o, target)
-
-      // apply transformation
-      matrix = new SVG.Rotate(o.rotation, o.cx, o.cy)
-
-    // act on scale
-    } else if (o.scale != null || o.scaleX != null || o.scaleY != null) {
-      // ensure centre point
-      ensureCentre(o, target)
-
-      // ensure scale values on both axes
-      o.scaleX = o.scale != null ? o.scale : o.scaleX != null ? o.scaleX : 1
-      o.scaleY = o.scale != null ? o.scale : o.scaleY != null ? o.scaleY : 1
-
-      matrix = new SVG.Scale(o.scaleX, o.scaleY, o.cx, o.cy)
-
-    // act on skew
-    } else if (o.skewX != null || o.skewY != null) {
-      // ensure centre point
-      ensureCentre(o, target)
-
-      // ensure skew values on both axes
-      o.skewX = o.skewX != null ? o.skewX : 0
-      o.skewY = o.skewY != null ? o.skewY : 0
-
-      matrix = new SVG.Skew(o.skewX, o.skewY, o.cx, o.cy)
-
-    // act on flip
-    } else if (o.flip) {
-      if (o.flip === 'x' || o.flip === 'y') {
-        o.offset = o.offset == null ? target.bbox()['c' + o.flip] : o.offset
-      } else {
-        if (o.offset == null) {
-          bbox = target.bbox()
-          o.flip = bbox.cx
-          o.offset = bbox.cy
-        } else {
-          o.flip = o.offset
-        }
-      }
-
-      matrix = new SVG.Matrix().flip(o.flip, o.offset)
-
-    // act on translate
-    } else if (o.x != null || o.y != null) {
-      matrix = new SVG.Translate(o.x, o.y)
-    }
-
-    if (!matrix) return this
-
-    matrix.relative = relative
-
-    this.last().transforms.push(matrix)
-
-    return this._callStart()
-  }
-})
-
-SVG.extend(SVG.Element, {
-  // Reset all transformations
-  untransform: function () {
-    return this.attr('transform', null)
-  },
-  // merge the whole transformation chain into one matrix and returns it
-  matrixify: function () {
-    var matrix = (this.attr('transform') || '')
-      // split transformations
-      .split(SVG.regex.transforms).slice(0, -1).map(function (str) {
-        // generate key => value pairs
-        var kv = str.trim().split('(')
-        return [kv[0], kv[1].split(SVG.regex.delimiter).map(function (str) { return parseFloat(str) })]
-      })
-      // merge every transformation into one matrix
-      .reduce(function (matrix, transform) {
-        if (transform[0] === 'matrix') return matrix.multiply(arrayToMatrix(transform[1]))
-        return matrix[transform[0]].apply(matrix, transform[1])
-      }, new SVG.Matrix())
-
-    return matrix
-  },
-  // add an element to another parent without changing the visual representation on the screen
-  toParent: function (parent) {
-    if (this === parent) return this
-    var ctm = this.screenCTM()
-    var pCtm = parent.screenCTM().inverse()
-
-    this.addTo(parent).untransform().transform(pCtm.multiply(ctm))
-
-    return this
-  },
-  // same as above with parent equals root-svg
-  toDoc: function () {
-    return this.toParent(this.doc())
-  }
-
-})
-
-SVG.Transformation = SVG.invent({
-
-  create: function (source, inversed) {
-    if (arguments.length > 1 && typeof inversed !== 'boolean') {
-      return this.constructor.bind(this)([].slice.call(arguments))
-    }
-
-    var i, len
-    if (Array.isArray(source)) {
-      for (i = 0, len = this.arguments.length; i < len; ++i) {
-        this[this.arguments[i]] = source[i]
-      }
-    } else if (typeof source === 'object') {
-      for (i = 0, len = this.arguments.length; i < len; ++i) {
-        this[this.arguments[i]] = source[this.arguments[i]]
-      }
-    }
-
-    this.inversed = false
-
-    if (inversed === true) {
-      this.inversed = true
-    }
-  },
-
-  extend: {
-
-    arguments: [],
-    method: '',
-
-    at: function (pos) {
-      var params = []
-
-      for (var i = 0, len = this.arguments.length; i < len; ++i) {
-        params.push(this[this.arguments[i]])
-      }
-
-      var m = this._undo || new SVG.Matrix()
-
-      m = new SVG.Matrix().morph(SVG.Matrix.prototype[this.method].apply(m, params)).at(pos)
-
-      return this.inversed ? m.inverse() : m
-    },
-
-    undo: function (o) {
-      for (var i = 0, len = this.arguments.length; i < len; ++i) {
-        o[this.arguments[i]] = typeof this[this.arguments[i]] === 'undefined' ? 0 : o[this.arguments[i]]
-      }
-
-      // The method SVG.Matrix.extract which was used before calling this
-      // method to obtain a value for the parameter o doesn't return a cx and
-      // a cy so we use the ones that were provided to this object at its creation
-      o.cx = this.cx
-      o.cy = this.cy
-
-      this._undo = new SVG[capitalize(this.method)](o, true).at(1)
-      return this
-    }
-
-  }
-
-})
-
-SVG.Translate = SVG.invent({
-
-  parent: SVG.Matrix,
-  inherit: SVG.Transformation,
-
-  create: function (source, inversed) {
-    this.constructor.apply(this, [].slice.call(arguments))
-  },
-
-  extend: {
-    arguments: ['transformedX', 'transformedY'],
-    method: 'translate'
-  }
-
-})
-
-SVG.Rotate = SVG.invent({
-
-  parent: SVG.Matrix,
-  inherit: SVG.Transformation,
-
-  create: function (source, inversed) {
-    this.constructor.apply(this, [].slice.call(arguments))
-  },
-
-  extend: {
-    arguments: ['rotation', 'cx', 'cy'],
-    method: 'rotate',
-    at: function (pos) {
-      var m = new SVG.Matrix().rotate(new SVG.Number().morph(this.rotation - (this._undo ? this._undo.rotation : 0)).at(pos), this.cx, this.cy)
-      return this.inversed ? m.inverse() : m
-    },
-    undo: function (o) {
-      this._undo = o
-      return this
-    }
-  }
-
-})
-
-SVG.Scale = SVG.invent({
-
-  parent: SVG.Matrix,
-  inherit: SVG.Transformation,
-
-  create: function (source, inversed) {
-    this.constructor.apply(this, [].slice.call(arguments))
-  },
-
-  extend: {
-    arguments: ['scaleX', 'scaleY', 'cx', 'cy'],
-    method: 'scale'
-  }
-
-})
-
-SVG.Skew = SVG.invent({
-
-  parent: SVG.Matrix,
-  inherit: SVG.Transformation,
-
-  create: function (source, inversed) {
-    this.constructor.apply(this, [].slice.call(arguments))
-  },
-
-  extend: {
-    arguments: ['skewX', 'skewY', 'cx', 'cy'],
-    method: 'skew'
-  }
-})
-
-/* global camelCase */
-
-SVG.extend(SVG.Element, {
-  // Dynamic style generator
-  css: function (s, v) {
-    var ret = {}
-    var t, i
-    if (arguments.length === 0) {
-      // get full style as object
-      this.node.style.cssText.split(/\s*;\s*/).filter(function (el) { return !!el.length }).forEach(function (el) {
-        t = el.split(/\s*:\s*/)
-        ret[t[0]] = t[1]
-      })
-      return ret
-    }
-
-    if (arguments.length < 2) {
-      // get style properties in the array
-      if (Array.isArray(s)) {
-        for (i = s.length; i--;) {
-          ret[camelCase(s[i])] = this.node.style[camelCase(s[i])]
-        }
-        return ret
-      }
-
-      // get style for property
-      if (typeof s === 'string') {
-        return this.node.style[camelCase(s)]
-      }
-
-      // set styles in object
-      if (typeof s === 'object') {
-        for (i in s) {
-          // set empty string if null/undefined/'' was given
-          this.node.style[camelCase(i)] = (s[i] == null || SVG.regex.isBlank.test(s[i])) ? '' : s[i]
-        }
-      }
-    }
-
-    // set style for property
-    if (arguments.length === 2) {
-      this.node.style[camelCase(s)] = (v == null || SVG.regex.isBlank.test(v)) ? '' : v
-    }
-
-    return this
-  }
-})
-
-/* global createElement */
-
-SVG.Parent = SVG.invent({
-  // Initialize node
-  create: function (node) {
-    this.constructor(node)
-  },
-
-  // Inherit from
-  inherit: SVG.Element,
-
-  // Add class methods
-  extend: {
-    // Returns all child elements
-    children: function () {
-      return SVG.utils.map(this.node.children, function (node) {
-        return SVG.adopt(node)
-      })
-    },
-    // Add given element at a position
-    add: function (element, i) {
-      element = createElement(element)
-
-      if (i == null) {
-        this.node.appendChild(element.node)
-      } else if (element.node !== this.node.children[i]) {
-        this.node.insertBefore(element.node, this.node.children[i])
-      }
-
-      return this
-    },
-    // Basically does the same as `add()` but returns the added element instead
-    put: function (element, i) {
-      this.add(element, i)
-      return element.instance || element
-    },
-    // Checks if the given element is a child
-    has: function (element) {
-      return this.index(element) >= 0
-    },
-    // Gets index of given element
-    index: function (element) {
-      return [].slice.call(this.node.children).indexOf(element.node)
-    },
-    // Get a element at the given index
-    get: function (i) {
-      return SVG.adopt(this.node.children[i])
-    },
-    // Get first child
-    first: function () {
-      return this.get(0)
-    },
-    // Get the last child
-    last: function () {
-      return this.get(this.node.children.length - 1)
-    },
-    // Iterates over all children and invokes a given block
-    each: function (block, deep) {
-      var children = this.children()
-      var i, il
-
-      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.Parent)) {
-          children[i].each(block, deep)
-        }
-      }
-
-      return this
-    },
-    // Remove a given child
-    removeElement: function (element) {
-      this.node.removeChild(element.node)
-
-      return this
-    },
-    // Remove all elements in this container
-    clear: function () {
-      // remove children
-      while (this.node.hasChildNodes()) {
-        this.node.removeChild(this.node.lastChild)
-      }
-
-      // remove defs reference
-      delete this._defs
-
-      return this
-    }
-  }
-
-})
-
-SVG.extend(SVG.Parent, {
-  flatten: function (parent) {
-    if (this instanceof SVG.Defs) return this
-
-    parent = parent || (this instanceof SVG.Doc ? this : this.parent(SVG.Parent))
-
-    this.each(function () {
-      if (this instanceof SVG.Defs) return this
-      if (this instanceof SVG.Parent) return this.flatten(parent)
-      return this.toParent(parent)
-    })
-
-    // we need this so that SVG.Doc does not get removed
-    this.node.firstElementChild || this.remove()
-
-    return this
-  }
-})
-
-SVG.Container = SVG.invent({
-  // Initialize node
-  create: function (node) {
-    this.constructor(node)
-  },
-
-  // Inherit from
-  inherit: SVG.Parent
-})
-
-// Add events to elements
-;[ 'click',
-  'dblclick',
-  'mousedown',
-  'mouseup',
-  'mouseover',
-  'mouseout',
-  'mousemove',
-  // , 'mouseenter' -> not supported by IE
-  // , 'mouseleave' -> not supported by IE
-  'touchstart',
-  'touchmove',
-  'touchleave',
-  'touchend',
-  'touchcancel' ].forEach(function (event) {
-  // add event to SVG.Element
-    SVG.Element.prototype[event] = function (f) {
-    // bind event to element rather than element node
-      SVG.on(this, event, f)
-      return this
-    }
-  })
-
-// Initialize listeners stack
-SVG.listeners = []
-SVG.handlerMap = []
-SVG.listenerId = 0
-
-// Add event binder in the SVG namespace
-SVG.on = function (node, events, listener, binding, options) {
-  events.split(SVG.regex.delimiter).forEach(function (event) {
-    // create listener, get object-index
-    var l = listener.bind(binding || node)
-    var n = node instanceof SVG.Element ? node.node : node
-    var index = (SVG.handlerMap.indexOf(n) + 1 || SVG.handlerMap.push(n)) - 1
-    var ev = event.split('.')[0]
-    var ns = event.split('.')[1] || '*'
-
-    // ensure valid object
-    SVG.listeners[index] = SVG.listeners[index] || {}
-    SVG.listeners[index][ev] = SVG.listeners[index][ev] || {}
-    SVG.listeners[index][ev][ns] = SVG.listeners[index][ev][ns] || {}
-
-    if (!listener._svgjsListenerId) {
-      listener._svgjsListenerId = ++SVG.listenerId
-    }
-
-    // reference listener
-    SVG.listeners[index][ev][ns][listener._svgjsListenerId] = l
-
-    // add listener
-    n.addEventListener(ev, l, options || false)
-  })
-}
-
-// Add event unbinder in the SVG namespace
-SVG.off = function (node, event, listener) {
-  var index = SVG.handlerMap.indexOf(node)
-  var ev = event && event.split('.')[0]
-  var ns = event && event.split('.')[1]
-  var namespace = ''
-
-  if (index === -1) return
-
-  if (listener) {
-    if (typeof listener === 'function') listener = listener._svgjsListenerId
-    if (!listener) return
-
-    // remove listener reference
-    if (SVG.listeners[index][ev] && SVG.listeners[index][ev][ns || '*']) {
-      // remove listener
-      node.removeEventListener(ev, SVG.listeners[index][ev][ns || '*'][listener], false)
-
-      delete SVG.listeners[index][ev][ns || '*'][listener]
-    }
-  } else if (ns && ev) {
-    // remove all listeners for a namespaced event
-    if (SVG.listeners[index][ev] && SVG.listeners[index][ev][ns]) {
-      for (listener in SVG.listeners[index][ev][ns]) {
-        SVG.off(node, [ev, ns].join('.'), listener)
-      }
-
-      delete SVG.listeners[index][ev][ns]
-    }
-  } else if (ns) {
-    // remove all listeners for a specific namespace
-    for (event in SVG.listeners[index]) {
-      for (namespace in SVG.listeners[index][event]) {
-        if (ns === namespace) {
-          SVG.off(node, [event, ns].join('.'))
-        }
-      }
-    }
-  } else if (ev) {
-    // remove all listeners for the event
-    if (SVG.listeners[index][ev]) {
-      for (namespace in SVG.listeners[index][ev]) {
-        SVG.off(node, [ev, namespace].join('.'))
-      }
-
-      delete SVG.listeners[index][ev]
-    }
-  } else {
-    // remove all listeners on a given node
-    for (event in SVG.listeners[index]) {
-      SVG.off(node, event)
-    }
-
-    delete SVG.listeners[index]
-    delete SVG.handlerMap[index]
-  }
-}
-
-//
-SVG.extend(SVG.Element, {
-  // Bind given event to listener
-  on: function (event, listener, binding, options) {
-    SVG.on(this, event, listener, binding, options)
-    return this
-  },
-
-  // Unbind event from listener
-  off: function (event, listener) {
-    SVG.off(this.node, event, listener)
-    return this
-  },
-
-  // Fire given event
-  fire: function (event, data) {
-    // Dispatch event
-    if (event instanceof window.Event) {
-      this.node.dispatchEvent(event)
-    } else {
-      this.node.dispatchEvent(event = new window.CustomEvent(event, {detail: data, cancelable: true}))
-    }
-
-    this._event = event
-    return this
-  },
-
-  event: function () {
-    return this._event
-  }
-})
-
-SVG.Defs = SVG.invent({
-  // Initialize node
-  create: 'defs',
-
-  // Inherit from
-  inherit: SVG.Container
-})
-
-SVG.G = SVG.invent({
-  // Initialize node
-  create: 'g',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Move over x-axis
-    x: function (x) {
-      return x == null ? this.transform('x') : this.transform({ x: x - this.x() }, true)
-    },
-    // Move over y-axis
-    y: function (y) {
-      return y == null ? this.transform('y') : this.transform({ y: y - this.y() }, true)
-    },
-    // Move by center over x-axis
-    cx: function (x) {
-      return x == null ? this.gbox().cx : this.x(x - this.gbox().width / 2)
-    },
-    // Move by center over y-axis
-    cy: function (y) {
-      return y == null ? this.gbox().cy : this.y(y - this.gbox().height / 2)
-    },
-    gbox: function () {
-      var bbox = this.bbox()
-      var trans = this.transform()
-
-      bbox.x += trans.x
-      bbox.x2 += trans.x
-      bbox.cx += trans.x
-
-      bbox.y += trans.y
-      bbox.y2 += trans.y
-      bbox.cy += trans.y
-
-      return bbox
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // Create a group element
-    group: function () {
-      return this.put(new SVG.G())
-    }
-  }
-})
-
-// ### This module adds backward / forward functionality to elements.
-
-//
-SVG.extend(SVG.Element, {
-  // Get all siblings, including myself
-  siblings: function () {
-    return this.parent().children()
-  },
-
-  // Get the curent position siblings
-  position: function () {
-    return this.parent().index(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)
-  prev: function () {
-    return this.siblings()[this.position() - 1]
-  },
-
-  // Send given element one step forward
-  forward: function () {
-    var i = this.position() + 1
-    var p = this.parent()
-
-    // move node one step forward
-    p.removeElement(this).add(this, i)
-
-    // make sure defs node is always at the top
-    if (p instanceof SVG.Doc) {
-      p.node.appendChild(p.defs().node)
-    }
-
-    return this
-  },
-
-  // 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 () {
-    var p = this.parent()
-
-    // Move node forward
-    p.node.appendChild(this.node)
-
-    // Make sure defs node is always at the top
-    if (p instanceof SVG.Doc) {
-      p.node.appendChild(p.defs().node)
-    }
-
-    return 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 = SVG.invent({
-  // Initialize node
-  create: 'mask',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Unmask all masked elements and remove itself
-    remove: function () {
-      // unmask all targets
-      this.targets().forEach(function (el) {
-        el.unmask()
-      })
-
-      // remove mask from parent
-      return SVG.Element.prototype.remove.call(this)
-    },
-
-    targets: function () {
-      return SVG.select('svg [mask*="' + this.id() + '"]')
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // Create masking element
-    mask: function () {
-      return this.defs().put(new SVG.Mask())
-    }
-  }
-})
-
-SVG.extend(SVG.Element, {
-  // Distribute mask to svg element
-  maskWith: function (element) {
-    // use given mask or create a new one
-    var masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element)
-
-    // apply mask
-    return this.attr('mask', 'url("#' + masker.id() + '")')
-  },
-  // Unmask element
-  unmask: function () {
-    return this.attr('mask', null)
-  },
-  masker: function () {
-    return this.reference('mask')
-  }
-})
-
-SVG.ClipPath = SVG.invent({
-  // Initialize node
-  create: 'clipPath',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Unclip all clipped elements and remove itself
-    remove: function () {
-      // unclip all targets
-      this.targets().forEach(function (el) {
-        el.unclip()
-      })
-
-      // remove clipPath from parent
-      return SVG.Element.prototype.remove.call(this)
-    },
-
-    targets: function () {
-      return SVG.select('svg [clip-path*="' + this.id() + '"]')
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // Create clipping element
-    clip: function () {
-      return this.defs().put(new SVG.ClipPath())
-    }
-  }
-})
-
-//
-SVG.extend(SVG.Element, {
-  // Distribute clipPath to svg element
-  clipWith: function (element) {
-    // use given clip or create a new one
-    var clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element)
-
-    // apply mask
-    return this.attr('clip-path', 'url("#' + clipper.id() + '")')
-  },
-  // Unclip element
-  unclip: function () {
-    return this.attr('clip-path', null)
-  },
-  clipper: function () {
-    return this.reference('clip-path')
-  }
-
-})
-
-SVG.Gradient = SVG.invent({
-  // Initialize node
-  create: function (type) {
-    this.constructor(typeof type === 'object' ? type : SVG.create(type + 'Gradient'))
-  },
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Add a color stop
-    stop: function (offset, color, opacity) {
-      return this.put(new SVG.Stop()).update(offset, color, opacity)
-    },
-    // Update gradient
-    update: function (block) {
-      // remove all stops
-      this.clear()
-
-      // invoke passed block
-      if (typeof block === 'function') {
-        block.call(this, this)
-      }
-
-      return this
-    },
-    // Return the fill id
-    url: function () {
-      return 'url(#' + this.id() + ')'
-    },
-    // Alias string convertion to fill
-    toString: function () {
-      return this.url()
-    },
-    // custom attr to handle transform
-    attr: function (a, b, c) {
-      if (a === 'transform') a = 'gradientTransform'
-      return SVG.Container.prototype.attr.call(this, a, b, c)
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // Create gradient element in defs
-    gradient: function (type, block) {
-      return this.defs().gradient(type, block)
-    }
-  }
-})
-
-// Add animatable methods to both gradient and fx module
-SVG.extend([SVG.Gradient, SVG.FX], {
-  // From position
-  from: function (x, y) {
-    return (this._target || this).type === 'radialGradient'
-      ? 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._target || this).type === 'radialGradient'
-      ? this.attr({ cx: new SVG.Number(x), cy: new SVG.Number(y) })
-      : this.attr({ x2: new SVG.Number(x), y2: new SVG.Number(y) })
-  }
-})
-
-// Base gradient generation
-SVG.extend(SVG.Defs, {
-  // define gradient
-  gradient: function (type, block) {
-    return this.put(new SVG.Gradient(type)).update(block)
-  }
-
-})
-
-SVG.Stop = SVG.invent({
-  // Initialize node
-  create: 'stop',
-
-  // Inherit from
-  inherit: SVG.Element,
-
-  // Add class methods
-  extend: {
-    // add color stops
-    update: function (o) {
-      if (typeof o === 'number' || o instanceof SVG.Number) {
-        o = {
-          offset: arguments[0],
-          color: arguments[1],
-          opacity: arguments[2]
-        }
-      }
-
-      // 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.Pattern = SVG.invent({
-  // Initialize node
-  create: 'pattern',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Return the fill id
-    url: function () {
-      return 'url(#' + this.id() + ')'
-    },
-    // Update pattern by rebuilding
-    update: function (block) {
-      // remove content
-      this.clear()
-
-      // invoke passed block
-      if (typeof block === 'function') {
-        block.call(this, this)
-      }
-
-      return this
-    },
-    // Alias string convertion to fill
-    toString: function () {
-      return this.url()
-    },
-    // custom attr to handle transform
-    attr: function (a, b, c) {
-      if (a === 'transform') a = 'patternTransform'
-      return SVG.Container.prototype.attr.call(this, a, b, c)
-    }
-
-  },
-
-  // Add parent method
-  construct: {
-    // Create pattern element in defs
-    pattern: function (width, height, block) {
-      return this.defs().pattern(width, height, block)
-    }
-  }
-})
-
-SVG.extend(SVG.Defs, {
-  // Define gradient
-  pattern: function (width, height, block) {
-    return this.put(new SVG.Pattern()).update(block).attr({
-      x: 0,
-      y: 0,
-      width: width,
-      height: height,
-      patternUnits: 'userSpaceOnUse'
-    })
-  }
-
-})
-
-SVG.Doc = SVG.invent({
-  // Initialize node
-  create: function (node) {
-    this.constructor(node || SVG.create('svg'))
-
-    // set svg element attributes and ensure defs node
-    this.namespace().defs()
-  },
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Add namespaces
-    namespace: function () {
-      return this
-        .attr({ xmlns: SVG.ns, version: '1.1' })
-        .attr('xmlns:xlink', SVG.xlink, SVG.xmlns)
-        .attr('xmlns:svgjs', SVG.svgjs, SVG.xmlns)
-    },
-    // Creates and returns defs element
-    defs: function () {
-      return SVG.adopt(this.node.getElementsByTagName('defs')[0]) || this.put(new SVG.Defs())
-    },
-    // custom parent method
-    parent: function () {
-      return this.node.parentNode.nodeName === '#document' ? null : this.node.parentNode
-    },
-      // Removes the doc from the DOM
-    remove: function () {
-      if (this.parent()) {
-        this.parent().removeChild(this.node)
-      }
-
-      return this
-    },
-    clear: function () {
-      // remove children
-      while (this.node.hasChildNodes()) {
-        this.node.removeChild(this.node.lastChild)
-      }
-      return this
-    },
-    toNested: function () {
-      var el = SVG.create('svg')
-      this.node.instance = null
-      el.appendChild(this.node)
-
-      return SVG.adopt(this.node)
-    }
-  }
-
-})
-
-
-SVG.Shape = SVG.invent({
-  // Initialize node
-  create: function (node) {
-    this.constructor(node)
-  },
-
-  // Inherit from
-  inherit: SVG.Element
-})
-
-
-SVG.Bare = SVG.invent({
-  // Initialize
-  create: function (element, inherit) {
-    // construct element
-    this.constructor(SVG.create(element))
-
-    // inherit custom methods
-    if (inherit) {
-      for (var method in inherit.prototype) {
-        if (typeof inherit.prototype[method] === 'function') {
-          this[method] = inherit.prototype[method]
-        }
-      }
-    }
-  },
-
-  // Inherit from
-  inherit: SVG.Element,
-
-  // Add methods
-  extend: {
-    // Insert some plain text
-    words: function (text) {
-      // remove contents
-      while (this.node.hasChildNodes()) {
-        this.node.removeChild(this.node.lastChild)
-      }
-
-      // create text node
-      this.node.appendChild(document.createTextNode(text))
-
-      return this
-    }
-  }
-})
-
-SVG.extend(SVG.Parent, {
-  // Create an element that is not described by SVG.js
-  element: function (element, inherit) {
-    return this.put(new SVG.Bare(element, inherit))
-  }
-})
-
-
-SVG.Symbol = SVG.invent({
-  // Initialize node
-  create: 'symbol',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  construct: {
-    // create symbol
-    symbol: function () {
-      return this.put(new SVG.Symbol())
-    }
-  }
-})
-
-
-SVG.Use = SVG.invent({
-  // Initialize node
-  create: 'use',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add class methods
-  extend: {
-    // Use element as a reference
-    element: function (element, file) {
-      // Set lined element
-      return this.attr('href', (file || '') + '#' + element, SVG.xlink)
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // Create a use element
-    use: function (element, file) {
-      return this.put(new SVG.Use()).element(element, file)
-    }
-  }
-})
-
-
-SVG.Rect = SVG.invent({
-  // Initialize node
-  create: 'rect',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add parent method
-  construct: {
-    // Create a rect element
-    rect: function (width, height) {
-      return this.put(new SVG.Rect()).size(width, height)
-    }
-  }
-})
-
-/* global proportionalSize */
-
-SVG.Circle = SVG.invent({
-  // Initialize node
-  create: 'circle',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add parent method
-  construct: {
-    // Create circle element, based on ellipse
-    circle: function (size) {
-      return this.put(new SVG.Circle()).rx(new SVG.Number(size).divide(2)).move(0, 0)
-    }
-  }
-})
-
-SVG.extend([SVG.Circle, SVG.FX], {
-  // Radius x value
-  rx: function (rx) {
-    return this.attr('r', rx)
-  },
-  // Alias radius x value
-  ry: function (ry) {
-    return this.rx(ry)
-  }
-})
-
-SVG.Ellipse = SVG.invent({
-  // Initialize node
-  create: 'ellipse',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add parent method
-  construct: {
-    // Create an ellipse
-    ellipse: function (width, height) {
-      return this.put(new SVG.Ellipse()).size(width, height).move(0, 0)
-    }
-  }
-})
-
-SVG.extend([SVG.Ellipse, SVG.Rect, SVG.FX], {
-  // Radius x value
-  rx: function (rx) {
-    return this.attr('rx', rx)
-  },
-  // Radius y value
-  ry: function (ry) {
-    return this.attr('ry', ry)
-  }
-})
-
-// Add common method
-SVG.extend([SVG.Circle, SVG.Ellipse], {
-    // Move over x-axis
-  x: function (x) {
-    return x == null ? this.cx() - this.rx() : this.cx(x + this.rx())
-  },
-    // Move over y-axis
-  y: function (y) {
-    return y == null ? this.cy() - this.ry() : this.cy(y + this.ry())
-  },
-    // Move by center over x-axis
-  cx: function (x) {
-    return x == null ? this.attr('cx') : this.attr('cx', x)
-  },
-    // Move by center over y-axis
-  cy: function (y) {
-    return y == null ? this.attr('cy') : this.attr('cy', y)
-  },
-    // Set width of element
-  width: function (width) {
-    return width == null ? this.rx() * 2 : this.rx(new SVG.Number(width).divide(2))
-  },
-    // Set height of element
-  height: function (height) {
-    return height == null ? this.ry() * 2 : this.ry(new SVG.Number(height).divide(2))
-  },
-    // Custom size function
-  size: function (width, height) {
-    var p = proportionalSize(this, width, height)
-
-    return this
-        .rx(new SVG.Number(p.width).divide(2))
-        .ry(new SVG.Number(p.height).divide(2))
-  }
-})
-
-/* global proportionalSize */
-
-SVG.Line = SVG.invent({
-  // Initialize node
-  create: 'line',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add class methods
-  extend: {
-    // Get array
-    array: function () {
-      return new SVG.PointArray([
-        [ this.attr('x1'), this.attr('y1') ],
-        [ this.attr('x2'), this.attr('y2') ]
-      ])
-    },
-    // Overwrite native plot() method
-    plot: function (x1, y1, x2, y2) {
-      if (x1 == null) {
-        return this.array()
-      } else if (typeof y1 !== 'undefined') {
-        x1 = { x1: x1, y1: y1, x2: x2, y2: y2 }
-      } else {
-        x1 = new SVG.PointArray(x1).toLine()
-      }
-
-      return this.attr(x1)
-    },
-    // Move by left top corner
-    move: function (x, y) {
-      return this.attr(this.array().move(x, y).toLine())
-    },
-    // Set element size to given width and height
-    size: function (width, height) {
-      var p = proportionalSize(this, width, height)
-      return this.attr(this.array().size(p.width, p.height).toLine())
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // Create a line element
-    line: function (x1, y1, x2, y2) {
-      // make sure plot is called as a setter
-      // x1 is not necessarily a number, it can also be an array, a string and a SVG.PointArray
-      return SVG.Line.prototype.plot.apply(
-        this.put(new SVG.Line())
-      , x1 != null ? [x1, y1, x2, y2] : [0, 0, 0, 0]
-      )
-    }
-  }
-})
-
-/* global proportionalSize */
-
-SVG.Polyline = SVG.invent({
-  // Initialize node
-  create: 'polyline',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add parent method
-  construct: {
-    // Create a wrapped polyline element
-    polyline: function (p) {
-      // make sure plot is called as a setter
-      return this.put(new SVG.Polyline()).plot(p || new SVG.PointArray())
-    }
-  }
-})
-
-SVG.Polygon = SVG.invent({
-  // Initialize node
-  create: 'polygon',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add parent method
-  construct: {
-    // Create a wrapped polygon element
-    polygon: function (p) {
-      // make sure plot is called as a setter
-      return this.put(new SVG.Polygon()).plot(p || new SVG.PointArray())
-    }
-  }
-})
-
-// Add polygon-specific functions
-SVG.extend([SVG.Polyline, SVG.Polygon], {
-  // Get array
-  array: function () {
-    return this._array || (this._array = new SVG.PointArray(this.attr('points')))
-  },
-
-  // Plot new path
-  plot: function (p) {
-    return (p == null) ? this.array()
-      : this.clear().attr('points', typeof p === 'string' ? p
-      : (this._array = new SVG.PointArray(p)))
-  },
-
-  // Clear array cache
-  clear: function () {
-    delete this._array
-    return this
-  },
-
-  // Move by left top corner
-  move: function (x, y) {
-    return this.attr('points', this.array().move(x, y))
-  },
-
-  // Set element size to given width and height
-  size: function (width, height) {
-    var p = proportionalSize(this, width, height)
-    return this.attr('points', this.array().size(p.width, p.height))
-  }
-})
-
-// unify all point to point elements
-SVG.extend([SVG.Line, SVG.Polyline, SVG.Polygon], {
-  // Define morphable array
-  MorphArray: SVG.PointArray,
-  // 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)
-  }
-})
-
-/* global proportionalSize */
-
-SVG.Path = SVG.invent({
-  // Initialize node
-  create: 'path',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add class methods
-  extend: {
-    // Define morphable array
-    MorphArray: SVG.PathArray,
-    // Get array
-    array: function () {
-      return this._array || (this._array = new SVG.PathArray(this.attr('d')))
-    },
-    // Plot new path
-    plot: function (d) {
-      return (d == null) ? this.array()
-        : this.clear().attr('d', typeof d === 'string' ? d : (this._array = new SVG.PathArray(d)))
-    },
-    // Clear array cache
-    clear: function () {
-      delete this._array
-      return this
-    },
-    // Move by left top corner
-    move: function (x, y) {
-      return this.attr('d', this.array().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 element size to given width and height
-    size: function (width, height) {
-      var p = proportionalSize(this, width, height)
-      return this.attr('d', this.array().size(p.width, p.height))
-    },
-    // Set width of element
-    width: function (width) {
-      return width == null ? this.bbox().width : this.size(width, this.bbox().height)
-    },
-    // Set height of element
-    height: function (height) {
-      return height == null ? this.bbox().height : this.size(this.bbox().width, height)
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // Create a wrapped path element
-    path: function (d) {
-      // make sure plot is called as a setter
-      return this.put(new SVG.Path()).plot(d || new SVG.PathArray())
-    }
-  }
-})
-
-SVG.Image = SVG.invent({
-  // Initialize node
-  create: 'image',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add class methods
-  extend: {
-    // (re)load image
-    load: function (url, callback) {
-      if (!url) return this
-
-      var img = new window.Image()
-
-      SVG.on(img, 'load', function (e) {
-        var p = this.parent(SVG.Pattern)
-
-        // ensure image size
-        if (this.width() === 0 && this.height() === 0) {
-          this.size(img.width, img.height)
-        }
-
-        if (p instanceof SVG.Pattern) {
-          // ensure pattern size if not set
-          if (p.width() === 0 && p.height() === 0) {
-            p.size(this.width(), this.height())
-          }
-        }
-
-        if (typeof callback === 'function') {
-          callback.call(this, {
-            width: img.width,
-            height: img.height,
-            ratio: img.width / img.height,
-            url: url
-          })
-        }
-      }, this)
-
-      SVG.on(img, 'load error', function () {
-        // dont forget to unbind memory leaking events
-        SVG.off(img)
-      })
-
-      return this.attr('href', (img.src = url), SVG.xlink)
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // create image element, load image and set its size
-    image: function (source, callback) {
-      return this.put(new SVG.Image()).size(0, 0).load(source, callback)
-    }
-  }
-})
-
-SVG.Text = SVG.invent({
-  // Initialize node
-  create: function (node) {
-    this.constructor(node || SVG.create('text'))
-    this.dom.leading = new SVG.Number(1.3)    // store leading value for rebuilding
-    this._rebuild = true                      // enable automatic updating of dy values
-    this._build = false                     // disable build mode for adding multiple lines
-
-    // set default font
-    this.attr('font-family', SVG.defaults.attrs['font-family'])
-  },
-
-  // Inherit from
-  inherit: SVG.Parent,
-
-  // Add class methods
-  extend: {
-    // Move over x-axis
-    x: function (x) {
-      // act as getter
-      if (x == null) {
-        return this.attr('x')
-      }
-
-      return this.attr('x', x)
-    },
-    // Move over y-axis
-    y: function (y) {
-      var oy = this.attr('y')
-      var o = typeof oy === 'number' ? oy - this.bbox().y : 0
-
-      // act as getter
-      if (y == null) {
-        return typeof oy === 'number' ? oy - o : oy
-      }
-
-      return this.attr('y', typeof y === 'number' ? y + o : y)
-    },
-    // Move center over x-axis
-    cx: function (x) {
-      return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2)
-    },
-    // Move center over y-axis
-    cy: function (y) {
-      return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2)
-    },
-    // Set the text content
-    text: function (text) {
-      // act as getter
-      if (text === undefined) {
-        var children = this.node.childNodes
-        var firstLine = 0
-        text = ''
-
-        for (var i = 0, len = children.length; i < len; ++i) {
-          // skip textPaths - they are no lines
-          if (children[i].nodeName === 'textPath') {
-            if (i === 0) firstLine = 1
-            continue
-          }
-
-          // add newline if its not the first child and newLined is set to true
-          if (i !== firstLine && children[i].nodeType !== 3 && SVG.adopt(children[i]).dom.newLined === true) {
-            text += '\n'
-          }
-
-          // add content of this node
-          text += children[i].textContent
-        }
-
-        return text
-      }
-
-      // remove existing content
-      this.clear().build(true)
-
-      if (typeof text === 'function') {
-        // call block
-        text.call(this, this)
-      } else {
-        // store text and make sure text is not blank
-        text = text.split('\n')
-
-        // build new lines
-        for (var j = 0, jl = text.length; j < jl; j++) {
-          this.tspan(text[j]).newLine()
-        }
-      }
-
-      // disable build mode and rebuild lines
-      return this.build(false).rebuild()
-    },
-    // Set font size
-    size: function (size) {
-      return this.attr('font-size', size).rebuild()
-    },
-    // Set / get leading
-    leading: function (value) {
-      // act as getter
-      if (value == null) {
-        return this.dom.leading
-      }
-
-      // act as setter
-      this.dom.leading = new SVG.Number(value)
-
-      return this.rebuild()
-    },
-    // Rebuild appearance type
-    rebuild: function (rebuild) {
-      // store new rebuild flag if given
-      if (typeof rebuild === 'boolean') {
-        this._rebuild = rebuild
-      }
-
-      // define position of all lines
-      if (this._rebuild) {
-        var self = this
-        var blankLineOffset = 0
-        var dy = this.dom.leading * new SVG.Number(this.attr('font-size'))
-
-        this.each(function () {
-          if (this.dom.newLined) {
-            this.attr('x', self.attr('x'))
-
-            if (this.text() === '\n') {
-              blankLineOffset += dy
-            } else {
-              this.attr('dy', dy + blankLineOffset)
-              blankLineOffset = 0
-            }
-          }
-        })
-
-        this.fire('rebuild')
-      }
-
-      return this
-    },
-    // Enable / disable build mode
-    build: function (build) {
-      this._build = !!build
-      return this
-    },
-    // overwrite method from parent to set data properly
-    setData: function (o) {
-      this.dom = o
-      this.dom.leading = new SVG.Number(o.leading || 1.3)
-      return this
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // Create text element
-    text: function (text) {
-      return this.put(new SVG.Text()).text(text)
-    },
-    // Create plain text element
-    plain: function (text) {
-      return this.put(new SVG.Text()).plain(text)
-    }
-  }
-
-})
-
-SVG.Tspan = SVG.invent({
-  // Initialize node
-  create: 'tspan',
-
-  // Inherit from
-  inherit: SVG.Parent,
-
-  // Add class methods
-  extend: {
-    // Set text content
-    text: function (text) {
-      if (text == null) return this.node.textContent + (this.dom.newLined ? '\n' : '')
-
-      typeof text === 'function' ? text.call(this, this) : this.plain(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 () {
-      // fetch text parent
-      var t = this.parent(SVG.Text)
-
-      // mark new line
-      this.dom.newLined = true
-
-      // apply new hy¡n
-      return this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x())
-    }
-  }
-})
-
-SVG.extend([SVG.Text, SVG.Tspan], {
-  // Create plain text node
-  plain: function (text) {
-    // clear if build mode is disabled
-    if (this._build === false) {
-      this.clear()
-    }
-
-    // create text node
-    this.node.appendChild(document.createTextNode(text))
-
-    return this
-  },
-  // Create a tspan
-  tspan: function (text) {
-    var tspan = new SVG.Tspan()
-
-    // clear if build mode is disabled
-    if (!this._build) {
-      this.clear()
-    }
-
-    // add new tspan
-    this.node.appendChild(tspan.node)
-
-    return tspan.text(text)
-  },
-  // FIXME: Does this also work for textpath?
-  // Get length of text element
-  length: function () {
-    return this.node.getComputedTextLength()
-  }
-})
-
-SVG.TextPath = SVG.invent({
-  // Initialize node
-  create: 'textPath',
-
-  // Inherit from
-  inherit: SVG.Text,
-
-  // Define parent class
-  parent: SVG.Parent,
-
-  // Add parent method
-  extend: {
-    MorphArray: SVG.PathArray,
-    // return the array of the path track element
-    array: function () {
-      var track = this.track()
-
-      return track ? track.array() : null
-    },
-    // Plot path if any
-    plot: function (d) {
-      var track = this.track()
-      var pathArray = null
-
-      if (track) {
-        pathArray = track.plot(d)
-      }
-
-      return (d == null) ? pathArray : this
-    },
-    // Get the path element
-    track: function () {
-      return this.reference('href')
-    }
-  },
-  construct: {
-    textPath: function (text, path) {
-      return this.defs().path(path).text(text).addTo(this)
-    }
-  }
-})
-
-SVG.extend([SVG.Text], {
-    // Create path for text to run on
-  path: function (track) {
-    var path = new SVG.TextPath()
-
-    // if d is a path, reuse it
-    if (!(track instanceof SVG.Path)) {
-      // create path element
-      track = this.doc().defs().path(track)
-    }
-
-    // link textPath to path and add content
-    path.attr('href', '#' + track, SVG.xlink)
-
-    // add textPath element as child node and return textPath
-    return this.put(path)
-  },
-  // Todo: make this plural?
-  // Get the textPath children
-  textPath: function () {
-    return this.select('textPath')
-  }
-})
-
-SVG.extend([SVG.Path], {
-  // creates a textPath from this path
-  text: function (text) {
-    if (text instanceof SVG.Text) {
-      var txt = text.text()
-      return text.clear().path(this).text(txt)
-    }
-    return this.parent().put(new SVG.Text()).path(this).text(text)
-  }
-  // TODO: Maybe add `targets` to get all textPaths associated with this path
-})
-
-
-SVG.Nested = SVG.invent({
-  // Initialize node
-  create: 'svg',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add parent method
-  construct: {
-    // Create nested svg document
-    nested: function () {
-      return this.put(new SVG.Nested())
-    }
-  }
-})
-
-SVG.A = SVG.invent({
-  // Initialize node
-  create: 'a',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Link url
-    to: function (url) {
-      return this.attr('href', url, SVG.xlink)
-    },
-    // Link target attribute
-    target: function (target) {
-      return this.attr('target', target)
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // 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.Marker = SVG.invent({
-  // Initialize node
-  create: 'marker',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Set width of element
-    width: function (width) {
-      return this.attr('markerWidth', width)
-    },
-    // Set height of element
-    height: function (height) {
-      return this.attr('markerHeight', height)
-    },
-    // Set marker refX and refY
-    ref: function (x, y) {
-      return this.attr('refX', x).attr('refY', y)
-    },
-    // Update marker
-    update: function (block) {
-      // remove all content
-      this.clear()
-
-      // invoke passed block
-      if (typeof block === 'function') { block.call(this, this) }
-
-      return this
-    },
-    // Return the fill id
-    toString: function () {
-      return 'url(#' + this.id() + ')'
-    }
-  },
-
-  // Add parent method
-  construct: {
-    marker: function (width, height, block) {
-      // Create marker element in defs
-      return this.defs().marker(width, height, block)
-    }
-  }
-
-})
-
-SVG.extend(SVG.Defs, {
-  // Create marker
-  marker: function (width, height, block) {
-    // Set default viewbox to match the width and height, set ref to cx and cy and set orient to auto
-    return this.put(new SVG.Marker())
-      .size(width, height)
-      .ref(width / 2, height / 2)
-      .viewbox(0, 0, width, height)
-      .attr('orient', 'auto')
-      .update(block)
-  }
-
-})
-
-SVG.extend([SVG.Line, SVG.Polyline, SVG.Polygon, SVG.Path], {
-  // Create and attach markers
-  marker: function (marker, width, height, block) {
-    var attr = ['marker']
-
-    // Build attribute name
-    if (marker !== 'all') attr.push(marker)
-    attr = attr.join('-')
-
-    // Set marker attribute
-    marker = arguments[1] instanceof SVG.Marker
-      ? arguments[1]
-      : this.doc().marker(width, height, block)
-
-    return this.attr(attr, marker)
-  }
-})
-
-// Define list of available attributes for stroke and fill
-var sugar = {
-  stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'],
-  fill: ['color', 'opacity', 'rule'],
-  prefix: function (t, a) {
-    return a === 'color' ? t : t + '-' + a
-  }
-}
-
-// Add sugar for fill and stroke
-;['fill', 'stroke'].forEach(function (m) {
-  var extension = {}
-  var i
-
-  extension[m] = function (o) {
-    if (typeof o === 'undefined') {
-      return this
-    }
-    if (typeof o === 'string' || SVG.Color.isRgb(o) || (o && typeof o.fill === 'function')) {
-      this.attr(m, o)
-    } else {
-      // set all attributes from sugar.fill and sugar.stroke list
-      for (i = sugar[m].length - 1; i >= 0; i--) {
-        if (o[sugar[m][i]] != null) {
-          this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]])
-        }
-      }
-    }
-
-    return this
-  }
-
-  SVG.extend([SVG.Element, SVG.FX], extension)
-})
-
-SVG.extend([SVG.Element, SVG.FX], {
-  // Map rotation to transform
-  rotate: function (d, cx, cy) {
-    return this.transform({ rotation: d, cx: cx, cy: cy })
-  },
-  // Map skew to transform
-  skew: function (x, y, cx, cy) {
-    return arguments.length === 1 || arguments.length === 3
-      ? this.transform({ skew: x, cx: y, cy: cx })
-      : this.transform({ skewX: x, skewY: y, cx: cx, cy: cy })
-  },
-  // Map scale to transform
-  scale: function (x, y, cx, cy) {
-    return arguments.length === 1 || arguments.length === 3
-      ? this.transform({ scale: x, cx: y, cy: cx })
-      : this.transform({ scaleX: x, scaleY: y, cx: cx, cy: cy })
-  },
-  // Map translate to transform
-  translate: function (x, y) {
-    return this.transform({ x: x, y: y })
-  },
-  // Map flip to transform
-  flip: function (a, o) {
-    o = typeof a === 'number' ? a : o
-    return this.transform({ flip: a || 'both', offset: o })
-  },
-  // Map matrix to transform
-  matrix: function (m) {
-    return this.attr('transform', new SVG.Matrix(arguments.length === 6 ? [].slice.call(arguments) : m))
-  },
-  // Opacity
-  opacity: function (value) {
-    return this.attr('opacity', value)
-  },
-  // Relative move over x axis
-  dx: function (x) {
-    return this.x(new SVG.Number(x).plus(this instanceof SVG.FX ? 0 : this.x()), true)
-  },
-  // Relative move over y axis
-  dy: function (y) {
-    return this.y(new SVG.Number(y).plus(this instanceof SVG.FX ? 0 : this.y()), true)
-  },
-  // Relative move over x and y axes
-  dmove: function (x, y) {
-    return this.dx(x).dy(y)
-  }
-})
-
-SVG.extend([SVG.Rect, SVG.Ellipse, SVG.Circle, SVG.Gradient, SVG.FX], {
-  // Add x and y radius
-  radius: function (x, y) {
-    var type = (this._target || this).type
-    return type === 'radialGradient' || type === 'radialGradient'
-      ? this.attr('r', new SVG.Number(x))
-      : this.rx(x).ry(y == null ? x : y)
-  }
-})
-
-SVG.extend(SVG.Path, {
-  // Get path length
-  length: function () {
-    return this.node.getTotalLength()
-  },
-  // Get point at length
-  pointAt: function (length) {
-    return new SVG.Point(this.node.getPointAtLength(length))
-  }
-})
-
-SVG.extend([SVG.Parent, SVG.Text, SVG.Tspan, SVG.FX], {
-  // Set font
-  font: function (a, v) {
-    if (typeof a === 'object') {
-      for (v in a) this.font(v, a[v])
-    }
-
-    return a === 'leading'
-        ? this.leading(v)
-      : a === 'anchor'
-        ? this.attr('text-anchor', v)
-      : a === 'size' || a === 'family' || a === 'weight' || a === 'stretch' || a === 'variant' || a === 'style'
-        ? this.attr('font-' + a, v)
-      : this.attr(a, v)
-  }
-})
-
-
-SVG.extend(SVG.Element, {
-  // Store data values on svg nodes
-  data: function (a, v, r) {
-    if (typeof a === 'object') {
-      for (v in a) {
-        this.data(v, a[v])
-      }
-    } else 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
-  }
-})
-
-
-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 key in k) {
-        this.remember(key, k[key])
-      }
-    } else if (arguments.length === 1) {
-      // retrieve memory
-      return this.memory()[k]
-    } else {
-      // store memory
-      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 = {})
-  }
-})
-
-/* global idFromReference */
-
-// Method for getting an element by id
-SVG.get = function (id) {
-  var node = document.getElementById(idFromReference(id) || id)
-  return SVG.adopt(node)
-}
-
-// Select elements by query string
-SVG.select = function (query, parent) {
-  return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {
-    return SVG.adopt(node)
-  })
-}
-
-SVG.$$ = function (query, parent) {
-  return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {
-    return SVG.adopt(node)
-  })
-}
-
-SVG.$ = function (query, parent) {
-  return SVG.adopt((parent || document).querySelector(query))
-}
-
-SVG.extend(SVG.Parent, {
-  // Scoped select method
-  select: function (query) {
-    return SVG.select(query, this.node)
-  }
-})
-
-/* eslint no-unused-vars: 0 */
-
-function createElement (element, makeNested) {
-  if (element instanceof SVG.Element) return element
-
-  if (typeof element === 'object') {
-    return SVG.adopt(element)
-  }
-
-  if (element == null) {
-    return new SVG.Doc()
-  }
-
-  if (typeof element === 'string' && element.charAt(0) !== '<') {
-    return SVG.adopt(document.querySelector(element))
-  }
-
-  var node = SVG.create('svg')
-  node.innerHTML = element
-
-  element = SVG.adopt(node.firstElementChild)
-
-  return element
-}
-
-function isNulledBox (box) {
-  return !box.w && !box.h && !box.x && !box.y
-}
-
-function domContains (node) {
-  return (document.documentElement.contains || function (node) {
-    // This is IE - it does not support contains() for top-level SVGs
-    while (node.parentNode) {
-      node = node.parentNode
-    }
-    return node === document
-  }).call(document.documentElement, node)
-}
-
-function pathRegReplace (a, b, c, d) {
-  return c + d.replace(SVG.regex.dots, ' .')
-}
-
-// creates deep clone of array
-function arrayClone (arr) {
-  var clone = arr.slice(0)
-  for (var i = clone.length; i--;) {
-    if (Array.isArray(clone[i])) {
-      clone[i] = arrayClone(clone[i])
-    }
-  }
-  return clone
-}
-
-// tests if a given element is instance of an object
-function is (el, obj) {
-  return el instanceof obj
-}
-
-// tests if a given selector matches an element
-function matches (el, selector) {
-  return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector)
-}
-
-// Convert dash-separated-string to camelCase
-function camelCase (s) {
-  return s.toLowerCase().replace(/-(.)/g, function (m, g) {
-    return g.toUpperCase()
-  })
-}
-
-// Capitalize first letter of a string
-function capitalize (s) {
-  return s.charAt(0).toUpperCase() + s.slice(1)
-}
-
-// Ensure to six-based hex
-function fullHex (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
-}
-
-// Component to hex value
-function compToHex (comp) {
-  var hex = comp.toString(16)
-  return hex.length === 1 ? '0' + hex : hex
-}
-
-// Calculate proportional width and height values when necessary
-function proportionalSize (element, width, height) {
-  if (width == null || height == null) {
-    var box = element.bbox()
-
-    if (width == null) {
-      width = box.width / box.height * height
-    } else if (height == null) {
-      height = box.height / box.width * width
-    }
-  }
-
-  return {
-    width: width,
-    height: height
-  }
-}
-
-// Delta transform point
-function deltaTransformPoint (matrix, x, y) {
-  return {
-    x: x * matrix.a + y * matrix.c + 0,
-    y: x * matrix.b + y * matrix.d + 0
-  }
-}
-
-// Map matrix array to object
-function arrayToMatrix (a) {
-  return { a: a[0], b: a[1], c: a[2], d: a[3], e: a[4], f: a[5] }
-}
-
-// Parse matrix if required
-function parseMatrix (matrix) {
-  if (!(matrix instanceof SVG.Matrix)) {
-    matrix = new SVG.Matrix(matrix)
-  }
-
-  return matrix
-}
-
-// Add centre point to transform object
-function ensureCentre (o, target) {
-  o.cx = o.cx == null ? target.bbox().cx : o.cx
-  o.cy = o.cy == null ? target.bbox().cy : o.cy
-}
-
-// PathArray Helpers
-function arrayToString (a) {
-  for (var i = 0, il = a.length, s = ''; i < il; i++) {
-    s += a[i][0]
-
-    if (a[i][1] != null) {
-      s += a[i][1]
-
-      if (a[i][2] != null) {
-        s += ' '
-        s += a[i][2]
-
-        if (a[i][3] != null) {
-          s += ' '
-          s += a[i][3]
-          s += ' '
-          s += a[i][4]
-
-          if (a[i][5] != null) {
-            s += ' '
-            s += a[i][5]
-            s += ' '
-            s += a[i][6]
-
-            if (a[i][7] != null) {
-              s += ' '
-              s += a[i][7]
-            }
-          }
-        }
-      }
-    }
-  }
-
-  return s + ' '
-}
-
-// Deep new id assignment
-function assignNewId (node) {
-  // do the same for SVG child nodes as well
-  for (var i = node.children.length - 1; i >= 0; i--) {
-    assignNewId(node.children[i])
-  }
-
-  if (node.id) {
-    return SVG.adopt(node).id(SVG.eid(node.nodeName))
-  }
-
-  return SVG.adopt(node)
-}
-
-// Add more bounding box properties
-function fullBox (b) {
-  if (b.x == null) {
-    b.x = 0
-    b.y = 0
-    b.width = 0
-    b.height = 0
-  }
-
-  b.w = b.width
-  b.h = b.height
-  b.x2 = b.x + b.width
-  b.y2 = b.y + b.height
-  b.cx = b.x + b.width / 2
-  b.cy = b.y + b.height / 2
-
-  return b
-}
-
-// Get id from reference string
-function idFromReference (url) {
-  var m = (url || '').toString().match(SVG.regex.reference)
-
-  if (m) return m[1]
-}
-
-// Create matrix array for looping
-var abcdef = 'abcdef'.split('')
-
-/* globals fullBox, domContains, isNulledBox, Exception */
-
-SVG.Box = SVG.invent({
-  create: function (source) {
-    var base = [0, 0, 0, 0]
-    source = typeof source === 'string' ? source.split(SVG.regex.delimiter).map(parseFloat)
-      : Array.isArray(source) ? source
-      : typeof source === 'object' ? [source.left != null ? source.left
-      : source.x, source.top != null ? source.top : source.y, source.width, source.height]
-      : arguments.length === 4 ? [].slice.call(arguments)
-      : base
-
-    this.x = source[0]
-    this.y = source[1]
-    this.width = source[2]
-    this.height = source[3]
-
-    // add center, right, bottom...
-    fullBox(this)
-  },
-  extend: {
-    // Merge rect box with another, return a new instance
-    merge: function (box) {
-      var x = Math.min(this.x, box.x)
-      var y = Math.min(this.y, box.y)
-
-      return new SVG.Box(
-        x, y,
-        Math.max(this.x + this.width, box.x + box.width) - x,
-        Math.max(this.y + this.height, box.y + box.height) - y
-      )
-    },
-
-    transform: function (m) {
-      var xMin = Infinity
-      var xMax = -Infinity
-      var yMin = Infinity
-      var yMax = -Infinity
-
-      var pts = [
-        new SVG.Point(this.x, this.y),
-        new SVG.Point(this.x2, this.y),
-        new SVG.Point(this.x, this.y2),
-        new SVG.Point(this.x2, this.y2)
-      ]
-
-      pts.forEach(function (p) {
-        p = p.transform(m)
-        xMin = Math.min(xMin, p.x)
-        xMax = Math.max(xMax, p.x)
-        yMin = Math.min(yMin, p.y)
-        yMax = Math.max(yMax, p.y)
-      })
-
-      return new SVG.Box(
-        xMin, yMin,
-        xMax - xMin,
-        yMax - yMin
-      )
-    },
-
-    addOffset: function () {
-      // offset by window scroll position, because getBoundingClientRect changes when window is scrolled
-      this.x += window.pageXOffset
-      this.y += window.pageYOffset
-      return this
-    },
-    toString: function () {
-      return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height
-    },
-    morph: function (x, y, width, height) {
-      this.destination = new SVG.Box(x, y, width, height)
-      return this
-    },
-
-    at: function (pos) {
-      if (!this.destination) return this
-
-      return new SVG.Box(
-          this.x + (this.destination.x - this.x) * pos
-        , this.y + (this.destination.y - this.y) * pos
-        , this.width + (this.destination.width - this.width) * pos
-        , this.height + (this.destination.height - this.height) * pos
-      )
-    }
-  },
-
-    // Define Parent
-  parent: SVG.Element,
-
-  // Constructor
-  construct: {
-    // Get bounding box
-    bbox: function () {
-      var box
-
-      try {
-        // find native bbox
-        box = this.node.getBBox()
-
-        if (isNulledBox(box) && !domContains(this.node)) {
-          throw new Exception('Element not in the dom')
-        }
-      } catch (e) {
-        try {
-          var clone = this.clone(SVG.parser().svg).show()
-          box = clone.node.getBBox()
-          clone.remove()
-        } catch (e) {
-          console.warn('Getting a bounding box of this element is not possible')
-        }
-      }
-
-      return new SVG.Box(box)
-    },
-
-    rbox: function (el) {
-      // IE11 throws an error when element not in dom
-      try {
-        var box = new SVG.Box(this.node.getBoundingClientRect())
-        if (el) return box.transform(el.screenCTM().inverse())
-        return box.addOffset()
-      } catch (e) {
-        return new SVG.Box()
-      }
-    }
-  }
-})
-
-SVG.extend([SVG.Doc, SVG.Nested, SVG.Symbol, SVG.Image, SVG.Pattern, SVG.Marker, SVG.ForeignObject, SVG.View], {
-  viewbox: function (x, y, width, height) {
-    // act as getter
-    if (x == null) return new SVG.Box(this.attr('viewBox'))
-
-    // act as setter
-    return this.attr('viewBox', new SVG.Box(x, y, width, height))
-  }
-})
-
-
-SVG.parser = function () {
-  var b
-
-  if (!SVG.parser.nodes.svg.node.parentNode) {
-    b = document.body || document.documentElement
-    SVG.parser.nodes.svg.addTo(b)
-  }
-
-  return SVG.parser.nodes
-}
-
-SVG.parser.nodes = {
-  svg: new SVG.Nested().size(2, 0).css({
-    opacity: 0,
-    position: 'absolute',
-    left: '-100%',
-    top: '-100%',
-    overflow: 'hidden'
-  })
-}
-
-SVG.parser.nodes.path = SVG.parser.nodes.svg.path().node
-
-
-return SVG
-
-}));
\ No newline at end of file
+\r
+(function(root, factory) {\r
+  /* istanbul ignore next */\r
+  if (typeof define === 'function' && define.amd) {\r
+    define(function(){\r
+      return factory(root, root.document)\r
+    })\r
+  } else if (typeof exports === 'object') {\r
+    module.exports = root.document ? factory(root, root.document) : function(w){ return factory(w, w.document) }\r
+  } else {\r
+    root.SVG = factory(root, root.document)\r
+  }\r
+}(typeof window !== "undefined" ? window : this, function(window, document) {\r
+\r
+// Check that our browser supports svg\r
+var supported = !! document.createElementNS &&\r
+  !! document.createElementNS('http://www.w3.org/2000/svg','svg').createSVGRect\r
+\r
+// If we don't support svg, just exit without doing anything\r
+if (!supported)\r
+  return {supported: false}\r
+\r
+// Otherwise, the library will be here\r
+/* global createElement, capitalize */\r
+/* eslint-disable new-cap */\r
+\r
+// The main wrapping element\r
+var SVG = this.SVG = function (element) {\r
+  if (SVG.supported) {\r
+    element = createElement(element)\r
+    return element\r
+  }\r
+}\r
+\r
+// Svg must be supported if we reached this stage\r
+SVG.supported = true\r
+\r
+// Default namespaces\r
+SVG.ns = 'http://www.w3.org/2000/svg'\r
+SVG.xmlns = 'http://www.w3.org/2000/xmlns/'\r
+SVG.xlink = 'http://www.w3.org/1999/xlink'\r
+SVG.svgjs = 'http://svgjs.com/svgjs'\r
+\r
+// Element id sequence\r
+SVG.did = 1000\r
+\r
+// Get next named element id\r
+SVG.eid = function (name) {\r
+  return 'Svgjs' + capitalize(name) + (SVG.did++)\r
+}\r
+\r
+// Method for element creation\r
+SVG.create = function (name) {\r
+  // create element\r
+  return document.createElementNS(this.ns, name)\r
+}\r
+\r
+// Method for extending objects\r
+SVG.extend = function (modules, methods) {\r
+  var key, i\r
+\r
+  modules = Array.isArray(modules) ? modules : [modules]\r
+\r
+  for (i = modules.length - 1; i >= 0; i--) {\r
+    if (modules[i]) {\r
+      for (key in methods) {\r
+        modules[i].prototype[key] = methods[key]\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+// Invent new element\r
+SVG.invent = function (config) {\r
+  // Create element initializer\r
+  var initializer = typeof config.create === 'function' ? config.create\r
+    : function (node) {\r
+      this.constructor(node || SVG.create(config.create))\r
+    }\r
+\r
+  // Inherit prototype\r
+  if (config.inherit) {\r
+    initializer.prototype = new config.inherit()\r
+  }\r
+\r
+  // Extend with methods\r
+  if (config.extend) {\r
+    SVG.extend(initializer, config.extend)\r
+  }\r
+\r
+  // Attach construct method to parent\r
+  if (config.construct) { SVG.extend(config.parent || SVG.Container, config.construct) }\r
+\r
+  return initializer\r
+}\r
+\r
+// Adopt existing svg elements\r
+SVG.adopt = function (node) {\r
+  // check for presence of node\r
+  if (!node) return null\r
+\r
+  // make sure a node isn't already adopted\r
+  if (node.instance instanceof SVG.Element) return node.instance\r
+\r
+  if (!(node instanceof window.SVGElement)) {\r
+    return new SVG.HtmlNode(node)\r
+  }\r
+\r
+  // initialize variables\r
+  var element\r
+\r
+  // adopt with element-specific settings\r
+  if (node.nodeName === 'svg') {\r
+    element = new SVG.Doc(node)\r
+  } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') {\r
+    element = new SVG.Gradient(node)\r
+  } else if (SVG[capitalize(node.nodeName)]) {\r
+    element = new SVG[capitalize(node.nodeName)](node)\r
+  } else {\r
+    element = new SVG.Parent(node)\r
+  }\r
+\r
+  return element\r
+}\r
+
+// Storage for regular expressions\r
+SVG.regex = {\r
+  // Parse unit value\r
+  numberAndUnit: /^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,\r
+\r
+  // Parse hex value\r
+  hex: /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,\r
+\r
+  // Parse rgb value\r
+  rgb: /rgb\((\d+),(\d+),(\d+)\)/,\r
+\r
+  // Parse reference id\r
+  reference: /#([a-z0-9\-_]+)/i,\r
+\r
+  // splits a transformation chain\r
+  transforms: /\)\s*,?\s*/,\r
+\r
+  // Whitespace\r
+  whitespace: /\s/g,\r
+\r
+  // Test hex value\r
+  isHex: /^#[a-f0-9]{3,6}$/i,\r
+\r
+  // Test rgb value\r
+  isRgb: /^rgb\(/,\r
+\r
+  // Test css declaration\r
+  isCss: /[^:]+:[^;]+;?/,\r
+\r
+  // Test for blank string\r
+  isBlank: /^(\s+)?$/,\r
+\r
+  // Test for numeric string\r
+  isNumber: /^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,\r
+\r
+  // Test for percent value\r
+  isPercent: /^-?[\d.]+%$/,\r
+\r
+  // Test for image url\r
+  isImage: /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,\r
+\r
+  // split at whitespace and comma\r
+  delimiter: /[\s,]+/,\r
+\r
+  // The following regex are used to parse the d attribute of a path\r
+\r
+  // Matches all hyphens which are not after an exponent\r
+  hyphen: /([^e])-/gi,\r
+\r
+  // Replaces and tests for all path letters\r
+  pathLetters: /[MLHVCSQTAZ]/gi,\r
+\r
+  // yes we need this one, too\r
+  isPathLetter: /[MLHVCSQTAZ]/i,\r
+\r
+  // matches 0.154.23.45\r
+  numbersWithDots: /((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,\r
+\r
+  // matches .\r
+  dots: /\./g\r
+}\r
+
+SVG.utils = {\r
+  // Map function\r
+  map: function (array, block) {\r
+    var i\r
+    var il = array.length\r
+    var result = []\r
+\r
+    for (i = 0; i < il; i++) {\r
+      result.push(block(array[i]))\r
+    }\r
+\r
+    return result\r
+  },\r
+\r
+  // Filter function\r
+  filter: function (array, block) {\r
+    var i\r
+    var il = array.length\r
+    var result = []\r
+\r
+    for (i = 0; i < il; i++) {\r
+      if (block(array[i])) { result.push(array[i]) }\r
+    }\r
+\r
+    return result\r
+  },\r
+\r
+  // Degrees to radians\r
+  radians: function (d) {\r
+    return d % 360 * Math.PI / 180\r
+  },\r
+\r
+  // Radians to degrees\r
+  degrees: function (r) {\r
+    return r * 180 / Math.PI % 360\r
+  },\r
+\r
+  filterSVGElements: function (nodes) {\r
+    return this.filter(nodes, function (el) { return el instanceof window.SVGElement })\r
+  }\r
+\r
+}\r
+
+\r
+SVG.defaults = {\r
+\r
+  // Default attribute values\r
+  attrs: {\r
+\r
+    // fill and stroke\r
+    'fill-opacity': 1,\r
+    'stroke-opacity': 1,\r
+    'stroke-width': 0,\r
+    'stroke-linejoin': 'miter',\r
+    'stroke-linecap': 'butt',\r
+    fill: '#000000',\r
+    stroke: '#000000',\r
+    opacity: 1,\r
+\r
+    // position\r
+    x: 0,\r
+    y: 0,\r
+    cx: 0,\r
+    cy: 0,\r
+\r
+    // size\r
+    width: 0,\r
+    height: 0,\r
+\r
+    // radius\r
+    r: 0,\r
+    rx: 0,\r
+    ry: 0,\r
+\r
+    // gradient\r
+    offset: 0,\r
+    'stop-opacity': 1,\r
+    'stop-color': '#000000',\r
+\r
+    // text\r
+    'font-size': 16,\r
+    'font-family': 'Helvetica, Arial, sans-serif',\r
+    'text-anchor': 'start'\r
+  }\r
+}\r
+
+/* globals fullHex, compToHex */\r
+\r
+// Module for color convertions\r
+SVG.Color = function (color) {\r
+  var match\r
+\r
+  // initialize defaults\r
+  this.r = 0\r
+  this.g = 0\r
+  this.b = 0\r
+\r
+  if (!color) return\r
+\r
+  // parse color\r
+  if (typeof color === 'string') {\r
+    if (SVG.regex.isRgb.test(color)) {\r
+      // get rgb values\r
+      match = SVG.regex.rgb.exec(color.replace(SVG.regex.whitespace, ''))\r
+\r
+      // parse numeric values\r
+      this.r = parseInt(match[1])\r
+      this.g = parseInt(match[2])\r
+      this.b = parseInt(match[3])\r
+    } else if (SVG.regex.isHex.test(color)) {\r
+      // get hex values\r
+      match = SVG.regex.hex.exec(fullHex(color))\r
+\r
+      // parse numeric values\r
+      this.r = parseInt(match[1], 16)\r
+      this.g = parseInt(match[2], 16)\r
+      this.b = parseInt(match[3], 16)\r
+    }\r
+  } else if (typeof color === 'object') {\r
+    this.r = color.r\r
+    this.g = color.g\r
+    this.b = color.b\r
+  }\r
+}\r
+\r
+SVG.extend(SVG.Color, {\r
+  // Default to hex conversion\r
+  toString: function () {\r
+    return this.toHex()\r
+  },\r
+  // Build hex value\r
+  toHex: function () {\r
+    return '#' +\r
+      compToHex(this.r) +\r
+      compToHex(this.g) +\r
+      compToHex(this.b)\r
+  },\r
+  // Build rgb value\r
+  toRgb: function () {\r
+    return 'rgb(' + [this.r, this.g, this.b].join() + ')'\r
+  },\r
+  // Calculate true brightness\r
+  brightness: function () {\r
+    return (this.r / 255 * 0.30) +\r
+      (this.g / 255 * 0.59) +\r
+      (this.b / 255 * 0.11)\r
+  },\r
+  // Make color morphable\r
+  morph: function (color) {\r
+    this.destination = new SVG.Color(color)\r
+\r
+    return this\r
+  },\r
+  // Get morphed color at given position\r
+  at: function (pos) {\r
+    // make sure a destination is defined\r
+    if (!this.destination) return this\r
+\r
+    // normalise pos\r
+    pos = pos < 0 ? 0 : pos > 1 ? 1 : pos\r
+\r
+    // generate morphed color\r
+    return new SVG.Color({\r
+      r: ~~(this.r + (this.destination.r - this.r) * pos),\r
+      g: ~~(this.g + (this.destination.g - this.g) * pos),\r
+      b: ~~(this.b + (this.destination.b - this.b) * pos)\r
+    })\r
+  }\r
+\r
+})\r
+\r
+// Testers\r
+\r
+// Test if given value is a color string\r
+SVG.Color.test = function (color) {\r
+  color += ''\r
+  return SVG.regex.isHex.test(color) ||\r
+    SVG.regex.isRgb.test(color)\r
+}\r
+\r
+// Test if given value is a rgb object\r
+SVG.Color.isRgb = function (color) {\r
+  return color && typeof color.r === 'number' &&\r
+    typeof color.g === 'number' &&\r
+    typeof color.b === 'number'\r
+}\r
+\r
+// Test if given value is a color\r
+SVG.Color.isColor = function (color) {\r
+  return SVG.Color.isRgb(color) || SVG.Color.test(color)\r
+}\r
+
+/* global arrayClone */\r
+\r
+// Module for array conversion\r
+SVG.Array = function (array, fallback) {\r
+  array = (array || []).valueOf()\r
+\r
+  // if array is empty and fallback is provided, use fallback\r
+  if (array.length === 0 && fallback) {\r
+    array = fallback.valueOf()\r
+  }\r
+\r
+  // parse array\r
+  this.value = this.parse(array)\r
+}\r
+\r
+SVG.extend(SVG.Array, {\r
+  // Make array morphable\r
+  morph: function (array) {\r
+    this.destination = this.parse(array)\r
+\r
+    // normalize length of arrays\r
+    if (this.value.length !== this.destination.length) {\r
+      var lastValue = this.value[this.value.length - 1]\r
+      var lastDestination = this.destination[this.destination.length - 1]\r
+\r
+      while (this.value.length > this.destination.length) {\r
+        this.destination.push(lastDestination)\r
+      }\r
+      while (this.value.length < this.destination.length) {\r
+        this.value.push(lastValue)\r
+      }\r
+    }\r
+\r
+    return this\r
+  },\r
+  // Clean up any duplicate points\r
+  settle: function () {\r
+    // find all unique values\r
+    for (var i = 0, il = this.value.length, seen = []; i < il; i++) {\r
+      if (seen.indexOf(this.value[i]) === -1) {\r
+        seen.push(this.value[i])\r
+      }\r
+    }\r
+\r
+    // set new value\r
+    this.value = seen\r
+    return seen\r
+  },\r
+  // Get morphed array at given position\r
+  at: function (pos) {\r
+    // make sure a destination is defined\r
+    if (!this.destination) return this\r
+\r
+    // generate morphed array\r
+    for (var i = 0, il = this.value.length, array = []; i < il; i++) {\r
+      array.push(this.value[i] + (this.destination[i] - this.value[i]) * pos)\r
+    }\r
+\r
+    return new SVG.Array(array)\r
+  },\r
+  // Convert array to string\r
+  toString: function () {\r
+    return this.value.join(' ')\r
+  },\r
+  // Real value\r
+  valueOf: function () {\r
+    return this.value\r
+  },\r
+  // Parse whitespace separated string\r
+  parse: function (array) {\r
+    array = array.valueOf()\r
+\r
+    // if already is an array, no need to parse it\r
+    if (Array.isArray(array)) return array\r
+\r
+    return array.trim().split(SVG.regex.delimiter).map(parseFloat)\r
+  },\r
+  // Reverse array\r
+  reverse: function () {\r
+    this.value.reverse()\r
+\r
+    return this\r
+  },\r
+  clone: function () {\r
+    var clone = new this.constructor()\r
+    clone.value = arrayClone(this.value)\r
+    return clone\r
+  }\r
+})\r
+
+\r
+// Poly points array\r
+SVG.PointArray = function (array, fallback) {\r
+  SVG.Array.call(this, array, fallback || [[0, 0]])\r
+}\r
+\r
+// Inherit from SVG.Array\r
+SVG.PointArray.prototype = new SVG.Array()\r
+SVG.PointArray.prototype.constructor = SVG.PointArray\r
+\r
+SVG.extend(SVG.PointArray, {\r
+  // Convert array to string\r
+  toString: function () {\r
+    // convert to a poly point string\r
+    for (var i = 0, il = this.value.length, array = []; i < il; i++) {\r
+      array.push(this.value[i].join(','))\r
+    }\r
+\r
+    return array.join(' ')\r
+  },\r
+\r
+  // Convert array to line object\r
+  toLine: function () {\r
+    return {\r
+      x1: this.value[0][0],\r
+      y1: this.value[0][1],\r
+      x2: this.value[1][0],\r
+      y2: this.value[1][1]\r
+    }\r
+  },\r
+\r
+  // Get morphed array at given position\r
+  at: function (pos) {\r
+    // make sure a destination is defined\r
+    if (!this.destination) return this\r
+\r
+    // generate morphed point string\r
+    for (var i = 0, il = this.value.length, array = []; i < il; i++) {\r
+      array.push([\r
+        this.value[i][0] + (this.destination[i][0] - this.value[i][0]) * pos,\r
+        this.value[i][1] + (this.destination[i][1] - this.value[i][1]) * pos\r
+      ])\r
+    }\r
+\r
+    return new SVG.PointArray(array)\r
+  },\r
+\r
+  // Parse point string and flat array\r
+  parse: function (array) {\r
+    var points = []\r
+\r
+    array = array.valueOf()\r
+\r
+    // if it is an array\r
+    if (Array.isArray(array)) {\r
+      // and it is not flat, there is no need to parse it\r
+      if (Array.isArray(array[0])) {\r
+        return array\r
+      }\r
+    } else { // Else, it is considered as a string\r
+      // parse points\r
+      array = array.trim().split(SVG.regex.delimiter).map(parseFloat)\r
+    }\r
+\r
+    // validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints\r
+    // Odd number of coordinates is an error. In such cases, drop the last odd coordinate.\r
+    if (array.length % 2 !== 0) array.pop()\r
+\r
+    // wrap points in two-tuples and parse points as floats\r
+    for (var i = 0, len = array.length; i < len; i = i + 2) {\r
+      points.push([ array[i], array[i + 1] ])\r
+    }\r
+\r
+    return points\r
+  },\r
+\r
+  // Move point string\r
+  move: function (x, y) {\r
+    var box = this.bbox()\r
+\r
+    // get relative offset\r
+    x -= box.x\r
+    y -= box.y\r
+\r
+    // move every point\r
+    if (!isNaN(x) && !isNaN(y)) {\r
+      for (var i = this.value.length - 1; i >= 0; i--) {\r
+        this.value[i] = [this.value[i][0] + x, this.value[i][1] + y]\r
+      }\r
+    }\r
+\r
+    return this\r
+  },\r
+  // Resize poly string\r
+  size: function (width, height) {\r
+    var i\r
+    var box = this.bbox()\r
+\r
+    // recalculate position of all points according to new size\r
+    for (i = this.value.length - 1; i >= 0; i--) {\r
+      if (box.width) this.value[i][0] = ((this.value[i][0] - box.x) * width) / box.width + box.x\r
+      if (box.height) this.value[i][1] = ((this.value[i][1] - box.y) * height) / box.height + box.y\r
+    }\r
+\r
+    return this\r
+  },\r
+\r
+  // Get bounding box of points\r
+  bbox: function () {\r
+    var maxX = -Infinity\r
+    var maxY = -Infinity\r
+    var minX = Infinity\r
+    var minY = Infinity\r
+    this.value.forEach(function (el) {\r
+      maxX = Math.max(el[0], maxX)\r
+      maxY = Math.max(el[1], maxY)\r
+      minX = Math.min(el[0], minX)\r
+      minY = Math.min(el[1], minY)\r
+    })\r
+    return {x: minX, y: minY, width: maxX - minX, height: maxY - minY}\r
+  }\r
+})\r
+
+/* globals arrayToString, pathRegReplace */\r
+\r
+var pathHandlers = {\r
+  M: function (c, p, p0) {\r
+    p.x = p0.x = c[0]\r
+    p.y = p0.y = c[1]\r
+\r
+    return ['M', p.x, p.y]\r
+  },\r
+  L: function (c, p) {\r
+    p.x = c[0]\r
+    p.y = c[1]\r
+    return ['L', c[0], c[1]]\r
+  },\r
+  H: function (c, p) {\r
+    p.x = c[0]\r
+    return ['H', c[0]]\r
+  },\r
+  V: function (c, p) {\r
+    p.y = c[0]\r
+    return ['V', c[0]]\r
+  },\r
+  C: function (c, p) {\r
+    p.x = c[4]\r
+    p.y = c[5]\r
+    return ['C', c[0], c[1], c[2], c[3], c[4], c[5]]\r
+  },\r
+  S: function (c, p) {\r
+    p.x = c[2]\r
+    p.y = c[3]\r
+    return ['S', c[0], c[1], c[2], c[3]]\r
+  },\r
+  Q: function (c, p) {\r
+    p.x = c[2]\r
+    p.y = c[3]\r
+    return ['Q', c[0], c[1], c[2], c[3]]\r
+  },\r
+  T: function (c, p) {\r
+    p.x = c[0]\r
+    p.y = c[1]\r
+    return ['T', c[0], c[1]]\r
+  },\r
+  Z: function (c, p, p0) {\r
+    p.x = p0.x\r
+    p.y = p0.y\r
+    return ['Z']\r
+  },\r
+  A: function (c, p) {\r
+    p.x = c[5]\r
+    p.y = c[6]\r
+    return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]]\r
+  }\r
+}\r
+\r
+var mlhvqtcsaz = 'mlhvqtcsaz'.split('')\r
+\r
+for (var i = 0, il = mlhvqtcsaz.length; i < il; ++i) {\r
+  pathHandlers[mlhvqtcsaz[i]] = (function (i) {\r
+    return function (c, p, p0) {\r
+      if (i === 'H') c[0] = c[0] + p.x\r
+      else if (i === 'V') c[0] = c[0] + p.y\r
+      else if (i === 'A') {\r
+        c[5] = c[5] + p.x\r
+        c[6] = c[6] + p.y\r
+      } else {\r
+        for (var j = 0, jl = c.length; j < jl; ++j) {\r
+          c[j] = c[j] + (j % 2 ? p.y : p.x)\r
+        }\r
+      }\r
+\r
+      return pathHandlers[i](c, p, p0)\r
+    }\r
+  })(mlhvqtcsaz[i].toUpperCase())\r
+}\r
+\r
+// Path points array\r
+SVG.PathArray = function (array, fallback) {\r
+  SVG.Array.call(this, array, fallback || [['M', 0, 0]])\r
+}\r
+\r
+// Inherit from SVG.Array\r
+SVG.PathArray.prototype = new SVG.Array()\r
+SVG.PathArray.prototype.constructor = SVG.PathArray\r
+\r
+SVG.extend(SVG.PathArray, {\r
+  // Convert array to string\r
+  toString: function () {\r
+    return arrayToString(this.value)\r
+  },\r
+  // Move path string\r
+  move: function (x, y) {\r
+    // get bounding box of current situation\r
+    var box = this.bbox()\r
+\r
+    // get relative offset\r
+    x -= box.x\r
+    y -= box.y\r
+\r
+    if (!isNaN(x) && !isNaN(y)) {\r
+      // move every point\r
+      for (var l, i = this.value.length - 1; i >= 0; i--) {\r
+        l = this.value[i][0]\r
+\r
+        if (l === 'M' || l === 'L' || l === 'T') {\r
+          this.value[i][1] += x\r
+          this.value[i][2] += y\r
+        } else if (l === 'H') {\r
+          this.value[i][1] += x\r
+        } else if (l === 'V') {\r
+          this.value[i][1] += y\r
+        } else if (l === 'C' || l === 'S' || l === 'Q') {\r
+          this.value[i][1] += x\r
+          this.value[i][2] += y\r
+          this.value[i][3] += x\r
+          this.value[i][4] += y\r
+\r
+          if (l === 'C') {\r
+            this.value[i][5] += x\r
+            this.value[i][6] += y\r
+          }\r
+        } else if (l === 'A') {\r
+          this.value[i][6] += x\r
+          this.value[i][7] += y\r
+        }\r
+      }\r
+    }\r
+\r
+    return this\r
+  },\r
+  // Resize path string\r
+  size: function (width, height) {\r
+    // get bounding box of current situation\r
+    var box = this.bbox()\r
+    var i, l\r
+\r
+    // recalculate position of all points according to new size\r
+    for (i = this.value.length - 1; i >= 0; i--) {\r
+      l = this.value[i][0]\r
+\r
+      if (l === 'M' || l === 'L' || l === 'T') {\r
+        this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x\r
+        this.value[i][2] = ((this.value[i][2] - box.y) * height) / box.height + box.y\r
+      } else if (l === 'H') {\r
+        this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x\r
+      } else if (l === 'V') {\r
+        this.value[i][1] = ((this.value[i][1] - box.y) * height) / box.height + box.y\r
+      } else if (l === 'C' || l === 'S' || l === 'Q') {\r
+        this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x\r
+        this.value[i][2] = ((this.value[i][2] - box.y) * height) / box.height + box.y\r
+        this.value[i][3] = ((this.value[i][3] - box.x) * width) / box.width + box.x\r
+        this.value[i][4] = ((this.value[i][4] - box.y) * height) / box.height + box.y\r
+\r
+        if (l === 'C') {\r
+          this.value[i][5] = ((this.value[i][5] - box.x) * width) / box.width + box.x\r
+          this.value[i][6] = ((this.value[i][6] - box.y) * height) / box.height + box.y\r
+        }\r
+      } else if (l === 'A') {\r
+        // resize radii\r
+        this.value[i][1] = (this.value[i][1] * width) / box.width\r
+        this.value[i][2] = (this.value[i][2] * height) / box.height\r
+\r
+        // move position values\r
+        this.value[i][6] = ((this.value[i][6] - box.x) * width) / box.width + box.x\r
+        this.value[i][7] = ((this.value[i][7] - box.y) * height) / box.height + box.y\r
+      }\r
+    }\r
+\r
+    return this\r
+  },\r
+  // Test if the passed path array use the same path data commands as this path array\r
+  equalCommands: function (pathArray) {\r
+    var i, il, equalCommands\r
+\r
+    pathArray = new SVG.PathArray(pathArray)\r
+\r
+    equalCommands = this.value.length === pathArray.value.length\r
+    for (i = 0, il = this.value.length; equalCommands && i < il; i++) {\r
+      equalCommands = this.value[i][0] === pathArray.value[i][0]\r
+    }\r
+\r
+    return equalCommands\r
+  },\r
+  // Make path array morphable\r
+  morph: function (pathArray) {\r
+    pathArray = new SVG.PathArray(pathArray)\r
+\r
+    if (this.equalCommands(pathArray)) {\r
+      this.destination = pathArray\r
+    } else {\r
+      this.destination = null\r
+    }\r
+\r
+    return this\r
+  },\r
+  // Get morphed path array at given position\r
+  at: function (pos) {\r
+    // make sure a destination is defined\r
+    if (!this.destination) return this\r
+\r
+    var sourceArray = this.value\r
+    var destinationArray = this.destination.value\r
+    var array = []\r
+    var pathArray = new SVG.PathArray()\r
+    var i, il, j, jl\r
+\r
+    // Animate has specified in the SVG spec\r
+    // See: https://www.w3.org/TR/SVG11/paths.html#PathElement\r
+    for (i = 0, il = sourceArray.length; i < il; i++) {\r
+      array[i] = [sourceArray[i][0]]\r
+      for (j = 1, jl = sourceArray[i].length; j < jl; j++) {\r
+        array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos\r
+      }\r
+      // For the two flags of the elliptical arc command, the SVG spec say:\r
+      // Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true\r
+      // Elliptical arc command as an array followed by corresponding indexes:\r
+      // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]\r
+      //   0    1   2        3                 4             5      6  7\r
+      if (array[i][0] === 'A') {\r
+        array[i][4] = +(array[i][4] !== 0)\r
+        array[i][5] = +(array[i][5] !== 0)\r
+      }\r
+    }\r
+\r
+    // Directly modify the value of a path array, this is done this way for performance\r
+    pathArray.value = array\r
+    return pathArray\r
+  },\r
+  // Absolutize and parse path to array\r
+  parse: function (array) {\r
+    // if it's already a patharray, no need to parse it\r
+    if (array instanceof SVG.PathArray) return array.valueOf()\r
+\r
+    // prepare for parsing\r
+    var s\r
+    var paramCnt = { 'M': 2, 'L': 2, 'H': 1, 'V': 1, 'C': 6, 'S': 4, 'Q': 4, 'T': 2, 'A': 7, 'Z': 0 }\r
+\r
+    if (typeof array === 'string') {\r
+      array = array\r
+        .replace(SVG.regex.numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123\r
+        .replace(SVG.regex.pathLetters, ' $& ') // put some room between letters and numbers\r
+        .replace(SVG.regex.hyphen, '$1 -')      // add space before hyphen\r
+        .trim()                                 // trim\r
+        .split(SVG.regex.delimiter)   // split into array\r
+    } else {\r
+      array = array.reduce(function (prev, curr) {\r
+        return [].concat.call(prev, curr)\r
+      }, [])\r
+    }\r
+\r
+    // array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]\r
+    var result = []\r
+    var p = new SVG.Point()\r
+    var p0 = new SVG.Point()\r
+    var index = 0\r
+    var len = array.length\r
+\r
+    do {\r
+      // Test if we have a path letter\r
+      if (SVG.regex.isPathLetter.test(array[index])) {\r
+        s = array[index]\r
+        ++index\r
+      // If last letter was a move command and we got no new, it defaults to [L]ine\r
+      } else if (s === 'M') {\r
+        s = 'L'\r
+      } else if (s === 'm') {\r
+        s = 'l'\r
+      }\r
+\r
+      result.push(pathHandlers[s].call(null,\r
+          array.slice(index, (index = index + paramCnt[s.toUpperCase()])).map(parseFloat),\r
+          p, p0\r
+        )\r
+      )\r
+    } while (len > index)\r
+\r
+    return result\r
+  },\r
+  // Get bounding box of path\r
+  bbox: function () {\r
+    SVG.parser().path.setAttribute('d', this.toString())\r
+    return SVG.parser.nodes.path.getBBox()\r
+  }\r
+\r
+})\r
+
+\r
+// Module for unit convertions\r
+SVG.Number = SVG.invent({\r
+  // Initialize\r
+  create: function (value, unit) {\r
+    // initialize defaults\r
+    this.value = 0\r
+    this.unit = unit || ''\r
+\r
+    // parse value\r
+    if (typeof value === 'number') {\r
+      // ensure a valid numeric value\r
+      this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value\r
+    } else if (typeof value === 'string') {\r
+      unit = value.match(SVG.regex.numberAndUnit)\r
+\r
+      if (unit) {\r
+        // make value numeric\r
+        this.value = parseFloat(unit[1])\r
+\r
+        // normalize\r
+        if (unit[5] === '%') { this.value /= 100 } else if (unit[5] === 's') {\r
+          this.value *= 1000\r
+        }\r
+\r
+        // store unit\r
+        this.unit = unit[5]\r
+      }\r
+    } else {\r
+      if (value instanceof SVG.Number) {\r
+        this.value = value.valueOf()\r
+        this.unit = value.unit\r
+      }\r
+    }\r
+  },\r
+  // Add methods\r
+  extend: {\r
+    // Stringalize\r
+    toString: function () {\r
+      return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6\r
+        : this.unit === 's' ? this.value / 1e3\r
+        : this.value\r
+      ) + this.unit\r
+    },\r
+    toJSON: function () {\r
+      return this.toString()\r
+    },   // Convert to primitive\r
+    valueOf: function () {\r
+      return this.value\r
+    },\r
+    // Add number\r
+    plus: function (number) {\r
+      number = new SVG.Number(number)\r
+      return new SVG.Number(this + number, this.unit || number.unit)\r
+    },\r
+    // Subtract number\r
+    minus: function (number) {\r
+      number = new SVG.Number(number)\r
+      return new SVG.Number(this - number, this.unit || number.unit)\r
+    },\r
+    // Multiply number\r
+    times: function (number) {\r
+      number = new SVG.Number(number)\r
+      return new SVG.Number(this * number, this.unit || number.unit)\r
+    },\r
+    // Divide number\r
+    divide: function (number) {\r
+      number = new SVG.Number(number)\r
+      return new SVG.Number(this / number, this.unit || number.unit)\r
+    },\r
+    // Convert to different unit\r
+    to: function (unit) {\r
+      var number = new SVG.Number(this)\r
+\r
+      if (typeof unit === 'string') {\r
+        number.unit = unit\r
+      }\r
+\r
+      return number\r
+    },\r
+    // Make number morphable\r
+    morph: function (number) {\r
+      this.destination = new SVG.Number(number)\r
+\r
+      if (number.relative) {\r
+        this.destination.value += this.value\r
+      }\r
+\r
+      return this\r
+    },\r
+    // Get morphed number at given position\r
+    at: function (pos) {\r
+      // Make sure a destination is defined\r
+      if (!this.destination) return this\r
+\r
+      // Generate new morphed number\r
+      return new SVG.Number(this.destination)\r
+          .minus(this)\r
+          .times(pos)\r
+          .plus(this)\r
+    }\r
+\r
+  }\r
+})\r
+
+/* global createElement */\r
+\r
+SVG.HtmlNode = SVG.invent({\r
+  create: function (element) {\r
+    this.node = element\r
+  },\r
+\r
+  extend: {\r
+    add: function (element, i) {\r
+      element = createElement(element)\r
+\r
+      if (element.node !== this.node.children[i]) {\r
+        this.node.insertBefore(element.node, this.node.children[i] || null)\r
+      }\r
+\r
+      return this\r
+    },\r
+\r
+    put: function (element, i) {\r
+      this.add(element, i)\r
+      return element\r
+    }\r
+  }\r
+})\r
+
+/* global proportionalSize, assignNewId, createElement, matches, is */\r
+\r
+SVG.Element = SVG.invent({\r
+  // Initialize node\r
+  create: function (node) {\r
+    // event listener\r
+    this.events = {}\r
+\r
+    // initialize data object\r
+    this.dom = {}\r
+\r
+    // create circular reference\r
+    this.node = node\r
+    if (this.node) {\r
+      this.type = node.nodeName\r
+      this.node.instance = this\r
+      this.events = node.events || {}\r
+\r
+      if (node.hasAttribute('svgjs:data')) {\r
+        // pull svgjs data from the dom (getAttributeNS doesn't work in html5)\r
+        this.setData(JSON.parse(node.getAttribute('svgjs:data')) || {})\r
+      }\r
+    }\r
+  },\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Move over x-axis\r
+    x: function (x) {\r
+      return this.attr('x', x)\r
+    },\r
+\r
+    // Move over y-axis\r
+    y: function (y) {\r
+      return this.attr('y', y)\r
+    },\r
+\r
+    // Move by center over x-axis\r
+    cx: function (x) {\r
+      return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2)\r
+    },\r
+\r
+    // Move by center over y-axis\r
+    cy: function (y) {\r
+      return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2)\r
+    },\r
+\r
+    // Move element to given x and y values\r
+    move: function (x, y) {\r
+      return this.x(x).y(y)\r
+    },\r
+\r
+    // Move element by its center\r
+    center: function (x, y) {\r
+      return this.cx(x).cy(y)\r
+    },\r
+\r
+    // Set width of element\r
+    width: function (width) {\r
+      return this.attr('width', width)\r
+    },\r
+\r
+    // Set height of element\r
+    height: function (height) {\r
+      return this.attr('height', height)\r
+    },\r
+\r
+    // Set element size to given width and height\r
+    size: function (width, height) {\r
+      var p = proportionalSize(this, width, height)\r
+\r
+      return this\r
+        .width(new SVG.Number(p.width))\r
+        .height(new SVG.Number(p.height))\r
+    },\r
+\r
+    // Clone element\r
+    clone: function (parent) {\r
+      // write dom data to the dom so the clone can pickup the data\r
+      this.writeDataToDom()\r
+\r
+      // clone element and assign new id\r
+      var clone = assignNewId(this.node.cloneNode(true))\r
+\r
+      // insert the clone in the given parent or after myself\r
+      if (parent) parent.add(clone)\r
+      else this.after(clone)\r
+\r
+      return clone\r
+    },\r
+\r
+    // Remove element\r
+    remove: function () {\r
+      if (this.parent()) { this.parent().removeElement(this) }\r
+\r
+      return this\r
+    },\r
+\r
+    // Replace element\r
+    replace: function (element) {\r
+      this.after(element).remove()\r
+\r
+      return element\r
+    },\r
+\r
+    // Add element to given container and return self\r
+    addTo: function (parent) {\r
+      return createElement(parent).put(this)\r
+    },\r
+\r
+    // Add element to given container and return container\r
+    putIn: function (parent) {\r
+      return createElement(parent).add(this)\r
+    },\r
+\r
+    // Get / set id\r
+    id: function (id) {\r
+      // generate new id if no id set\r
+      if (typeof id === 'undefined' && !this.node.id) {\r
+        this.node.id = SVG.eid(this.type)\r
+      }\r
+\r
+      // dont't set directly width this.node.id to make `null` work correctly\r
+      return this.attr('id', id)\r
+    },\r
+\r
+    // Checks whether the given point inside the bounding box of the element\r
+    inside: function (x, y) {\r
+      var box = this.bbox()\r
+\r
+      return x > box.x &&\r
+        y > box.y &&\r
+        x < box.x + box.width &&\r
+        y < box.y + box.height\r
+    },\r
+\r
+    // Show element\r
+    show: function () {\r
+      return this.css('display', '')\r
+    },\r
+\r
+    // Hide element\r
+    hide: function () {\r
+      return this.css('display', 'none')\r
+    },\r
+\r
+    // Is element visible?\r
+    visible: function () {\r
+      return this.css('display') !== 'none'\r
+    },\r
+\r
+    // Return id on string conversion\r
+    toString: function () {\r
+      return this.id()\r
+    },\r
+\r
+    // Return array of classes on the node\r
+    classes: function () {\r
+      var attr = this.attr('class')\r
+      return attr == null ? [] : attr.trim().split(SVG.regex.delimiter)\r
+    },\r
+\r
+    // Return true if class exists on the node, false otherwise\r
+    hasClass: function (name) {\r
+      return this.classes().indexOf(name) !== -1\r
+    },\r
+\r
+    // Add class to the node\r
+    addClass: function (name) {\r
+      if (!this.hasClass(name)) {\r
+        var array = this.classes()\r
+        array.push(name)\r
+        this.attr('class', array.join(' '))\r
+      }\r
+\r
+      return this\r
+    },\r
+\r
+    // Remove class from the node\r
+    removeClass: function (name) {\r
+      if (this.hasClass(name)) {\r
+        this.attr('class', this.classes().filter(function (c) {\r
+          return c !== name\r
+        }).join(' '))\r
+      }\r
+\r
+      return this\r
+    },\r
+\r
+    // Toggle the presence of a class on the node\r
+    toggleClass: function (name) {\r
+      return this.hasClass(name) ? this.removeClass(name) : this.addClass(name)\r
+    },\r
+\r
+    // Get referenced element form attribute value\r
+    reference: function (attr) {\r
+      return SVG.get(this.attr(attr))\r
+    },\r
+\r
+    // Returns the parent element instance\r
+    parent: function (type) {\r
+      var parent = this\r
+\r
+      // check for parent\r
+      if (!parent.node.parentNode) return null\r
+\r
+      // get parent element\r
+      parent = SVG.adopt(parent.node.parentNode)\r
+\r
+      if (!type) return parent\r
+\r
+      // loop trough ancestors if type is given\r
+      while (parent && parent.node instanceof window.SVGElement) {\r
+        if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent\r
+        parent = SVG.adopt(parent.node.parentNode)\r
+      }\r
+    },\r
+\r
+    // Get parent document\r
+    doc: function () {\r
+      var p = this.parent(SVG.Doc)\r
+      return p && p.doc()\r
+    },\r
+\r
+    // Get defs\r
+    defs: function () {\r
+      return this.doc().defs()\r
+    },\r
+\r
+    // return array of all ancestors of given type up to the root svg\r
+    parents: function (type) {\r
+      var parents = []\r
+      var parent = this\r
+\r
+      do {\r
+        parent = parent.parent(type)\r
+        if (!parent || !parent.node) break\r
+\r
+        parents.push(parent)\r
+      } while (parent.parent)\r
+\r
+      return parents\r
+    },\r
+\r
+    // matches the element vs a css selector\r
+    matches: function (selector) {\r
+      return matches(this.node, selector)\r
+    },\r
+\r
+    // Returns the svg node to call native svg methods on it\r
+    native: function () {\r
+      return this.node\r
+    },\r
+\r
+    // Import raw svg\r
+    svg: function (svg) {\r
+      var well, len\r
+\r
+      // act as a setter if svg is given\r
+      if (svg && this instanceof SVG.Parent) {\r
+        // create temporary holder\r
+        well = document.createElementNS(SVG.ns, 'svg')\r
+        // dump raw svg\r
+        well.innerHTML = svg\r
+\r
+        // transplant nodes\r
+        for (len = well.children.length; len--;) {\r
+          this.node.appendChild(well.firstElementChild)\r
+        }\r
+\r
+      // otherwise act as a getter\r
+      } else {\r
+        // write svgjs data to the dom\r
+        this.writeDataToDom()\r
+\r
+        return this.node.outerHTML\r
+      }\r
+\r
+      return this\r
+    },\r
+\r
+    // write svgjs data to the dom\r
+    writeDataToDom: function () {\r
+      // dump variables recursively\r
+      if (this.is(SVG.Parent)) {\r
+        this.each(function () {\r
+          this.writeDataToDom()\r
+        })\r
+      }\r
+\r
+      // remove previously set data\r
+      this.node.removeAttribute('svgjs:data')\r
+\r
+      if (Object.keys(this.dom).length) {\r
+        this.node.setAttribute('svgjs:data', JSON.stringify(this.dom)) // see #428\r
+      }\r
+      return this\r
+    },\r
+\r
+    // set given data to the elements data property\r
+    setData: function (o) {\r
+      this.dom = o\r
+      return this\r
+    },\r
+    is: function (obj) {\r
+      return is(this, obj)\r
+    }\r
+  }\r
+})\r
+
+SVG.easing = {\r
+  '-': function (pos) { return pos },\r
+  '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },\r
+  '>': function (pos) { return Math.sin(pos * Math.PI / 2) },\r
+  '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 }\r
+}\r
+\r
+SVG.morph = function (pos) {\r
+  return function (from, to) {\r
+    return new SVG.MorphObj(from, to).at(pos)\r
+  }\r
+}\r
+\r
+SVG.Situation = SVG.invent({\r
+\r
+  create: function (o) {\r
+    this.init = false\r
+    this.reversed = false\r
+    this.reversing = false\r
+\r
+    this.duration = new SVG.Number(o.duration).valueOf()\r
+    this.delay = new SVG.Number(o.delay).valueOf()\r
+\r
+    this.start = +new Date() + this.delay\r
+    this.finish = this.start + this.duration\r
+    this.ease = o.ease\r
+\r
+    // this.loop is incremented from 0 to this.loops\r
+    // it is also incremented when in an infinite loop (when this.loops is true)\r
+    this.loop = 0\r
+    this.loops = false\r
+\r
+    this.animations = {\r
+      // functionToCall: [list of morphable objects]\r
+      // e.g. move: [SVG.Number, SVG.Number]\r
+    }\r
+\r
+    this.attrs = {\r
+      // holds all attributes which are not represented from a function svg.js provides\r
+      // e.g. someAttr: SVG.Number\r
+    }\r
+\r
+    this.styles = {\r
+      // holds all styles which should be animated\r
+      // e.g. fill-color: SVG.Color\r
+    }\r
+\r
+    this.transforms = [\r
+      // holds all transformations as transformation objects\r
+      // e.g. [SVG.Rotate, SVG.Translate, SVG.Matrix]\r
+    ]\r
+\r
+    this.once = {\r
+      // functions to fire at a specific position\r
+      // e.g. "0.5": function foo(){}\r
+    }\r
+  }\r
+\r
+})\r
+\r
+SVG.FX = SVG.invent({\r
+\r
+  create: function (element) {\r
+    this._target = element\r
+    this.situations = []\r
+    this.active = false\r
+    this.situation = null\r
+    this.paused = false\r
+    this.lastPos = 0\r
+    this.pos = 0\r
+    // The absolute position of an animation is its position in the context of its complete duration (including delay and loops)\r
+    // When performing a delay, absPos is below 0 and when performing a loop, its value is above 1\r
+    this.absPos = 0\r
+    this._speed = 1\r
+  },\r
+\r
+  extend: {\r
+\r
+    /**\r
+     * sets or returns the target of this animation\r
+     * @param o object || number In case of Object it holds all parameters. In case of number its the duration of the animation\r
+     * @param ease function || string Function which should be used for easing or easing keyword\r
+     * @param delay Number indicating the delay before the animation starts\r
+     * @return target || this\r
+     */\r
+    animate: function (o, ease, delay) {\r
+      if (typeof o === 'object') {\r
+        ease = o.ease\r
+        delay = o.delay\r
+        o = o.duration\r
+      }\r
+\r
+      var situation = new SVG.Situation({\r
+        duration: o || 1000,\r
+        delay: delay || 0,\r
+        ease: SVG.easing[ease || '-'] || ease\r
+      })\r
+\r
+      this.queue(situation)\r
+\r
+      return this\r
+    },\r
+\r
+    /**\r
+     * sets a delay before the next element of the queue is called\r
+     * @param delay Duration of delay in milliseconds\r
+     * @return this.target()\r
+     */\r
+    delay: function (delay) {\r
+      // The delay is performed by an empty situation with its duration\r
+      // attribute set to the duration of the delay\r
+      var situation = new SVG.Situation({\r
+        duration: delay,\r
+        delay: 0,\r
+        ease: SVG.easing['-']\r
+      })\r
+\r
+      return this.queue(situation)\r
+    },\r
+\r
+    /**\r
+     * sets or returns the target of this animation\r
+     * @param null || target SVG.Element which should be set as new target\r
+     * @return target || this\r
+     */\r
+    target: function (target) {\r
+      if (target && target instanceof SVG.Element) {\r
+        this._target = target\r
+        return this\r
+      }\r
+\r
+      return this._target\r
+    },\r
+\r
+    // returns the absolute position at a given time\r
+    timeToAbsPos: function (timestamp) {\r
+      return (timestamp - this.situation.start) / (this.situation.duration / this._speed)\r
+    },\r
+\r
+    // returns the timestamp from a given absolute positon\r
+    absPosToTime: function (absPos) {\r
+      return this.situation.duration / this._speed * absPos + this.situation.start\r
+    },\r
+\r
+    // starts the animationloop\r
+    startAnimFrame: function () {\r
+      this.stopAnimFrame()\r
+      this.animationFrame = window.requestAnimationFrame(function () { this.step() }.bind(this))\r
+    },\r
+\r
+    // cancels the animationframe\r
+    stopAnimFrame: function () {\r
+      window.cancelAnimationFrame(this.animationFrame)\r
+    },\r
+\r
+    // kicks off the animation - only does something when the queue is currently not active and at least one situation is set\r
+    start: function () {\r
+      // dont start if already started\r
+      if (!this.active && this.situation) {\r
+        this.active = true\r
+        this.startCurrent()\r
+      }\r
+\r
+      return this\r
+    },\r
+\r
+    // start the current situation\r
+    startCurrent: function () {\r
+      this.situation.start = +new Date() + this.situation.delay / this._speed\r
+      this.situation.finish = this.situation.start + this.situation.duration / this._speed\r
+      return this.initAnimations().step()\r
+    },\r
+\r
+    /**\r
+     * adds a function / Situation to the animation queue\r
+     * @param fn function / situation to add\r
+     * @return this\r
+     */\r
+    queue: function (fn) {\r
+      if (typeof fn === 'function' || fn instanceof SVG.Situation) {\r
+        this.situations.push(fn)\r
+      }\r
+\r
+      if (!this.situation) this.situation = this.situations.shift()\r
+\r
+      return this\r
+    },\r
+\r
+    /**\r
+     * pulls next element from the queue and execute it\r
+     * @return this\r
+     */\r
+    dequeue: function () {\r
+      // stop current animation\r
+      this.stop()\r
+\r
+      // get next animation from queue\r
+      this.situation = this.situations.shift()\r
+\r
+      if (this.situation) {\r
+        if (this.situation instanceof SVG.Situation) {\r
+          this.start()\r
+        } else {\r
+          // If it is not a SVG.Situation, then it is a function, we execute it\r
+          this.situation(this)\r
+        }\r
+      }\r
+\r
+      return this\r
+    },\r
+\r
+    // updates all animations to the current state of the element\r
+    // this is important when one property could be changed from another property\r
+    initAnimations: function () {\r
+      var i, j, source\r
+      var s = this.situation\r
+\r
+      if (s.init) return this\r
+\r
+      for (i in s.animations) {\r
+        source = this.target()[i]()\r
+\r
+        if (!Array.isArray(source)) {\r
+          source = [source]\r
+        }\r
+\r
+        if (!Array.isArray(s.animations[i])) {\r
+          s.animations[i] = [s.animations[i]]\r
+        }\r
+\r
+        // if(s.animations[i].length > source.length) {\r
+        //  source.concat = source.concat(s.animations[i].slice(source.length, s.animations[i].length))\r
+        // }\r
+\r
+        for (j = source.length; j--;) {\r
+          // The condition is because some methods return a normal number instead\r
+          // of a SVG.Number\r
+          if (s.animations[i][j] instanceof SVG.Number) {\r
+            source[j] = new SVG.Number(source[j])\r
+          }\r
+\r
+          s.animations[i][j] = source[j].morph(s.animations[i][j])\r
+        }\r
+      }\r
+\r
+      for (i in s.attrs) {\r
+        s.attrs[i] = new SVG.MorphObj(this.target().attr(i), s.attrs[i])\r
+      }\r
+\r
+      for (i in s.styles) {\r
+        s.styles[i] = new SVG.MorphObj(this.target().css(i), s.styles[i])\r
+      }\r
+\r
+      s.initialTransformation = this.target().matrixify()\r
+\r
+      s.init = true\r
+      return this\r
+    },\r
+\r
+    clearQueue: function () {\r
+      this.situations = []\r
+      return this\r
+    },\r
+\r
+    clearCurrent: function () {\r
+      this.situation = null\r
+      return this\r
+    },\r
+\r
+    /** stops the animation immediately\r
+     * @param jumpToEnd A Boolean indicating whether to complete the current animation immediately.\r
+     * @param clearQueue A Boolean indicating whether to remove queued animation as well.\r
+     * @return this\r
+     */\r
+    stop: function (jumpToEnd, clearQueue) {\r
+      var active = this.active\r
+      this.active = false\r
+\r
+      if (clearQueue) {\r
+        this.clearQueue()\r
+      }\r
+\r
+      if (jumpToEnd && this.situation) {\r
+        // initialize the situation if it was not\r
+        !active && this.startCurrent()\r
+        this.atEnd()\r
+      }\r
+\r
+      this.stopAnimFrame()\r
+\r
+      return this.clearCurrent()\r
+    },\r
+\r
+    /** resets the element to the state where the current element has started\r
+     * @return this\r
+     */\r
+    reset: function () {\r
+      if (this.situation) {\r
+        var temp = this.situation\r
+        this.stop()\r
+        this.situation = temp\r
+        this.atStart()\r
+      }\r
+      return this\r
+    },\r
+\r
+    // Stop the currently-running animation, remove all queued animations, and complete all animations for the element.\r
+    finish: function () {\r
+      this.stop(true, false)\r
+\r
+      while (this.dequeue().situation && this.stop(true, false));\r
+\r
+      this.clearQueue().clearCurrent()\r
+\r
+      return this\r
+    },\r
+\r
+    // set the internal animation pointer at the start position, before any loops, and updates the visualisation\r
+    atStart: function () {\r
+      return this.at(0, true)\r
+    },\r
+\r
+    // set the internal animation pointer at the end position, after all the loops, and updates the visualisation\r
+    atEnd: function () {\r
+      if (this.situation.loops === true) {\r
+        // If in a infinite loop, we end the current iteration\r
+        this.situation.loops = this.situation.loop + 1\r
+      }\r
+\r
+      if (typeof this.situation.loops === 'number') {\r
+        // If performing a finite number of loops, we go after all the loops\r
+        return this.at(this.situation.loops, true)\r
+      } else {\r
+        // If no loops, we just go at the end\r
+        return this.at(1, true)\r
+      }\r
+    },\r
+\r
+    // set the internal animation pointer to the specified position and updates the visualisation\r
+    // if isAbsPos is true, pos is treated as an absolute position\r
+    at: function (pos, isAbsPos) {\r
+      var durDivSpd = this.situation.duration / this._speed\r
+\r
+      this.absPos = pos\r
+      // If pos is not an absolute position, we convert it into one\r
+      if (!isAbsPos) {\r
+        if (this.situation.reversed) this.absPos = 1 - this.absPos\r
+        this.absPos += this.situation.loop\r
+      }\r
+\r
+      this.situation.start = +new Date() - this.absPos * durDivSpd\r
+      this.situation.finish = this.situation.start + durDivSpd\r
+\r
+      return this.step(true)\r
+    },\r
+\r
+    /**\r
+     * sets or returns the speed of the animations\r
+     * @param speed null || Number The new speed of the animations\r
+     * @return Number || this\r
+     */\r
+    speed: function (speed) {\r
+      if (speed === 0) return this.pause()\r
+\r
+      if (speed) {\r
+        this._speed = speed\r
+        // We use an absolute position here so that speed can affect the delay before the animation\r
+        return this.at(this.absPos, true)\r
+      } else return this._speed\r
+    },\r
+\r
+    // Make loopable\r
+    loop: function (times, reverse) {\r
+      var c = this.last()\r
+\r
+      // store total loops\r
+      c.loops = (times != null) ? times : true\r
+      c.loop = 0\r
+\r
+      if (reverse) c.reversing = true\r
+      return this\r
+    },\r
+\r
+    // pauses the animation\r
+    pause: function () {\r
+      this.paused = true\r
+      this.stopAnimFrame()\r
+\r
+      return this\r
+    },\r
+\r
+    // unpause the animation\r
+    play: function () {\r
+      if (!this.paused) return this\r
+      this.paused = false\r
+      // We use an absolute position here so that the delay before the animation can be paused\r
+      return this.at(this.absPos, true)\r
+    },\r
+\r
+    /**\r
+     * toggle or set the direction of the animation\r
+     * true sets direction to backwards while false sets it to forwards\r
+     * @param reversed Boolean indicating whether to reverse the animation or not (default: toggle the reverse status)\r
+     * @return this\r
+     */\r
+    reverse: function (reversed) {\r
+      var c = this.last()\r
+\r
+      if (typeof reversed === 'undefined') c.reversed = !c.reversed\r
+      else c.reversed = reversed\r
+\r
+      return this\r
+    },\r
+\r
+    /**\r
+     * returns a float from 0-1 indicating the progress of the current animation\r
+     * @param eased Boolean indicating whether the returned position should be eased or not\r
+     * @return number\r
+     */\r
+    progress: function (easeIt) {\r
+      return easeIt ? this.situation.ease(this.pos) : this.pos\r
+    },\r
+\r
+    /**\r
+     * adds a callback function which is called when the current animation is finished\r
+     * @param fn Function which should be executed as callback\r
+     * @return number\r
+     */\r
+    after: function (fn) {\r
+      var c = this.last()\r
+      function wrapper (e) {\r
+        if (e.detail.situation === c) {\r
+          fn.call(this, c)\r
+          this.off('finished.fx', wrapper) // prevent memory leak\r
+        }\r
+      }\r
+\r
+      this.target().on('finished.fx', wrapper)\r
+\r
+      return this._callStart()\r
+    },\r
+\r
+    // adds a callback which is called whenever one animation step is performed\r
+    during: function (fn) {\r
+      var c = this.last()\r
+      function wrapper (e) {\r
+        if (e.detail.situation === c) {\r
+          fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, c)\r
+        }\r
+      }\r
+\r
+      // see above\r
+      this.target().off('during.fx', wrapper).on('during.fx', wrapper)\r
+\r
+      this.after(function () {\r
+        this.off('during.fx', wrapper)\r
+      })\r
+\r
+      return this._callStart()\r
+    },\r
+\r
+    // calls after ALL animations in the queue are finished\r
+    afterAll: function (fn) {\r
+      var wrapper = function wrapper (e) {\r
+        fn.call(this)\r
+        this.off('allfinished.fx', wrapper)\r
+      }\r
+\r
+      // see above\r
+      this.target().off('allfinished.fx', wrapper).on('allfinished.fx', wrapper)\r
+\r
+      return this._callStart()\r
+    },\r
+\r
+    // calls on every animation step for all animations\r
+    duringAll: function (fn) {\r
+      var wrapper = function (e) {\r
+        fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, e.detail.situation)\r
+      }\r
+\r
+      this.target().off('during.fx', wrapper).on('during.fx', wrapper)\r
+\r
+      this.afterAll(function () {\r
+        this.off('during.fx', wrapper)\r
+      })\r
+\r
+      return this._callStart()\r
+    },\r
+\r
+    last: function () {\r
+      return this.situations.length ? this.situations[this.situations.length - 1] : this.situation\r
+    },\r
+\r
+    // adds one property to the animations\r
+    add: function (method, args, type) {\r
+      this.last()[type || 'animations'][method] = args\r
+      return this._callStart()\r
+    },\r
+\r
+    /** perform one step of the animation\r
+     *  @param ignoreTime Boolean indicating whether to ignore time and use position directly or recalculate position based on time\r
+     *  @return this\r
+     */\r
+    step: function (ignoreTime) {\r
+      // convert current time to an absolute position\r
+      if (!ignoreTime) this.absPos = this.timeToAbsPos(+new Date())\r
+\r
+      // This part convert an absolute position to a position\r
+      if (this.situation.loops !== false) {\r
+        var absPos, absPosInt, lastLoop\r
+\r
+        // If the absolute position is below 0, we just treat it as if it was 0\r
+        absPos = Math.max(this.absPos, 0)\r
+        absPosInt = Math.floor(absPos)\r
+\r
+        if (this.situation.loops === true || absPosInt < this.situation.loops) {\r
+          this.pos = absPos - absPosInt\r
+          lastLoop = this.situation.loop\r
+          this.situation.loop = absPosInt\r
+        } else {\r
+          this.absPos = this.situation.loops\r
+          this.pos = 1\r
+          // The -1 here is because we don't want to toggle reversed when all the loops have been completed\r
+          lastLoop = this.situation.loop - 1\r
+          this.situation.loop = this.situation.loops\r
+        }\r
+\r
+        if (this.situation.reversing) {\r
+          // Toggle reversed if an odd number of loops as occured since the last call of step\r
+          this.situation.reversed = this.situation.reversed !== Boolean((this.situation.loop - lastLoop) % 2)\r
+        }\r
+      } else {\r
+        // If there are no loop, the absolute position must not be above 1\r
+        this.absPos = Math.min(this.absPos, 1)\r
+        this.pos = this.absPos\r
+      }\r
+\r
+      // while the absolute position can be below 0, the position must not be below 0\r
+      if (this.pos < 0) this.pos = 0\r
+\r
+      if (this.situation.reversed) this.pos = 1 - this.pos\r
+\r
+      // apply easing\r
+      var eased = this.situation.ease(this.pos)\r
+\r
+      // call once-callbacks\r
+      for (var i in this.situation.once) {\r
+        if (i > this.lastPos && i <= eased) {\r
+          this.situation.once[i].call(this.target(), this.pos, eased)\r
+          delete this.situation.once[i]\r
+        }\r
+      }\r
+\r
+      // fire during callback with position, eased position and current situation as parameter\r
+      if (this.active) this.target().fire('during', {pos: this.pos, eased: eased, fx: this, situation: this.situation})\r
+\r
+      // the user may call stop or finish in the during callback\r
+      // so make sure that we still have a valid situation\r
+      if (!this.situation) {\r
+        return this\r
+      }\r
+\r
+      // apply the actual animation to every property\r
+      this.eachAt()\r
+\r
+      // do final code when situation is finished\r
+      if ((this.pos === 1 && !this.situation.reversed) || (this.situation.reversed && this.pos === 0)) {\r
+        // stop animation callback\r
+        this.stopAnimFrame()\r
+\r
+        // fire finished callback with current situation as parameter\r
+        this.target().fire('finished', {fx: this, situation: this.situation})\r
+\r
+        if (!this.situations.length) {\r
+          this.target().fire('allfinished')\r
+\r
+          // Recheck the length since the user may call animate in the afterAll callback\r
+          if (!this.situations.length) {\r
+            this.target().off('.fx') // there shouldnt be any binding left, but to make sure...\r
+            this.active = false\r
+          }\r
+        }\r
+\r
+        // start next animation\r
+        if (this.active) this.dequeue()\r
+        else this.clearCurrent()\r
+      } else if (!this.paused && this.active) {\r
+        // we continue animating when we are not at the end\r
+        this.startAnimFrame()\r
+      }\r
+\r
+      // save last eased position for once callback triggering\r
+      this.lastPos = eased\r
+      return this\r
+    },\r
+\r
+    // calculates the step for every property and calls block with it\r
+    eachAt: function () {\r
+      var i, len, at\r
+      var self = this\r
+      var target = this.target()\r
+      var s = this.situation\r
+\r
+      // apply animations which can be called trough a method\r
+      for (i in s.animations) {\r
+        at = [].concat(s.animations[i]).map(function (el) {\r
+          return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el\r
+        })\r
+\r
+        target[i].apply(target, at)\r
+      }\r
+\r
+      // apply animation which has to be applied with attr()\r
+      for (i in s.attrs) {\r
+        at = [i].concat(s.attrs[i]).map(function (el) {\r
+          return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el\r
+        })\r
+\r
+        target.attr.apply(target, at)\r
+      }\r
+\r
+      // apply animation which has to be applied with css()\r
+      for (i in s.styles) {\r
+        at = [i].concat(s.styles[i]).map(function (el) {\r
+          return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el\r
+        })\r
+\r
+        target.css.apply(target, at)\r
+      }\r
+\r
+      // animate initialTransformation which has to be chained\r
+      if (s.transforms.length) {\r
+        // get initial initialTransformation\r
+        at = s.initialTransformation\r
+        for (i = 0, len = s.transforms.length; i < len; i++) {\r
+          // get next transformation in chain\r
+          var a = s.transforms[i]\r
+\r
+          // multiply matrix directly\r
+          if (a instanceof SVG.Matrix) {\r
+            if (a.relative) {\r
+              at = at.multiply(new SVG.Matrix().morph(a).at(s.ease(this.pos)))\r
+            } else {\r
+              at = at.morph(a).at(s.ease(this.pos))\r
+            }\r
+            continue\r
+          }\r
+\r
+          // when transformation is absolute we have to reset the needed transformation first\r
+          if (!a.relative) {\r
+            a.undo(at.extract())\r
+          }\r
+\r
+          // and reapply it after\r
+          at = at.multiply(a.at(s.ease(this.pos)))\r
+        }\r
+\r
+        // set new matrix on element\r
+        target.matrix(at)\r
+      }\r
+\r
+      return this\r
+    },\r
+\r
+    // adds an once-callback which is called at a specific position and never again\r
+    once: function (pos, fn, isEased) {\r
+      var c = this.last()\r
+      if (!isEased) pos = c.ease(pos)\r
+\r
+      c.once[pos] = fn\r
+\r
+      return this\r
+    },\r
+\r
+    _callStart: function () {\r
+      setTimeout(function () { this.start() }.bind(this), 0)\r
+      return this\r
+    }\r
+\r
+  },\r
+\r
+  parent: SVG.Element,\r
+\r
+  // Add method to parent elements\r
+  construct: {\r
+    // Get fx module or create a new one, then animate with given duration and ease\r
+    animate: function (o, ease, delay) {\r
+      return (this.fx || (this.fx = new SVG.FX(this))).animate(o, ease, delay)\r
+    },\r
+    delay: function (delay) {\r
+      return (this.fx || (this.fx = new SVG.FX(this))).delay(delay)\r
+    },\r
+    stop: function (jumpToEnd, clearQueue) {\r
+      if (this.fx) {\r
+        this.fx.stop(jumpToEnd, clearQueue)\r
+      }\r
+\r
+      return this\r
+    },\r
+    finish: function () {\r
+      if (this.fx) {\r
+        this.fx.finish()\r
+      }\r
+\r
+      return this\r
+    },\r
+    // Pause current animation\r
+    pause: function () {\r
+      if (this.fx) {\r
+        this.fx.pause()\r
+      }\r
+\r
+      return this\r
+    },\r
+    // Play paused current animation\r
+    play: function () {\r
+      if (this.fx) { this.fx.play() }\r
+\r
+      return this\r
+    },\r
+    // Set/Get the speed of the animations\r
+    speed: function (speed) {\r
+      if (this.fx) {\r
+        if (speed == null) { return this.fx.speed() } else { this.fx.speed(speed) }\r
+      }\r
+\r
+      return this\r
+    }\r
+  }\r
+\r
+})\r
+\r
+// MorphObj is used whenever no morphable object is given\r
+SVG.MorphObj = SVG.invent({\r
+\r
+  create: function (from, to) {\r
+    // prepare color for morphing\r
+    if (SVG.Color.isColor(to)) return new SVG.Color(from).morph(to)\r
+    // prepare value list for morphing\r
+    if (SVG.regex.delimiter.test(from)) return new SVG.Array(from).morph(to)\r
+    // prepare number for morphing\r
+    if (SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to)\r
+\r
+    // prepare for plain morphing\r
+    this.value = from\r
+    this.destination = to\r
+  },\r
+\r
+  extend: {\r
+    at: function (pos, real) {\r
+      return real < 1 ? this.value : this.destination\r
+    },\r
+\r
+    valueOf: function () {\r
+      return this.value\r
+    }\r
+  }\r
+\r
+})\r
+\r
+SVG.extend(SVG.FX, {\r
+  // Add animatable attributes\r
+  attr: function (a, v, relative) {\r
+    // apply attributes individually\r
+    if (typeof a === 'object') {\r
+      for (var key in a) {\r
+        this.attr(key, a[key])\r
+      }\r
+    } else {\r
+      this.add(a, v, 'attrs')\r
+    }\r
+\r
+    return this\r
+  },\r
+  // Add animatable styles\r
+  css: function (s, v) {\r
+    if (typeof s === 'object') {\r
+      for (var key in s) {\r
+        this.css(key, s[key])\r
+      }\r
+    } else {\r
+      this.add(s, v, 'styles')\r
+    }\r
+\r
+    return this\r
+  },\r
+  // Animatable x-axis\r
+  x: function (x, relative) {\r
+    if (this.target() instanceof SVG.G) {\r
+      this.transform({x: x}, relative)\r
+      return this\r
+    }\r
+\r
+    var num = new SVG.Number(x)\r
+    num.relative = relative\r
+    return this.add('x', num)\r
+  },\r
+  // Animatable y-axis\r
+  y: function (y, relative) {\r
+    if (this.target() instanceof SVG.G) {\r
+      this.transform({y: y}, relative)\r
+      return this\r
+    }\r
+\r
+    var num = new SVG.Number(y)\r
+    num.relative = relative\r
+    return this.add('y', num)\r
+  },\r
+  // Animatable center x-axis\r
+  cx: function (x) {\r
+    return this.add('cx', new SVG.Number(x))\r
+  },\r
+  // Animatable center y-axis\r
+  cy: function (y) {\r
+    return this.add('cy', new SVG.Number(y))\r
+  },\r
+  // Add animatable move\r
+  move: function (x, y) {\r
+    return this.x(x).y(y)\r
+  },\r
+  // Add animatable center\r
+  center: function (x, y) {\r
+    return this.cx(x).cy(y)\r
+  },\r
+  // Add animatable size\r
+  size: function (width, height) {\r
+    if (this.target() instanceof SVG.Text) {\r
+      // animate font size for Text elements\r
+      this.attr('font-size', width)\r
+    } else {\r
+      // animate bbox based size for all other elements\r
+      var box\r
+\r
+      if (!width || !height) {\r
+        box = this.target().bbox()\r
+      }\r
+\r
+      if (!width) {\r
+        width = box.width / box.height * height\r
+      }\r
+\r
+      if (!height) {\r
+        height = box.height / box.width * width\r
+      }\r
+\r
+      this.add('width', new SVG.Number(width))\r
+          .add('height', new SVG.Number(height))\r
+    }\r
+\r
+    return this\r
+  },\r
+  // Add animatable width\r
+  width: function (width) {\r
+    return this.add('width', new SVG.Number(width))\r
+  },\r
+  // Add animatable height\r
+  height: function (height) {\r
+    return this.add('height', new SVG.Number(height))\r
+  },\r
+  // Add animatable plot\r
+  plot: function (a, b, c, d) {\r
+    // Lines can be plotted with 4 arguments\r
+    if (arguments.length === 4) {\r
+      return this.plot([a, b, c, d])\r
+    }\r
+\r
+    return this.add('plot', new (this.target().MorphArray)(a))\r
+  },\r
+  // Add leading method\r
+  leading: function (value) {\r
+    return this.target().leading\r
+      ? this.add('leading', new SVG.Number(value))\r
+      : this\r
+  },\r
+  // Add animatable viewbox\r
+  viewbox: function (x, y, width, height) {\r
+    if (this.target() instanceof SVG.Container) {\r
+      this.add('viewbox', new SVG.Box(x, y, width, height))\r
+    }\r
+\r
+    return this\r
+  },\r
+  update: function (o) {\r
+    if (this.target() instanceof SVG.Stop) {\r
+      if (typeof o === 'number' || o instanceof SVG.Number) {\r
+        return this.update({\r
+          offset: arguments[0],\r
+          color: arguments[1],\r
+          opacity: arguments[2]\r
+        })\r
+      }\r
+\r
+      if (o.opacity != null) this.attr('stop-opacity', o.opacity)\r
+      if (o.color != null) this.attr('stop-color', o.color)\r
+      if (o.offset != null) this.attr('offset', o.offset)\r
+    }\r
+\r
+    return this\r
+  }\r
+})\r
+
+/* global abcdef, arrayToMatrix, deltaTransformPoint, parseMatrix */\r
+\r
+SVG.Matrix = SVG.invent({\r
+  // Initialize\r
+  create: function (source) {\r
+    var base = arrayToMatrix([1, 0, 0, 1, 0, 0])\r
+    var i\r
+\r
+    // ensure source as object\r
+    source = source instanceof SVG.Element ? source.matrixify()\r
+      : typeof source === 'string' ? arrayToMatrix(source.split(SVG.regex.delimiter).map(parseFloat))\r
+      : arguments.length === 6 ? arrayToMatrix([].slice.call(arguments))\r
+      : Array.isArray(source) ? arrayToMatrix(source)\r
+      : typeof source === 'object' ? source\r
+      : base\r
+\r
+    // merge source\r
+    for (i = abcdef.length - 1; i >= 0; --i) {\r
+      this[abcdef[i]] = source[abcdef[i]] != null\r
+        ? source[abcdef[i]]\r
+        : base[abcdef[i]]\r
+    }\r
+  },\r
+\r
+  // Add methods\r
+  extend: {\r
+    // Extract individual transformations\r
+    extract: function () {\r
+      // find delta transform points\r
+      var px = deltaTransformPoint(this, 0, 1)\r
+      var py = deltaTransformPoint(this, 1, 0)\r
+      var skewX = 180 / Math.PI * Math.atan2(px.y, px.x) - 90\r
+\r
+      return {\r
+        // translation\r
+        x: this.e,\r
+        y: this.f,\r
+        transformedX: (this.e * Math.cos(skewX * Math.PI / 180) + this.f * Math.sin(skewX * Math.PI / 180)) / Math.sqrt(this.a * this.a + this.b * this.b),\r
+        transformedY: (this.f * Math.cos(skewX * Math.PI / 180) + this.e * Math.sin(-skewX * Math.PI / 180)) / Math.sqrt(this.c * this.c + this.d * this.d),\r
+        // skew\r
+        skewX: -skewX,\r
+        skewY: 180 / Math.PI * Math.atan2(py.y, py.x),\r
+        // scale\r
+        scaleX: Math.sqrt(this.a * this.a + this.b * this.b),\r
+        scaleY: Math.sqrt(this.c * this.c + this.d * this.d),\r
+        // rotation\r
+        rotation: skewX,\r
+        a: this.a,\r
+        b: this.b,\r
+        c: this.c,\r
+        d: this.d,\r
+        e: this.e,\r
+        f: this.f,\r
+        matrix: new SVG.Matrix(this)\r
+      }\r
+    },\r
+    // Clone matrix\r
+    clone: function () {\r
+      return new SVG.Matrix(this)\r
+    },\r
+    // Morph one matrix into another\r
+    morph: function (matrix) {\r
+      // store new destination\r
+      this.destination = new SVG.Matrix(matrix)\r
+\r
+      return this\r
+    },\r
+    // Get morphed matrix at a given position\r
+    at: function (pos) {\r
+      // make sure a destination is defined\r
+      if (!this.destination) return this\r
+\r
+      // calculate morphed matrix at a given position\r
+      var matrix = new SVG.Matrix({\r
+        a: this.a + (this.destination.a - this.a) * pos,\r
+        b: this.b + (this.destination.b - this.b) * pos,\r
+        c: this.c + (this.destination.c - this.c) * pos,\r
+        d: this.d + (this.destination.d - this.d) * pos,\r
+        e: this.e + (this.destination.e - this.e) * pos,\r
+        f: this.f + (this.destination.f - this.f) * pos\r
+      })\r
+\r
+      return matrix\r
+    },\r
+    // Multiplies by given matrix\r
+    multiply: function (matrix) {\r
+      return new SVG.Matrix(this.native().multiply(parseMatrix(matrix).native()))\r
+    },\r
+    // Inverses matrix\r
+    inverse: function () {\r
+      return new SVG.Matrix(this.native().inverse())\r
+    },\r
+    // Translate matrix\r
+    translate: function (x, y) {\r
+      return new SVG.Matrix(this.native().translate(x || 0, y || 0))\r
+    },\r
+    // Scale matrix\r
+    scale: function (x, y, cx, cy) {\r
+      // support uniformal scale\r
+      if (arguments.length === 1) {\r
+        y = x\r
+      } else if (arguments.length === 3) {\r
+        cy = cx\r
+        cx = y\r
+        y = x\r
+      }\r
+\r
+      return this.around(cx, cy, new SVG.Matrix(x, 0, 0, y, 0, 0))\r
+    },\r
+    // Rotate matrix\r
+    rotate: function (r, cx, cy) {\r
+      // convert degrees to radians\r
+      r = SVG.utils.radians(r)\r
+\r
+      return this.around(cx, cy, new SVG.Matrix(Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0, 0))\r
+    },\r
+    // Flip matrix on x or y, at a given offset\r
+    flip: function (a, o) {\r
+      return a === 'x' ? this.scale(-1, 1, o, 0)\r
+        : a === 'y' ? this.scale(1, -1, 0, o)\r
+        : this.scale(-1, -1, a, o != null ? o : a)\r
+    },\r
+    // Skew\r
+    skew: function (x, y, cx, cy) {\r
+      // support uniformal skew\r
+      if (arguments.length === 1) {\r
+        y = x\r
+      } else if (arguments.length === 3) {\r
+        cy = cx\r
+        cx = y\r
+        y = x\r
+      }\r
+\r
+      // convert degrees to radians\r
+      x = SVG.utils.radians(x)\r
+      y = SVG.utils.radians(y)\r
+\r
+      return this.around(cx, cy, new SVG.Matrix(1, Math.tan(y), Math.tan(x), 1, 0, 0))\r
+    },\r
+    // SkewX\r
+    skewX: function (x, cx, cy) {\r
+      return this.skew(x, 0, cx, cy)\r
+    },\r
+    // SkewY\r
+    skewY: function (y, cx, cy) {\r
+      return this.skew(0, y, cx, cy)\r
+    },\r
+    // Transform around a center point\r
+    around: function (cx, cy, matrix) {\r
+      return this\r
+        .multiply(new SVG.Matrix(1, 0, 0, 1, cx || 0, cy || 0))\r
+        .multiply(matrix)\r
+        .multiply(new SVG.Matrix(1, 0, 0, 1, -cx || 0, -cy || 0))\r
+    },\r
+    // Convert to native SVGMatrix\r
+    native: function () {\r
+      // create new matrix\r
+      var matrix = SVG.parser.nodes.svg.node.createSVGMatrix()\r
+\r
+      // update with current values\r
+      for (var i = abcdef.length - 1; i >= 0; i--) {\r
+        matrix[abcdef[i]] = this[abcdef[i]]\r
+      }\r
+\r
+      return matrix\r
+    },\r
+    // Convert matrix to string\r
+    toString: function () {\r
+      return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')'\r
+    }\r
+  },\r
+\r
+  // Define parent\r
+  parent: SVG.Element,\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Get current matrix\r
+    ctm: function () {\r
+      return new SVG.Matrix(this.node.getCTM())\r
+    },\r
+    // Get current screen matrix\r
+    screenCTM: function () {\r
+      /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537\r
+         This is needed because FF does not return the transformation matrix\r
+         for the inner coordinate system when getScreenCTM() is called on nested svgs.\r
+         However all other Browsers do that */\r
+      if (this instanceof SVG.Doc && !this.isRoot()) {\r
+        var rect = this.rect(1, 1)\r
+        var m = rect.node.getScreenCTM()\r
+        rect.remove()\r
+        return new SVG.Matrix(m)\r
+      }\r
+      return new SVG.Matrix(this.node.getScreenCTM())\r
+    }\r
+  }\r
+})\r
+
+\r
+SVG.Point = SVG.invent({\r
+  // Initialize\r
+  create: function (x, y) {\r
+    var base = {x: 0, y: 0}\r
+    var source\r
+\r
+    // ensure source as object\r
+    source = Array.isArray(x) ? {x: x[0], y: x[1]}\r
+      : typeof x === 'object' ? {x: x.x, y: x.y}\r
+      : x != null ? {x: x, y: (y != null ? y : x)}\r
+      : base // If y has no value, then x is used has its value\r
+\r
+    // merge source\r
+    this.x = source.x\r
+    this.y = source.y\r
+  },\r
+\r
+  // Add methods\r
+  extend: {\r
+    // Clone point\r
+    clone: function () {\r
+      return new SVG.Point(this)\r
+    },\r
+    // Morph one point into another\r
+    morph: function (x, y) {\r
+      // store new destination\r
+      this.destination = new SVG.Point(x, y)\r
+\r
+      return this\r
+    },\r
+    // Get morphed point at a given position\r
+    at: function (pos) {\r
+      // make sure a destination is defined\r
+      if (!this.destination) return this\r
+\r
+      // calculate morphed matrix at a given position\r
+      var point = new SVG.Point({\r
+        x: this.x + (this.destination.x - this.x) * pos,\r
+        y: this.y + (this.destination.y - this.y) * pos\r
+      })\r
+\r
+      return point\r
+    },\r
+    // Convert to native SVGPoint\r
+    native: function () {\r
+      // create new point\r
+      var point = SVG.parser.nodes.svg.node.createSVGPoint()\r
+\r
+      // update with current values\r
+      point.x = this.x\r
+      point.y = this.y\r
+\r
+      return point\r
+    },\r
+    // transform point with matrix\r
+    transform: function (matrix) {\r
+      return new SVG.Point(this.native().matrixTransform(matrix.native()))\r
+    }\r
+  }\r
+})\r
+\r
+SVG.extend(SVG.Element, {\r
+\r
+  // Get point\r
+  point: function (x, y) {\r
+    return new SVG.Point(x, y).transform(this.screenCTM().inverse())\r
+  }\r
+\r
+})\r
+
+SVG.extend(SVG.Element, {\r
+  // Set svg element attribute\r
+  attr: function (a, v, n) {\r
+    // act as full getter\r
+    if (a == null) {\r
+      // get an object of attributes\r
+      a = {}\r
+      v = this.node.attributes\r
+      for (n = v.length - 1; n >= 0; n--) {\r
+        a[v[n].nodeName] = SVG.regex.isNumber.test(v[n].nodeValue)\r
+          ? parseFloat(v[n].nodeValue)\r
+          : v[n].nodeValue\r
+      }\r
+      return a\r
+    } else if (typeof a === 'object') {\r
+      // apply every attribute individually if an object is passed\r
+      for (v in a) this.attr(v, a[v])\r
+    } else if (v === null) {\r
+        // remove value\r
+      this.node.removeAttribute(a)\r
+    } else if (v == null) {\r
+      // act as a getter if the first and only argument is not an object\r
+      v = this.node.getAttribute(a)\r
+      return v == null ? SVG.defaults.attrs[a]\r
+        : SVG.regex.isNumber.test(v) ? parseFloat(v)\r
+        : v\r
+    } else {\r
+      // convert image fill and stroke to patterns\r
+      if (a === 'fill' || a === 'stroke') {\r
+        if (SVG.regex.isImage.test(v)) {\r
+          v = this.doc().defs().image(v)\r
+        }\r
+\r
+        if (v instanceof SVG.Image) {\r
+          v = this.doc().defs().pattern(0, 0, function () {\r
+            this.add(v)\r
+          })\r
+        }\r
+      }\r
+\r
+      // ensure correct numeric values (also accepts NaN and Infinity)\r
+      if (typeof v === 'number') {\r
+        v = new SVG.Number(v)\r
+      } else if (SVG.Color.isColor(v)) {\r
+        // ensure full hex color\r
+        v = new SVG.Color(v)\r
+      } else if (Array.isArray(v)) {\r
+        // parse array values\r
+        v = new SVG.Array(v)\r
+      }\r
+\r
+      // if the passed attribute is leading...\r
+      if (a === 'leading') {\r
+        // ... call the leading method instead\r
+        if (this.leading) {\r
+          this.leading(v)\r
+        }\r
+      } else {\r
+        // set given attribute on node\r
+        typeof n === 'string' ? this.node.setAttributeNS(n, a, v.toString())\r
+          : this.node.setAttribute(a, v.toString())\r
+      }\r
+\r
+      // rebuild if required\r
+      if (this.rebuild && (a === 'font-size' || a === 'x')) {\r
+        this.rebuild(a, v)\r
+      }\r
+    }\r
+\r
+    return this\r
+  }\r
+})\r
+
+/* global ensureCentre, capitalize, arrayToMatrix */\r
+\r
+SVG.extend(SVG.Element, {\r
+  // Add transformations\r
+  transform: function (o, relative) {\r
+    // get target in case of the fx module, otherwise reference this\r
+    var target = this\r
+    var matrix, bbox\r
+\r
+    // act as a getter\r
+    if (typeof o !== 'object') {\r
+      // get current matrix\r
+      matrix = new SVG.Matrix(target).extract()\r
+\r
+      return typeof o === 'string' ? matrix[o] : matrix\r
+    }\r
+\r
+    // get current matrix\r
+    matrix = new SVG.Matrix(target)\r
+\r
+    // ensure relative flag\r
+    relative = !!relative || !!o.relative\r
+\r
+    // act on matrix\r
+    if (o.a != null) {\r
+      matrix = relative\r
+        ? matrix.multiply(new SVG.Matrix(o))\r
+        : new SVG.Matrix(o)\r
+\r
+    // act on rotation\r
+    } else if (o.rotation != null) {\r
+      // ensure centre point\r
+      ensureCentre(o, target)\r
+\r
+      // apply transformation\r
+      matrix = relative\r
+        ? matrix.rotate(o.rotation, o.cx, o.cy)\r
+        : matrix.rotate(o.rotation - matrix.extract().rotation, o.cx, o.cy)\r
+\r
+    // act on scale\r
+    } else if (o.scale != null || o.scaleX != null || o.scaleY != null) {\r
+      // ensure centre point\r
+      ensureCentre(o, target)\r
+\r
+      // ensure scale values on both axes\r
+      o.scaleX = o.scale != null ? o.scale : o.scaleX != null ? o.scaleX : 1\r
+      o.scaleY = o.scale != null ? o.scale : o.scaleY != null ? o.scaleY : 1\r
+\r
+      if (!relative) {\r
+        // absolute; multiply inversed values\r
+        var e = matrix.extract()\r
+        o.scaleX = o.scaleX * 1 / e.scaleX\r
+        o.scaleY = o.scaleY * 1 / e.scaleY\r
+      }\r
+\r
+      matrix = matrix.scale(o.scaleX, o.scaleY, o.cx, o.cy)\r
+\r
+    // act on skew\r
+    } else if (o.skew != null || o.skewX != null || o.skewY != null) {\r
+      // ensure centre point\r
+      ensureCentre(o, target)\r
+\r
+      // ensure skew values on both axes\r
+      o.skewX = o.skew != null ? o.skew : o.skewX != null ? o.skewX : 0\r
+      o.skewY = o.skew != null ? o.skew : o.skewY != null ? o.skewY : 0\r
+\r
+      if (!relative) {\r
+        // absolute; reset skew values\r
+        var el = matrix.extract()\r
+        matrix = matrix.multiply(new SVG.Matrix().skew(el.skewX, el.skewY, el.cx, el.cy).inverse())\r
+      }\r
+\r
+      matrix = matrix.skew(o.skewX, o.skewY, o.cx, o.cy)\r
+\r
+    // act on flip\r
+    } else if (o.flip) {\r
+      if (o.flip === 'x' || o.flip === 'y') {\r
+        o.offset = o.offset == null ? target.bbox()['c' + o.flip] : o.offset\r
+      } else {\r
+        if (o.offset == null) {\r
+          bbox = target.bbox()\r
+          o.flip = bbox.cx\r
+          o.offset = bbox.cy\r
+        } else {\r
+          o.flip = o.offset\r
+        }\r
+      }\r
+\r
+      matrix = new SVG.Matrix().flip(o.flip, o.offset)\r
+\r
+    // act on translate\r
+    } else if (o.x != null || o.y != null) {\r
+      if (relative) {\r
+        // relative\r
+        matrix = matrix.translate(o.x, o.y)\r
+      } else {\r
+        // absolute\r
+        if (o.x != null) matrix.e = o.x\r
+        if (o.y != null) matrix.f = o.y\r
+      }\r
+    }\r
+\r
+    return this.attr('transform', matrix)\r
+  }\r
+})\r
+\r
+SVG.extend(SVG.FX, {\r
+  transform: function (o, relative) {\r
+    // get target in case of the fx module, otherwise reference this\r
+    var target = this.target()\r
+    var matrix, bbox\r
+\r
+    // act as a getter\r
+    if (typeof o !== 'object') {\r
+      // get current matrix\r
+      matrix = new SVG.Matrix(target).extract()\r
+      return typeof o === 'string' ? matrix[o] : matrix\r
+    }\r
+\r
+    // ensure relative flag\r
+    relative = !!relative || !!o.relative\r
+\r
+    // act on matrix\r
+    if (o.a != null) {\r
+      matrix = new SVG.Matrix(o)\r
+\r
+    // act on rotation\r
+    } else if (o.rotation != null) {\r
+      // ensure centre point\r
+      ensureCentre(o, target)\r
+\r
+      // apply transformation\r
+      matrix = new SVG.Rotate(o.rotation, o.cx, o.cy)\r
+\r
+    // act on scale\r
+    } else if (o.scale != null || o.scaleX != null || o.scaleY != null) {\r
+      // ensure centre point\r
+      ensureCentre(o, target)\r
+\r
+      // ensure scale values on both axes\r
+      o.scaleX = o.scale != null ? o.scale : o.scaleX != null ? o.scaleX : 1\r
+      o.scaleY = o.scale != null ? o.scale : o.scaleY != null ? o.scaleY : 1\r
+\r
+      matrix = new SVG.Scale(o.scaleX, o.scaleY, o.cx, o.cy)\r
+\r
+    // act on skew\r
+    } else if (o.skewX != null || o.skewY != null) {\r
+      // ensure centre point\r
+      ensureCentre(o, target)\r
+\r
+      // ensure skew values on both axes\r
+      o.skewX = o.skewX != null ? o.skewX : 0\r
+      o.skewY = o.skewY != null ? o.skewY : 0\r
+\r
+      matrix = new SVG.Skew(o.skewX, o.skewY, o.cx, o.cy)\r
+\r
+    // act on flip\r
+    } else if (o.flip) {\r
+      if (o.flip === 'x' || o.flip === 'y') {\r
+        o.offset = o.offset == null ? target.bbox()['c' + o.flip] : o.offset\r
+      } else {\r
+        if (o.offset == null) {\r
+          bbox = target.bbox()\r
+          o.flip = bbox.cx\r
+          o.offset = bbox.cy\r
+        } else {\r
+          o.flip = o.offset\r
+        }\r
+      }\r
+\r
+      matrix = new SVG.Matrix().flip(o.flip, o.offset)\r
+\r
+    // act on translate\r
+    } else if (o.x != null || o.y != null) {\r
+      matrix = new SVG.Translate(o.x, o.y)\r
+    }\r
+\r
+    if (!matrix) return this\r
+\r
+    matrix.relative = relative\r
+\r
+    this.last().transforms.push(matrix)\r
+\r
+    return this._callStart()\r
+  }\r
+})\r
+\r
+SVG.extend(SVG.Element, {\r
+  // Reset all transformations\r
+  untransform: function () {\r
+    return this.attr('transform', null)\r
+  },\r
+  // merge the whole transformation chain into one matrix and returns it\r
+  matrixify: function () {\r
+    var matrix = (this.attr('transform') || '')\r
+      // split transformations\r
+      .split(SVG.regex.transforms).slice(0, -1).map(function (str) {\r
+        // generate key => value pairs\r
+        var kv = str.trim().split('(')\r
+        return [kv[0], kv[1].split(SVG.regex.delimiter).map(function (str) { return parseFloat(str) })]\r
+      })\r
+      // merge every transformation into one matrix\r
+      .reduce(function (matrix, transform) {\r
+        if (transform[0] === 'matrix') return matrix.multiply(arrayToMatrix(transform[1]))\r
+        return matrix[transform[0]].apply(matrix, transform[1])\r
+      }, new SVG.Matrix())\r
+\r
+    return matrix\r
+  },\r
+  // add an element to another parent without changing the visual representation on the screen\r
+  toParent: function (parent) {\r
+    if (this === parent) return this\r
+    var ctm = this.screenCTM()\r
+    var pCtm = parent.screenCTM().inverse()\r
+\r
+    this.addTo(parent).untransform().transform(pCtm.multiply(ctm))\r
+\r
+    return this\r
+  },\r
+  // same as above with parent equals root-svg\r
+  toDoc: function () {\r
+    return this.toParent(this.doc())\r
+  }\r
+\r
+})\r
+\r
+SVG.Transformation = SVG.invent({\r
+\r
+  create: function (source, inversed) {\r
+    if (arguments.length > 1 && typeof inversed !== 'boolean') {\r
+      return this.constructor.bind(this)([].slice.call(arguments))\r
+    }\r
+\r
+    var i, len\r
+    if (Array.isArray(source)) {\r
+      for (i = 0, len = this.arguments.length; i < len; ++i) {\r
+        this[this.arguments[i]] = source[i]\r
+      }\r
+    } else if (typeof source === 'object') {\r
+      for (i = 0, len = this.arguments.length; i < len; ++i) {\r
+        this[this.arguments[i]] = source[this.arguments[i]]\r
+      }\r
+    }\r
+\r
+    this.inversed = false\r
+\r
+    if (inversed === true) {\r
+      this.inversed = true\r
+    }\r
+  },\r
+\r
+  extend: {\r
+\r
+    arguments: [],\r
+    method: '',\r
+\r
+    at: function (pos) {\r
+      var params = []\r
+\r
+      for (var i = 0, len = this.arguments.length; i < len; ++i) {\r
+        params.push(this[this.arguments[i]])\r
+      }\r
+\r
+      var m = this._undo || new SVG.Matrix()\r
+\r
+      m = new SVG.Matrix().morph(SVG.Matrix.prototype[this.method].apply(m, params)).at(pos)\r
+\r
+      return this.inversed ? m.inverse() : m\r
+    },\r
+\r
+    undo: function (o) {\r
+      for (var i = 0, len = this.arguments.length; i < len; ++i) {\r
+        o[this.arguments[i]] = typeof this[this.arguments[i]] === 'undefined' ? 0 : o[this.arguments[i]]\r
+      }\r
+\r
+      // The method SVG.Matrix.extract which was used before calling this\r
+      // method to obtain a value for the parameter o doesn't return a cx and\r
+      // a cy so we use the ones that were provided to this object at its creation\r
+      o.cx = this.cx\r
+      o.cy = this.cy\r
+\r
+      this._undo = new SVG[capitalize(this.method)](o, true).at(1)\r
+      return this\r
+    }\r
+\r
+  }\r
+\r
+})\r
+\r
+SVG.Translate = SVG.invent({\r
+\r
+  parent: SVG.Matrix,\r
+  inherit: SVG.Transformation,\r
+\r
+  create: function (source, inversed) {\r
+    this.constructor.apply(this, [].slice.call(arguments))\r
+  },\r
+\r
+  extend: {\r
+    arguments: ['transformedX', 'transformedY'],\r
+    method: 'translate'\r
+  }\r
+\r
+})\r
+\r
+SVG.Rotate = SVG.invent({\r
+\r
+  parent: SVG.Matrix,\r
+  inherit: SVG.Transformation,\r
+\r
+  create: function (source, inversed) {\r
+    this.constructor.apply(this, [].slice.call(arguments))\r
+  },\r
+\r
+  extend: {\r
+    arguments: ['rotation', 'cx', 'cy'],\r
+    method: 'rotate',\r
+    at: function (pos) {\r
+      var m = new SVG.Matrix().rotate(new SVG.Number().morph(this.rotation - (this._undo ? this._undo.rotation : 0)).at(pos), this.cx, this.cy)\r
+      return this.inversed ? m.inverse() : m\r
+    },\r
+    undo: function (o) {\r
+      this._undo = o\r
+      return this\r
+    }\r
+  }\r
+\r
+})\r
+\r
+SVG.Scale = SVG.invent({\r
+\r
+  parent: SVG.Matrix,\r
+  inherit: SVG.Transformation,\r
+\r
+  create: function (source, inversed) {\r
+    this.constructor.apply(this, [].slice.call(arguments))\r
+  },\r
+\r
+  extend: {\r
+    arguments: ['scaleX', 'scaleY', 'cx', 'cy'],\r
+    method: 'scale'\r
+  }\r
+\r
+})\r
+\r
+SVG.Skew = SVG.invent({\r
+\r
+  parent: SVG.Matrix,\r
+  inherit: SVG.Transformation,\r
+\r
+  create: function (source, inversed) {\r
+    this.constructor.apply(this, [].slice.call(arguments))\r
+  },\r
+\r
+  extend: {\r
+    arguments: ['skewX', 'skewY', 'cx', 'cy'],\r
+    method: 'skew'\r
+  }\r
+})\r
+
+/* global camelCase */\r
+\r
+SVG.extend(SVG.Element, {\r
+  // Dynamic style generator\r
+  css: function (s, v) {\r
+    var ret = {}\r
+    var t, i\r
+    if (arguments.length === 0) {\r
+      // get full style as object\r
+      this.node.style.cssText.split(/\s*;\s*/).filter(function (el) { return !!el.length }).forEach(function (el) {\r
+        t = el.split(/\s*:\s*/)\r
+        ret[t[0]] = t[1]\r
+      })\r
+      return ret\r
+    }\r
+\r
+    if (arguments.length < 2) {\r
+      // get style properties in the array\r
+      if (Array.isArray(s)) {\r
+        for (i = s.length; i--;) {\r
+          ret[camelCase(s[i])] = this.node.style[camelCase(s[i])]\r
+        }\r
+        return ret\r
+      }\r
+\r
+      // get style for property\r
+      if (typeof s === 'string') {\r
+        return this.node.style[camelCase(s)]\r
+      }\r
+\r
+      // set styles in object\r
+      if (typeof s === 'object') {\r
+        for (i in s) {\r
+          // set empty string if null/undefined/'' was given\r
+          this.node.style[camelCase(i)] = (s[i] == null || SVG.regex.isBlank.test(s[i])) ? '' : s[i]\r
+        }\r
+      }\r
+    }\r
+\r
+    // set style for property\r
+    if (arguments.length === 2) {\r
+      this.node.style[camelCase(s)] = (v == null || SVG.regex.isBlank.test(v)) ? '' : v\r
+    }\r
+\r
+    return this\r
+  }\r
+})\r
+
+/* global createElement */\r
+\r
+SVG.Parent = SVG.invent({\r
+  // Initialize node\r
+  create: function (node) {\r
+    this.constructor(node)\r
+  },\r
+\r
+  // Inherit from\r
+  inherit: SVG.Element,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Returns all child elements\r
+    children: function () {\r
+      return SVG.utils.map(this.node.children, function (node) {\r
+        return SVG.adopt(node)\r
+      })\r
+    },\r
+    // Add given element at a position\r
+    add: function (element, i) {\r
+      element = createElement(element)\r
+\r
+      if (element.node !== this.node.children[i]) {\r
+        this.node.insertBefore(element.node, this.node.children[i] || null)\r
+      }\r
+\r
+      return this\r
+    },\r
+    // Basically does the same as `add()` but returns the added element instead\r
+    put: function (element, i) {\r
+      this.add(element, i)\r
+      return element.instance || element\r
+    },\r
+    // Checks if the given element is a child\r
+    has: function (element) {\r
+      return this.index(element) >= 0\r
+    },\r
+    // Gets index of given element\r
+    index: function (element) {\r
+      return [].slice.call(this.node.children).indexOf(element.node)\r
+    },\r
+    // Get a element at the given index\r
+    get: function (i) {\r
+      return SVG.adopt(this.node.children[i])\r
+    },\r
+    // Get first child\r
+    first: function () {\r
+      return this.get(0)\r
+    },\r
+    // Get the last child\r
+    last: function () {\r
+      return this.get(this.node.children.length - 1)\r
+    },\r
+    // Iterates over all children and invokes a given block\r
+    each: function (block, deep) {\r
+      var children = this.children()\r
+      var i, il\r
+\r
+      for (i = 0, il = children.length; i < il; i++) {\r
+        if (children[i] instanceof SVG.Element) {\r
+          block.apply(children[i], [i, children])\r
+        }\r
+\r
+        if (deep && (children[i] instanceof SVG.Parent)) {\r
+          children[i].each(block, deep)\r
+        }\r
+      }\r
+\r
+      return this\r
+    },\r
+    // Remove a given child\r
+    removeElement: function (element) {\r
+      this.node.removeChild(element.node)\r
+\r
+      return this\r
+    },\r
+    // Remove all elements in this container\r
+    clear: function () {\r
+      // remove children\r
+      while (this.node.hasChildNodes()) {\r
+        this.node.removeChild(this.node.lastChild)\r
+      }\r
+\r
+      // remove defs reference\r
+      delete this._defs\r
+\r
+      return this\r
+    }\r
+  }\r
+\r
+})\r
+
+SVG.extend(SVG.Parent, {\r
+  flatten: function (parent) {\r
+    // flattens is only possible for nested svgs and groups\r
+    if (!(this instanceof SVG.G || this instanceof SVG.Doc)) {\r
+      return this\r
+    }\r
+\r
+    parent = parent || (this instanceof SVG.Doc && this.isRoot() ? this : this.parent(SVG.Parent))\r
+\r
+    this.each(function () {\r
+      if (this instanceof SVG.Defs) return this\r
+      if (this instanceof SVG.Parent) return this.flatten(parent)\r
+      return this.toParent(parent)\r
+    })\r
+\r
+    // we need this so that SVG.Doc does not get removed\r
+    this.node.firstElementChild || this.remove()\r
+\r
+    return this\r
+  },\r
+  ungroup: function (parent) {\r
+    // ungroup is only possible for nested svgs and groups\r
+    if (!(this instanceof SVG.G || (this instanceof SVG.Doc && !this.isRoot()))) {\r
+      return this\r
+    }\r
+\r
+    parent = parent || this.parent(SVG.Parent)\r
+\r
+    this.each(function () {\r
+      return this.toParent(parent)\r
+    })\r
+\r
+    // we need this so that SVG.Doc does not get removed\r
+    this.remove()\r
+\r
+    return this\r
+  }\r
+})\r
+
+SVG.Container = SVG.invent({\r
+  // Initialize node\r
+  create: function (node) {\r
+    this.constructor(node)\r
+  },\r
+\r
+  // Inherit from\r
+  inherit: SVG.Parent\r
+})\r
+
+// Add events to elements\r
+\r
+;[ 'click',\r
+  'dblclick',\r
+  'mousedown',\r
+  'mouseup',\r
+  'mouseover',\r
+  'mouseout',\r
+  'mousemove',\r
+  'mouseenter',\r
+  'mouseleave',\r
+  'touchstart',\r
+  'touchmove',\r
+  'touchleave',\r
+  'touchend',\r
+  'touchcancel' ].forEach(function (event) {\r
+    // add event to SVG.Element\r
+    SVG.Element.prototype[event] = function (f) {\r
+    // bind event to element rather than element node\r
+      SVG.on(this, event, f)\r
+      return this\r
+    }\r
+  })\r
+\r
+SVG.listenerId = 0\r
+\r
+// Add event binder in the SVG namespace\r
+SVG.on = function (node, events, listener, binding, options) {\r
+  var l = listener.bind(binding || node)\r
+  var n = node instanceof SVG.Element ? node.node : node\r
+\r
+  // ensure instance object for nodes which are not adopted\r
+  n.instance = n.instance || {events: {}}\r
+\r
+  var bag = n.instance.events\r
+\r
+  // add id to listener\r
+  if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++SVG.listenerId }\r
+\r
+  events.split(SVG.regex.delimiter).forEach(function (event) {\r
+    var ev = event.split('.')[0]\r
+    var ns = event.split('.')[1] || '*'\r
+\r
+    // ensure valid object\r
+    bag[ev] = bag[ev] || {}\r
+    bag[ev][ns] = bag[ev][ns] || {}\r
+\r
+    // reference listener\r
+    bag[ev][ns][listener._svgjsListenerId] = l\r
+\r
+    // add listener\r
+    n.addEventListener(ev, l, options || false)\r
+  })\r
+}\r
+\r
+// Add event unbinder in the SVG namespace\r
+SVG.off = function (node, events, listener, options) {\r
+  var n = node instanceof SVG.Element ? node.node : node\r
+  if (!n.instance) return\r
+\r
+  // listener can be a function or a number\r
+  if (typeof listener === 'function') {\r
+    listener = listener._svgjsListenerId\r
+    if (!listener) return\r
+  }\r
+\r
+  var bag = n.instance.events\r
+\r
+  ;(events || '').split(SVG.regex.delimiter).forEach(function (event) {\r
+    var ev = event && event.split('.')[0]\r
+    var ns = event && event.split('.')[1]\r
+    var namespace, l\r
+\r
+    if (listener) {\r
+      // remove listener reference\r
+      if (bag[ev] && bag[ev][ns || '*']) {\r
+        // removeListener\r
+        n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false)\r
+\r
+        delete bag[ev][ns || '*'][listener]\r
+      }\r
+    } else if (ev && ns) {\r
+      // remove all listeners for a namespaced event\r
+      if (bag[ev] && bag[ev][ns]) {\r
+        for (l in bag[ev][ns]) { SVG.off(n, [ev, ns].join('.'), l) }\r
+\r
+        delete bag[ev][ns]\r
+      }\r
+    } else if (ns) {\r
+      // remove all listeners for a specific namespace\r
+      for (event in bag) {\r
+        for (namespace in bag[event]) {\r
+          if (ns === namespace) { SVG.off(n, [event, ns].join('.')) }\r
+        }\r
+      }\r
+    } else if (ev) {\r
+      // remove all listeners for the event\r
+      if (bag[ev]) {\r
+        for (namespace in bag[ev]) { SVG.off(n, [ev, namespace].join('.')) }\r
+\r
+        delete bag[ev]\r
+      }\r
+    } else {\r
+      // remove all listeners on a given node\r
+      for (event in bag) { SVG.off(n, event) }\r
+\r
+      n.instance.events = {}\r
+    }\r
+  })\r
+}\r
+\r
+SVG.extend(SVG.Element, {\r
+  // Bind given event to listener\r
+  on: function (event, listener, binding, options) {\r
+    SVG.on(this, event, listener, binding, options)\r
+    return this\r
+  },\r
+  // Unbind event from listener\r
+  off: function (event, listener) {\r
+    SVG.off(this.node, event, listener)\r
+    return this\r
+  },\r
+  dispatch: function (event, data) {\r
+    // Dispatch event\r
+    if (event instanceof window.Event) {\r
+      this.node.dispatchEvent(event)\r
+    } else {\r
+      this.node.dispatchEvent(event = new window.CustomEvent(event, {detail: data, cancelable: true}))\r
+    }\r
+    return event\r
+  },\r
+  // Fire given event\r
+  fire: function (event, data) {\r
+    this.dispatch(event, data)\r
+    return this\r
+  }\r
+})\r
+
+SVG.Defs = SVG.invent({\r
+  // Initialize node\r
+  create: 'defs',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Container\r
+})\r
+
+SVG.G = SVG.invent({\r
+  // Initialize node\r
+  create: 'g',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Container,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Move over x-axis\r
+    x: function (x) {\r
+      return x == null ? this.transform('x') : this.transform({ x: x - this.x() }, true)\r
+    },\r
+    // Move over y-axis\r
+    y: function (y) {\r
+      return y == null ? this.transform('y') : this.transform({ y: y - this.y() }, true)\r
+    },\r
+    // Move by center over x-axis\r
+    cx: function (x) {\r
+      return x == null ? this.gbox().cx : this.x(x - this.gbox().width / 2)\r
+    },\r
+    // Move by center over y-axis\r
+    cy: function (y) {\r
+      return y == null ? this.gbox().cy : this.y(y - this.gbox().height / 2)\r
+    },\r
+    gbox: function () {\r
+      var bbox = this.bbox()\r
+      var trans = this.transform()\r
+\r
+      bbox.x += trans.x\r
+      bbox.x2 += trans.x\r
+      bbox.cx += trans.x\r
+\r
+      bbox.y += trans.y\r
+      bbox.y2 += trans.y\r
+      bbox.cy += trans.y\r
+\r
+      return bbox\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create a group element\r
+    group: function () {\r
+      return this.put(new SVG.G())\r
+    }\r
+  }\r
+})\r
+
+// ### This module adds backward / forward functionality to elements.\r
+\r
+//\r
+SVG.extend(SVG.Element, {\r
+  // Get all siblings, including myself\r
+  siblings: function () {\r
+    return this.parent().children()\r
+  },\r
+\r
+  // Get the curent position siblings\r
+  position: function () {\r
+    return this.parent().index(this)\r
+  },\r
+\r
+  // Get the next element (will return null if there is none)\r
+  next: function () {\r
+    return this.siblings()[this.position() + 1]\r
+  },\r
+\r
+  // Get the next element (will return null if there is none)\r
+  prev: function () {\r
+    return this.siblings()[this.position() - 1]\r
+  },\r
+\r
+  // Send given element one step forward\r
+  forward: function () {\r
+    var i = this.position() + 1\r
+    var p = this.parent()\r
+\r
+    // move node one step forward\r
+    p.removeElement(this).add(this, i)\r
+\r
+    // make sure defs node is always at the top\r
+    if (p instanceof SVG.Doc) {\r
+      p.node.appendChild(p.defs().node)\r
+    }\r
+\r
+    return this\r
+  },\r
+\r
+  // Send given element one step backward\r
+  backward: function () {\r
+    var i = this.position()\r
+\r
+    if (i > 0) {\r
+      this.parent().removeElement(this).add(this, i - 1)\r
+    }\r
+\r
+    return this\r
+  },\r
+\r
+  // Send given element all the way to the front\r
+  front: function () {\r
+    var p = this.parent()\r
+\r
+    // Move node forward\r
+    p.node.appendChild(this.node)\r
+\r
+    // Make sure defs node is always at the top\r
+    if (p instanceof SVG.Doc) {\r
+      p.node.appendChild(p.defs().node)\r
+    }\r
+\r
+    return this\r
+  },\r
+\r
+  // Send given element all the way to the back\r
+  back: function () {\r
+    if (this.position() > 0) {\r
+      this.parent().removeElement(this).add(this, 0)\r
+    }\r
+\r
+    return this\r
+  },\r
+\r
+  // Inserts a given element before the targeted element\r
+  before: function (element) {\r
+    element.remove()\r
+\r
+    var i = this.position()\r
+\r
+    this.parent().add(element, i)\r
+\r
+    return this\r
+  },\r
+\r
+  // Insters a given element after the targeted element\r
+  after: function (element) {\r
+    element.remove()\r
+\r
+    var i = this.position()\r
+\r
+    this.parent().add(element, i + 1)\r
+\r
+    return this\r
+  }\r
+})\r
+
+SVG.Mask = SVG.invent({\r
+  // Initialize node\r
+  create: 'mask',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Container,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Unmask all masked elements and remove itself\r
+    remove: function () {\r
+      // unmask all targets\r
+      this.targets().forEach(function (el) {\r
+        el.unmask()\r
+      })\r
+\r
+      // remove mask from parent\r
+      return SVG.Element.prototype.remove.call(this)\r
+    },\r
+\r
+    targets: function () {\r
+      return SVG.select('svg [mask*="' + this.id() + '"]')\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create masking element\r
+    mask: function () {\r
+      return this.defs().put(new SVG.Mask())\r
+    }\r
+  }\r
+})\r
+\r
+SVG.extend(SVG.Element, {\r
+  // Distribute mask to svg element\r
+  maskWith: function (element) {\r
+    // use given mask or create a new one\r
+    var masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element)\r
+\r
+    // apply mask\r
+    return this.attr('mask', 'url("#' + masker.id() + '")')\r
+  },\r
+  // Unmask element\r
+  unmask: function () {\r
+    return this.attr('mask', null)\r
+  },\r
+  masker: function () {\r
+    return this.reference('mask')\r
+  }\r
+})\r
+
+SVG.ClipPath = SVG.invent({\r
+  // Initialize node\r
+  create: 'clipPath',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Container,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Unclip all clipped elements and remove itself\r
+    remove: function () {\r
+      // unclip all targets\r
+      this.targets().forEach(function (el) {\r
+        el.unclip()\r
+      })\r
+\r
+      // remove clipPath from parent\r
+      return SVG.Element.prototype.remove.call(this)\r
+    },\r
+\r
+    targets: function () {\r
+      return SVG.select('svg [clip-path*="' + this.id() + '"]')\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create clipping element\r
+    clip: function () {\r
+      return this.defs().put(new SVG.ClipPath())\r
+    }\r
+  }\r
+})\r
+\r
+//\r
+SVG.extend(SVG.Element, {\r
+  // Distribute clipPath to svg element\r
+  clipWith: function (element) {\r
+    // use given clip or create a new one\r
+    var clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element)\r
+\r
+    // apply mask\r
+    return this.attr('clip-path', 'url("#' + clipper.id() + '")')\r
+  },\r
+  // Unclip element\r
+  unclip: function () {\r
+    return this.attr('clip-path', null)\r
+  },\r
+  clipper: function () {\r
+    return this.reference('clip-path')\r
+  }\r
+\r
+})\r
+
+SVG.Gradient = SVG.invent({\r
+  // Initialize node\r
+  create: function (type) {\r
+    this.constructor(typeof type === 'object' ? type : SVG.create(type + 'Gradient'))\r
+  },\r
+\r
+  // Inherit from\r
+  inherit: SVG.Container,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Add a color stop\r
+    stop: function (offset, color, opacity) {\r
+      return this.put(new SVG.Stop()).update(offset, color, opacity)\r
+    },\r
+    // Update gradient\r
+    update: function (block) {\r
+      // remove all stops\r
+      this.clear()\r
+\r
+      // invoke passed block\r
+      if (typeof block === 'function') {\r
+        block.call(this, this)\r
+      }\r
+\r
+      return this\r
+    },\r
+    // Return the fill id\r
+    url: function () {\r
+      return 'url(#' + this.id() + ')'\r
+    },\r
+    // Alias string convertion to fill\r
+    toString: function () {\r
+      return this.url()\r
+    },\r
+    // custom attr to handle transform\r
+    attr: function (a, b, c) {\r
+      if (a === 'transform') a = 'gradientTransform'\r
+      return SVG.Container.prototype.attr.call(this, a, b, c)\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create gradient element in defs\r
+    gradient: function (type, block) {\r
+      return this.defs().gradient(type, block)\r
+    }\r
+  }\r
+})\r
+\r
+// Add animatable methods to both gradient and fx module\r
+SVG.extend([SVG.Gradient, SVG.FX], {\r
+  // From position\r
+  from: function (x, y) {\r
+    return (this._target || this).type === 'radialGradient'\r
+      ? this.attr({ fx: new SVG.Number(x), fy: new SVG.Number(y) })\r
+      : this.attr({ x1: new SVG.Number(x), y1: new SVG.Number(y) })\r
+  },\r
+  // To position\r
+  to: function (x, y) {\r
+    return (this._target || this).type === 'radialGradient'\r
+      ? this.attr({ cx: new SVG.Number(x), cy: new SVG.Number(y) })\r
+      : this.attr({ x2: new SVG.Number(x), y2: new SVG.Number(y) })\r
+  }\r
+})\r
+\r
+// Base gradient generation\r
+SVG.extend(SVG.Defs, {\r
+  // define gradient\r
+  gradient: function (type, block) {\r
+    return this.put(new SVG.Gradient(type)).update(block)\r
+  }\r
+\r
+})\r
+\r
+SVG.Stop = SVG.invent({\r
+  // Initialize node\r
+  create: 'stop',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Element,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // add color stops\r
+    update: function (o) {\r
+      if (typeof o === 'number' || o instanceof SVG.Number) {\r
+        o = {\r
+          offset: arguments[0],\r
+          color: arguments[1],\r
+          opacity: arguments[2]\r
+        }\r
+      }\r
+\r
+      // set attributes\r
+      if (o.opacity != null) this.attr('stop-opacity', o.opacity)\r
+      if (o.color != null) this.attr('stop-color', o.color)\r
+      if (o.offset != null) this.attr('offset', new SVG.Number(o.offset))\r
+\r
+      return this\r
+    }\r
+  }\r
+\r
+})\r
+
+SVG.Pattern = SVG.invent({\r
+  // Initialize node\r
+  create: 'pattern',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Container,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Return the fill id\r
+    url: function () {\r
+      return 'url(#' + this.id() + ')'\r
+    },\r
+    // Update pattern by rebuilding\r
+    update: function (block) {\r
+      // remove content\r
+      this.clear()\r
+\r
+      // invoke passed block\r
+      if (typeof block === 'function') {\r
+        block.call(this, this)\r
+      }\r
+\r
+      return this\r
+    },\r
+    // Alias string convertion to fill\r
+    toString: function () {\r
+      return this.url()\r
+    },\r
+    // custom attr to handle transform\r
+    attr: function (a, b, c) {\r
+      if (a === 'transform') a = 'patternTransform'\r
+      return SVG.Container.prototype.attr.call(this, a, b, c)\r
+    }\r
+\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create pattern element in defs\r
+    pattern: function (width, height, block) {\r
+      return this.defs().pattern(width, height, block)\r
+    }\r
+  }\r
+})\r
+\r
+SVG.extend(SVG.Defs, {\r
+  // Define gradient\r
+  pattern: function (width, height, block) {\r
+    return this.put(new SVG.Pattern()).update(block).attr({\r
+      x: 0,\r
+      y: 0,\r
+      width: width,\r
+      height: height,\r
+      patternUnits: 'userSpaceOnUse'\r
+    })\r
+  }\r
+\r
+})\r
+
+SVG.Doc = SVG.invent({\r
+  // Initialize node\r
+  create: function (node) {\r
+    this.constructor(node || SVG.create('svg'))\r
+\r
+    // set svg element attributes and ensure defs node\r
+    this.namespace()\r
+  },\r
+\r
+  // Inherit from\r
+  inherit: SVG.Container,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    isRoot: function () {\r
+      return !this.node.parentNode || !(this.node.parentNode instanceof window.SVGElement) || this.node.parentNode.nodeName === '#document'\r
+    },\r
+    // Check if this is a root svg. If not, call docs from this element\r
+    doc: function () {\r
+      if (this.isRoot()) return this\r
+      return SVG.Element.prototype.doc.call(this)\r
+    },\r
+    // Add namespaces\r
+    namespace: function () {\r
+      if (!this.isRoot()) return this.doc().namespace()\r
+      return this\r
+        .attr({ xmlns: SVG.ns, version: '1.1' })\r
+        .attr('xmlns:xlink', SVG.xlink, SVG.xmlns)\r
+        .attr('xmlns:svgjs', SVG.svgjs, SVG.xmlns)\r
+    },\r
+    // Creates and returns defs element\r
+    defs: function () {\r
+      if (!this.isRoot()) return this.doc().defs()\r
+      return SVG.adopt(this.node.getElementsByTagName('defs')[0]) || this.put(new SVG.Defs())\r
+    },\r
+    // custom parent method\r
+    parent: function (type) {\r
+      if (this.isRoot()) {\r
+        return this.node.parentNode.nodeName === '#document' ? null : this.node.parentNode\r
+      }\r
+\r
+      return SVG.Element.prototype.parent.call(this, type)\r
+    },\r
+    // Removes the doc from the DOM\r
+    remove: function () {\r
+      if (!this.isRoot()) {\r
+        return SVG.Element.prototype.remove.call(this)\r
+      }\r
+\r
+      if (this.parent()) {\r
+        this.parent().removeChild(this.node)\r
+      }\r
+\r
+      return this\r
+    },\r
+    clear: function () {\r
+      // remove children\r
+      while (this.node.hasChildNodes()) {\r
+        this.node.removeChild(this.node.lastChild)\r
+      }\r
+      return this\r
+    }\r
+  },\r
+  construct: {\r
+    // Create nested svg document\r
+    nested: function () {\r
+      return this.put(new SVG.Doc())\r
+    }\r
+  }\r
+})\r
+
+\r
+SVG.Shape = SVG.invent({\r
+  // Initialize node\r
+  create: function (node) {\r
+    this.constructor(node)\r
+  },\r
+\r
+  // Inherit from\r
+  inherit: SVG.Element\r
+})\r
+
+\r
+SVG.Bare = SVG.invent({\r
+  // Initialize\r
+  create: function (element, inherit) {\r
+    // construct element\r
+    this.constructor(SVG.create(element))\r
+\r
+    // inherit custom methods\r
+    if (inherit) {\r
+      for (var method in inherit.prototype) {\r
+        if (typeof inherit.prototype[method] === 'function') {\r
+          this[method] = inherit.prototype[method]\r
+        }\r
+      }\r
+    }\r
+  },\r
+\r
+  // Inherit from\r
+  inherit: SVG.Element,\r
+\r
+  // Add methods\r
+  extend: {\r
+    // Insert some plain text\r
+    words: function (text) {\r
+      // remove contents\r
+      while (this.node.hasChildNodes()) {\r
+        this.node.removeChild(this.node.lastChild)\r
+      }\r
+\r
+      // create text node\r
+      this.node.appendChild(document.createTextNode(text))\r
+\r
+      return this\r
+    }\r
+  }\r
+})\r
+\r
+SVG.extend(SVG.Parent, {\r
+  // Create an element that is not described by SVG.js\r
+  element: function (element, inherit) {\r
+    return this.put(new SVG.Bare(element, inherit))\r
+  }\r
+})\r
+
+\r
+SVG.Symbol = SVG.invent({\r
+  // Initialize node\r
+  create: 'symbol',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Container,\r
+\r
+  construct: {\r
+    // create symbol\r
+    symbol: function () {\r
+      return this.put(new SVG.Symbol())\r
+    }\r
+  }\r
+})\r
+
+\r
+SVG.Use = SVG.invent({\r
+  // Initialize node\r
+  create: 'use',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Shape,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Use element as a reference\r
+    element: function (element, file) {\r
+      // Set lined element\r
+      return this.attr('href', (file || '') + '#' + element, SVG.xlink)\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create a use element\r
+    use: function (element, file) {\r
+      return this.put(new SVG.Use()).element(element, file)\r
+    }\r
+  }\r
+})\r
+
+\r
+SVG.Rect = SVG.invent({\r
+  // Initialize node\r
+  create: 'rect',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Shape,\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create a rect element\r
+    rect: function (width, height) {\r
+      return this.put(new SVG.Rect()).size(width, height)\r
+    }\r
+  }\r
+})\r
+
+/* global proportionalSize */\r
+\r
+SVG.Circle = SVG.invent({\r
+  // Initialize node\r
+  create: 'circle',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Shape,\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create circle element, based on ellipse\r
+    circle: function (size) {\r
+      return this.put(new SVG.Circle()).rx(new SVG.Number(size).divide(2)).move(0, 0)\r
+    }\r
+  }\r
+})\r
+\r
+SVG.extend([SVG.Circle, SVG.FX], {\r
+  // Radius x value\r
+  rx: function (rx) {\r
+    return this.attr('r', rx)\r
+  },\r
+  // Alias radius x value\r
+  ry: function (ry) {\r
+    return this.rx(ry)\r
+  }\r
+})\r
+\r
+SVG.Ellipse = SVG.invent({\r
+  // Initialize node\r
+  create: 'ellipse',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Shape,\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create an ellipse\r
+    ellipse: function (width, height) {\r
+      return this.put(new SVG.Ellipse()).size(width, height).move(0, 0)\r
+    }\r
+  }\r
+})\r
+\r
+SVG.extend([SVG.Ellipse, SVG.Rect, SVG.FX], {\r
+  // Radius x value\r
+  rx: function (rx) {\r
+    return this.attr('rx', rx)\r
+  },\r
+  // Radius y value\r
+  ry: function (ry) {\r
+    return this.attr('ry', ry)\r
+  }\r
+})\r
+\r
+// Add common method\r
+SVG.extend([SVG.Circle, SVG.Ellipse], {\r
+    // Move over x-axis\r
+  x: function (x) {\r
+    return x == null ? this.cx() - this.rx() : this.cx(x + this.rx())\r
+  },\r
+    // Move over y-axis\r
+  y: function (y) {\r
+    return y == null ? this.cy() - this.ry() : this.cy(y + this.ry())\r
+  },\r
+    // Move by center over x-axis\r
+  cx: function (x) {\r
+    return x == null ? this.attr('cx') : this.attr('cx', x)\r
+  },\r
+    // Move by center over y-axis\r
+  cy: function (y) {\r
+    return y == null ? this.attr('cy') : this.attr('cy', y)\r
+  },\r
+    // Set width of element\r
+  width: function (width) {\r
+    return width == null ? this.rx() * 2 : this.rx(new SVG.Number(width).divide(2))\r
+  },\r
+    // Set height of element\r
+  height: function (height) {\r
+    return height == null ? this.ry() * 2 : this.ry(new SVG.Number(height).divide(2))\r
+  },\r
+    // Custom size function\r
+  size: function (width, height) {\r
+    var p = proportionalSize(this, width, height)\r
+\r
+    return this\r
+        .rx(new SVG.Number(p.width).divide(2))\r
+        .ry(new SVG.Number(p.height).divide(2))\r
+  }\r
+})\r
+
+/* global proportionalSize */\r
+\r
+SVG.Line = SVG.invent({\r
+  // Initialize node\r
+  create: 'line',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Shape,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Get array\r
+    array: function () {\r
+      return new SVG.PointArray([\r
+        [ this.attr('x1'), this.attr('y1') ],\r
+        [ this.attr('x2'), this.attr('y2') ]\r
+      ])\r
+    },\r
+    // Overwrite native plot() method\r
+    plot: function (x1, y1, x2, y2) {\r
+      if (x1 == null) {\r
+        return this.array()\r
+      } else if (typeof y1 !== 'undefined') {\r
+        x1 = { x1: x1, y1: y1, x2: x2, y2: y2 }\r
+      } else {\r
+        x1 = new SVG.PointArray(x1).toLine()\r
+      }\r
+\r
+      return this.attr(x1)\r
+    },\r
+    // Move by left top corner\r
+    move: function (x, y) {\r
+      return this.attr(this.array().move(x, y).toLine())\r
+    },\r
+    // Set element size to given width and height\r
+    size: function (width, height) {\r
+      var p = proportionalSize(this, width, height)\r
+      return this.attr(this.array().size(p.width, p.height).toLine())\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create a line element\r
+    line: function (x1, y1, x2, y2) {\r
+      // make sure plot is called as a setter\r
+      // x1 is not necessarily a number, it can also be an array, a string and a SVG.PointArray\r
+      return SVG.Line.prototype.plot.apply(\r
+        this.put(new SVG.Line())\r
+      , x1 != null ? [x1, y1, x2, y2] : [0, 0, 0, 0]\r
+      )\r
+    }\r
+  }\r
+})\r
+
+/* global proportionalSize */\r
+\r
+SVG.Polyline = SVG.invent({\r
+  // Initialize node\r
+  create: 'polyline',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Shape,\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create a wrapped polyline element\r
+    polyline: function (p) {\r
+      // make sure plot is called as a setter\r
+      return this.put(new SVG.Polyline()).plot(p || new SVG.PointArray())\r
+    }\r
+  }\r
+})\r
+\r
+SVG.Polygon = SVG.invent({\r
+  // Initialize node\r
+  create: 'polygon',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Shape,\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create a wrapped polygon element\r
+    polygon: function (p) {\r
+      // make sure plot is called as a setter\r
+      return this.put(new SVG.Polygon()).plot(p || new SVG.PointArray())\r
+    }\r
+  }\r
+})\r
+\r
+// Add polygon-specific functions\r
+SVG.extend([SVG.Polyline, SVG.Polygon], {\r
+  // Get array\r
+  array: function () {\r
+    return this._array || (this._array = new SVG.PointArray(this.attr('points')))\r
+  },\r
+\r
+  // Plot new path\r
+  plot: function (p) {\r
+    return (p == null) ? this.array()\r
+      : this.clear().attr('points', typeof p === 'string' ? p\r
+      : (this._array = new SVG.PointArray(p)))\r
+  },\r
+\r
+  // Clear array cache\r
+  clear: function () {\r
+    delete this._array\r
+    return this\r
+  },\r
+\r
+  // Move by left top corner\r
+  move: function (x, y) {\r
+    return this.attr('points', this.array().move(x, y))\r
+  },\r
+\r
+  // Set element size to given width and height\r
+  size: function (width, height) {\r
+    var p = proportionalSize(this, width, height)\r
+    return this.attr('points', this.array().size(p.width, p.height))\r
+  }\r
+})\r
+
+// unify all point to point elements\r
+SVG.extend([SVG.Line, SVG.Polyline, SVG.Polygon], {\r
+  // Define morphable array\r
+  MorphArray: SVG.PointArray,\r
+  // Move by left top corner over x-axis\r
+  x: function (x) {\r
+    return x == null ? this.bbox().x : this.move(x, this.bbox().y)\r
+  },\r
+  // Move by left top corner over y-axis\r
+  y: function (y) {\r
+    return y == null ? this.bbox().y : this.move(this.bbox().x, y)\r
+  },\r
+  // Set width of element\r
+  width: function (width) {\r
+    var b = this.bbox()\r
+\r
+    return width == null ? b.width : this.size(width, b.height)\r
+  },\r
+  // Set height of element\r
+  height: function (height) {\r
+    var b = this.bbox()\r
+\r
+    return height == null ? b.height : this.size(b.width, height)\r
+  }\r
+})\r
+
+/* global proportionalSize */\r
+\r
+SVG.Path = SVG.invent({\r
+  // Initialize node\r
+  create: 'path',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Shape,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Define morphable array\r
+    MorphArray: SVG.PathArray,\r
+    // Get array\r
+    array: function () {\r
+      return this._array || (this._array = new SVG.PathArray(this.attr('d')))\r
+    },\r
+    // Plot new path\r
+    plot: function (d) {\r
+      return (d == null) ? this.array()\r
+        : this.clear().attr('d', typeof d === 'string' ? d : (this._array = new SVG.PathArray(d)))\r
+    },\r
+    // Clear array cache\r
+    clear: function () {\r
+      delete this._array\r
+      return this\r
+    },\r
+    // Move by left top corner\r
+    move: function (x, y) {\r
+      return this.attr('d', this.array().move(x, y))\r
+    },\r
+    // Move by left top corner over x-axis\r
+    x: function (x) {\r
+      return x == null ? this.bbox().x : this.move(x, this.bbox().y)\r
+    },\r
+    // Move by left top corner over y-axis\r
+    y: function (y) {\r
+      return y == null ? this.bbox().y : this.move(this.bbox().x, y)\r
+    },\r
+    // Set element size to given width and height\r
+    size: function (width, height) {\r
+      var p = proportionalSize(this, width, height)\r
+      return this.attr('d', this.array().size(p.width, p.height))\r
+    },\r
+    // Set width of element\r
+    width: function (width) {\r
+      return width == null ? this.bbox().width : this.size(width, this.bbox().height)\r
+    },\r
+    // Set height of element\r
+    height: function (height) {\r
+      return height == null ? this.bbox().height : this.size(this.bbox().width, height)\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create a wrapped path element\r
+    path: function (d) {\r
+      // make sure plot is called as a setter\r
+      return this.put(new SVG.Path()).plot(d || new SVG.PathArray())\r
+    }\r
+  }\r
+})\r
+
+SVG.Image = SVG.invent({\r
+  // Initialize node\r
+  create: 'image',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Shape,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // (re)load image\r
+    load: function (url, callback) {\r
+      if (!url) return this\r
+\r
+      var img = new window.Image()\r
+\r
+      SVG.on(img, 'load', function (e) {\r
+        var p = this.parent(SVG.Pattern)\r
+\r
+        // ensure image size\r
+        if (this.width() === 0 && this.height() === 0) {\r
+          this.size(img.width, img.height)\r
+        }\r
+\r
+        if (p instanceof SVG.Pattern) {\r
+          // ensure pattern size if not set\r
+          if (p.width() === 0 && p.height() === 0) {\r
+            p.size(this.width(), this.height())\r
+          }\r
+        }\r
+\r
+        if (typeof callback === 'function') {\r
+          callback.call(this, {\r
+            width: img.width,\r
+            height: img.height,\r
+            ratio: img.width / img.height,\r
+            url: url\r
+          })\r
+        }\r
+      }, this)\r
+\r
+      SVG.on(img, 'load error', function () {\r
+        // dont forget to unbind memory leaking events\r
+        SVG.off(img)\r
+      })\r
+\r
+      return this.attr('href', (img.src = url), SVG.xlink)\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // create image element, load image and set its size\r
+    image: function (source, callback) {\r
+      return this.put(new SVG.Image()).size(0, 0).load(source, callback)\r
+    }\r
+  }\r
+})\r
+
+SVG.Text = SVG.invent({\r
+  // Initialize node\r
+  create: function (node) {\r
+    this.constructor(node || SVG.create('text'))\r
+    this.dom.leading = new SVG.Number(1.3)    // store leading value for rebuilding\r
+    this._rebuild = true                      // enable automatic updating of dy values\r
+    this._build = false                     // disable build mode for adding multiple lines\r
+\r
+    // set default font\r
+    this.attr('font-family', SVG.defaults.attrs['font-family'])\r
+  },\r
+\r
+  // Inherit from\r
+  inherit: SVG.Parent,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Move over x-axis\r
+    x: function (x) {\r
+      // act as getter\r
+      if (x == null) {\r
+        return this.attr('x')\r
+      }\r
+\r
+      return this.attr('x', x)\r
+    },\r
+    // Move over y-axis\r
+    y: function (y) {\r
+      var oy = this.attr('y')\r
+      var o = typeof oy === 'number' ? oy - this.bbox().y : 0\r
+\r
+      // act as getter\r
+      if (y == null) {\r
+        return typeof oy === 'number' ? oy - o : oy\r
+      }\r
+\r
+      return this.attr('y', typeof y === 'number' ? y + o : y)\r
+    },\r
+    // Move center over x-axis\r
+    cx: function (x) {\r
+      return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2)\r
+    },\r
+    // Move center over y-axis\r
+    cy: function (y) {\r
+      return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2)\r
+    },\r
+    // Set the text content\r
+    text: function (text) {\r
+      // act as getter\r
+      if (text === undefined) {\r
+        var children = this.node.childNodes\r
+        var firstLine = 0\r
+        text = ''\r
+\r
+        for (var i = 0, len = children.length; i < len; ++i) {\r
+          // skip textPaths - they are no lines\r
+          if (children[i].nodeName === 'textPath') {\r
+            if (i === 0) firstLine = 1\r
+            continue\r
+          }\r
+\r
+          // add newline if its not the first child and newLined is set to true\r
+          if (i !== firstLine && children[i].nodeType !== 3 && SVG.adopt(children[i]).dom.newLined === true) {\r
+            text += '\n'\r
+          }\r
+\r
+          // add content of this node\r
+          text += children[i].textContent\r
+        }\r
+\r
+        return text\r
+      }\r
+\r
+      // remove existing content\r
+      this.clear().build(true)\r
+\r
+      if (typeof text === 'function') {\r
+        // call block\r
+        text.call(this, this)\r
+      } else {\r
+        // store text and make sure text is not blank\r
+        text = text.split('\n')\r
+\r
+        // build new lines\r
+        for (var j = 0, jl = text.length; j < jl; j++) {\r
+          this.tspan(text[j]).newLine()\r
+        }\r
+      }\r
+\r
+      // disable build mode and rebuild lines\r
+      return this.build(false).rebuild()\r
+    },\r
+    // Set / get leading\r
+    leading: function (value) {\r
+      // act as getter\r
+      if (value == null) {\r
+        return this.dom.leading\r
+      }\r
+\r
+      // act as setter\r
+      this.dom.leading = new SVG.Number(value)\r
+\r
+      return this.rebuild()\r
+    },\r
+    // Rebuild appearance type\r
+    rebuild: function (rebuild) {\r
+      // store new rebuild flag if given\r
+      if (typeof rebuild === 'boolean') {\r
+        this._rebuild = rebuild\r
+      }\r
+\r
+      // define position of all lines\r
+      if (this._rebuild) {\r
+        var self = this\r
+        var blankLineOffset = 0\r
+        var dy = this.dom.leading * new SVG.Number(this.attr('font-size'))\r
+\r
+        this.each(function () {\r
+          if (this.dom.newLined) {\r
+            this.attr('x', self.attr('x'))\r
+\r
+            if (this.text() === '\n') {\r
+              blankLineOffset += dy\r
+            } else {\r
+              this.attr('dy', dy + blankLineOffset)\r
+              blankLineOffset = 0\r
+            }\r
+          }\r
+        })\r
+\r
+        this.fire('rebuild')\r
+      }\r
+\r
+      return this\r
+    },\r
+    // Enable / disable build mode\r
+    build: function (build) {\r
+      this._build = !!build\r
+      return this\r
+    },\r
+    // overwrite method from parent to set data properly\r
+    setData: function (o) {\r
+      this.dom = o\r
+      this.dom.leading = new SVG.Number(o.leading || 1.3)\r
+      return this\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create text element\r
+    text: function (text) {\r
+      return this.put(new SVG.Text()).text(text)\r
+    },\r
+    // Create plain text element\r
+    plain: function (text) {\r
+      return this.put(new SVG.Text()).plain(text)\r
+    }\r
+  }\r
+\r
+})\r
+\r
+SVG.Tspan = SVG.invent({\r
+  // Initialize node\r
+  create: 'tspan',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Parent,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Set text content\r
+    text: function (text) {\r
+      if (text == null) return this.node.textContent + (this.dom.newLined ? '\n' : '')\r
+\r
+      typeof text === 'function' ? text.call(this, this) : this.plain(text)\r
+\r
+      return this\r
+    },\r
+    // Shortcut dx\r
+    dx: function (dx) {\r
+      return this.attr('dx', dx)\r
+    },\r
+    // Shortcut dy\r
+    dy: function (dy) {\r
+      return this.attr('dy', dy)\r
+    },\r
+    // Create new line\r
+    newLine: function () {\r
+      // fetch text parent\r
+      var t = this.parent(SVG.Text)\r
+\r
+      // mark new line\r
+      this.dom.newLined = true\r
+\r
+      // apply new position\r
+      return this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x())\r
+    }\r
+  }\r
+})\r
+\r
+SVG.extend([SVG.Text, SVG.Tspan], {\r
+  // Create plain text node\r
+  plain: function (text) {\r
+    // clear if build mode is disabled\r
+    if (this._build === false) {\r
+      this.clear()\r
+    }\r
+\r
+    // create text node\r
+    this.node.appendChild(document.createTextNode(text))\r
+\r
+    return this\r
+  },\r
+  // Create a tspan\r
+  tspan: function (text) {\r
+    var tspan = new SVG.Tspan()\r
+\r
+    // clear if build mode is disabled\r
+    if (!this._build) {\r
+      this.clear()\r
+    }\r
+\r
+    // add new tspan\r
+    this.node.appendChild(tspan.node)\r
+\r
+    return tspan.text(text)\r
+  },\r
+  // FIXME: Does this also work for textpath?\r
+  // Get length of text element\r
+  length: function () {\r
+    return this.node.getComputedTextLength()\r
+  }\r
+})\r
+
+SVG.TextPath = SVG.invent({\r
+  // Initialize node\r
+  create: 'textPath',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Text,\r
+\r
+  // Define parent class\r
+  parent: SVG.Parent,\r
+\r
+  // Add parent method\r
+  extend: {\r
+    MorphArray: SVG.PathArray,\r
+    // return the array of the path track element\r
+    array: function () {\r
+      var track = this.track()\r
+\r
+      return track ? track.array() : null\r
+    },\r
+    // Plot path if any\r
+    plot: function (d) {\r
+      var track = this.track()\r
+      var pathArray = null\r
+\r
+      if (track) {\r
+        pathArray = track.plot(d)\r
+      }\r
+\r
+      return (d == null) ? pathArray : this\r
+    },\r
+    // Get the path element\r
+    track: function () {\r
+      return this.reference('href')\r
+    }\r
+  },\r
+  construct: {\r
+    textPath: function (text, path) {\r
+      return this.defs().path(path).text(text).addTo(this)\r
+    }\r
+  }\r
+})\r
+\r
+SVG.extend([SVG.Text], {\r
+    // Create path for text to run on\r
+  path: function (track) {\r
+    var path = new SVG.TextPath()\r
+\r
+    // if d is a path, reuse it\r
+    if (!(track instanceof SVG.Path)) {\r
+      // create path element\r
+      track = this.doc().defs().path(track)\r
+    }\r
+\r
+    // link textPath to path and add content\r
+    path.attr('href', '#' + track, SVG.xlink)\r
+\r
+    // add textPath element as child node and return textPath\r
+    return this.put(path)\r
+  },\r
+  // Todo: make this plural?\r
+  // Get the textPath children\r
+  textPath: function () {\r
+    return this.select('textPath')\r
+  }\r
+})\r
+\r
+SVG.extend([SVG.Path], {\r
+  // creates a textPath from this path\r
+  text: function (text) {\r
+    if (text instanceof SVG.Text) {\r
+      var txt = text.text()\r
+      return text.clear().path(this).text(txt)\r
+    }\r
+    return this.parent().put(new SVG.Text()).path(this).text(text)\r
+  }\r
+  // TODO: Maybe add `targets` to get all textPaths associated with this path\r
+})\r
+
+SVG.A = SVG.invent({\r
+  // Initialize node\r
+  create: 'a',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Container,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Link url\r
+    to: function (url) {\r
+      return this.attr('href', url, SVG.xlink)\r
+    },\r
+    // Link target attribute\r
+    target: function (target) {\r
+      return this.attr('target', target)\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    // Create a hyperlink element\r
+    link: function (url) {\r
+      return this.put(new SVG.A()).to(url)\r
+    }\r
+  }\r
+})\r
+\r
+SVG.extend(SVG.Element, {\r
+  // Create a hyperlink element\r
+  linkTo: function (url) {\r
+    var link = new SVG.A()\r
+\r
+    if (typeof url === 'function') { url.call(link, link) } else {\r
+      link.to(url)\r
+    }\r
+\r
+    return this.parent().put(link).put(this)\r
+  }\r
+\r
+})\r
+
+SVG.Marker = SVG.invent({\r
+  // Initialize node\r
+  create: 'marker',\r
+\r
+  // Inherit from\r
+  inherit: SVG.Container,\r
+\r
+  // Add class methods\r
+  extend: {\r
+    // Set width of element\r
+    width: function (width) {\r
+      return this.attr('markerWidth', width)\r
+    },\r
+    // Set height of element\r
+    height: function (height) {\r
+      return this.attr('markerHeight', height)\r
+    },\r
+    // Set marker refX and refY\r
+    ref: function (x, y) {\r
+      return this.attr('refX', x).attr('refY', y)\r
+    },\r
+    // Update marker\r
+    update: function (block) {\r
+      // remove all content\r
+      this.clear()\r
+\r
+      // invoke passed block\r
+      if (typeof block === 'function') { block.call(this, this) }\r
+\r
+      return this\r
+    },\r
+    // Return the fill id\r
+    toString: function () {\r
+      return 'url(#' + this.id() + ')'\r
+    }\r
+  },\r
+\r
+  // Add parent method\r
+  construct: {\r
+    marker: function (width, height, block) {\r
+      // Create marker element in defs\r
+      return this.defs().marker(width, height, block)\r
+    }\r
+  }\r
+\r
+})\r
+\r
+SVG.extend(SVG.Defs, {\r
+  // Create marker\r
+  marker: function (width, height, block) {\r
+    // Set default viewbox to match the width and height, set ref to cx and cy and set orient to auto\r
+    return this.put(new SVG.Marker())\r
+      .size(width, height)\r
+      .ref(width / 2, height / 2)\r
+      .viewbox(0, 0, width, height)\r
+      .attr('orient', 'auto')\r
+      .update(block)\r
+  }\r
+\r
+})\r
+\r
+SVG.extend([SVG.Line, SVG.Polyline, SVG.Polygon, SVG.Path], {\r
+  // Create and attach markers\r
+  marker: function (marker, width, height, block) {\r
+    var attr = ['marker']\r
+\r
+    // Build attribute name\r
+    if (marker !== 'all') attr.push(marker)\r
+    attr = attr.join('-')\r
+\r
+    // Set marker attribute\r
+    marker = arguments[1] instanceof SVG.Marker\r
+      ? arguments[1]\r
+      : this.doc().marker(width, height, block)\r
+\r
+    return this.attr(attr, marker)\r
+  }\r
+})\r
+
+// Define list of available attributes for stroke and fill\r
+var sugar = {\r
+  stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'],\r
+  fill: ['color', 'opacity', 'rule'],\r
+  prefix: function (t, a) {\r
+    return a === 'color' ? t : t + '-' + a\r
+  }\r
+}\r
+\r
+// Add sugar for fill and stroke\r
+;['fill', 'stroke'].forEach(function (m) {\r
+  var extension = {}\r
+  var i\r
+\r
+  extension[m] = function (o) {\r
+    if (typeof o === 'undefined') {\r
+      return this\r
+    }\r
+    if (typeof o === 'string' || SVG.Color.isRgb(o) || (o && typeof o.fill === 'function')) {\r
+      this.attr(m, o)\r
+    } else {\r
+      // set all attributes from sugar.fill and sugar.stroke list\r
+      for (i = sugar[m].length - 1; i >= 0; i--) {\r
+        if (o[sugar[m][i]] != null) {\r
+          this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]])\r
+        }\r
+      }\r
+    }\r
+\r
+    return this\r
+  }\r
+\r
+  SVG.extend([SVG.Element, SVG.FX], extension)\r
+})\r
+\r
+SVG.extend([SVG.Element, SVG.FX], {\r
+  // Map rotation to transform\r
+  rotate: function (d, cx, cy) {\r
+    return this.transform({ rotation: d, cx: cx, cy: cy })\r
+  },\r
+  // Map skew to transform\r
+  skew: function (x, y, cx, cy) {\r
+    return arguments.length === 1 || arguments.length === 3\r
+      ? this.transform({ skew: x, cx: y, cy: cx })\r
+      : this.transform({ skewX: x, skewY: y, cx: cx, cy: cy })\r
+  },\r
+  // Map scale to transform\r
+  scale: function (x, y, cx, cy) {\r
+    return arguments.length === 1 || arguments.length === 3\r
+      ? this.transform({ scale: x, cx: y, cy: cx })\r
+      : this.transform({ scaleX: x, scaleY: y, cx: cx, cy: cy })\r
+  },\r
+  // Map translate to transform\r
+  translate: function (x, y) {\r
+    return this.transform({ x: x, y: y })\r
+  },\r
+  // Map flip to transform\r
+  flip: function (a, o) {\r
+    o = typeof a === 'number' ? a : o\r
+    return this.transform({ flip: a || 'both', offset: o })\r
+  },\r
+  // Map matrix to transform\r
+  matrix: function (m) {\r
+    return this.attr('transform', new SVG.Matrix(arguments.length === 6 ? [].slice.call(arguments) : m))\r
+  },\r
+  // Opacity\r
+  opacity: function (value) {\r
+    return this.attr('opacity', value)\r
+  },\r
+  // Relative move over x axis\r
+  dx: function (x) {\r
+    return this.x(new SVG.Number(x).plus(this instanceof SVG.FX ? 0 : this.x()), true)\r
+  },\r
+  // Relative move over y axis\r
+  dy: function (y) {\r
+    return this.y(new SVG.Number(y).plus(this instanceof SVG.FX ? 0 : this.y()), true)\r
+  },\r
+  // Relative move over x and y axes\r
+  dmove: function (x, y) {\r
+    return this.dx(x).dy(y)\r
+  }\r
+})\r
+\r
+SVG.extend([SVG.Rect, SVG.Ellipse, SVG.Circle, SVG.Gradient, SVG.FX], {\r
+  // Add x and y radius\r
+  radius: function (x, y) {\r
+    var type = (this._target || this).type\r
+    return type === 'radialGradient' || type === 'radialGradient'\r
+      ? this.attr('r', new SVG.Number(x))\r
+      : this.rx(x).ry(y == null ? x : y)\r
+  }\r
+})\r
+\r
+SVG.extend(SVG.Path, {\r
+  // Get path length\r
+  length: function () {\r
+    return this.node.getTotalLength()\r
+  },\r
+  // Get point at length\r
+  pointAt: function (length) {\r
+    return new SVG.Point(this.node.getPointAtLength(length))\r
+  }\r
+})\r
+\r
+SVG.extend([SVG.Parent, SVG.Text, SVG.Tspan, SVG.FX], {\r
+  // Set font\r
+  font: function (a, v) {\r
+    if (typeof a === 'object') {\r
+      for (v in a) this.font(v, a[v])\r
+    }\r
+\r
+    return a === 'leading'\r
+        ? this.leading(v)\r
+      : a === 'anchor'\r
+        ? this.attr('text-anchor', v)\r
+      : a === 'size' || a === 'family' || a === 'weight' || a === 'stretch' || a === 'variant' || a === 'style'\r
+        ? this.attr('font-' + a, v)\r
+      : this.attr(a, v)\r
+  }\r
+})\r
+
+\r
+SVG.extend(SVG.Element, {\r
+  // Store data values on svg nodes\r
+  data: function (a, v, r) {\r
+    if (typeof a === 'object') {\r
+      for (v in a) {\r
+        this.data(v, a[v])\r
+      }\r
+    } else if (arguments.length < 2) {\r
+      try {\r
+        return JSON.parse(this.attr('data-' + a))\r
+      } catch (e) {\r
+        return this.attr('data-' + a)\r
+      }\r
+    } else {\r
+      this.attr('data-' + a,\r
+        v === null ? null\r
+        : r === true || typeof v === 'string' || typeof v === 'number' ? v\r
+        : JSON.stringify(v)\r
+      )\r
+    }\r
+\r
+    return this\r
+  }\r
+})\r
+
+\r
+SVG.extend(SVG.Element, {\r
+  // Remember arbitrary data\r
+  remember: function (k, v) {\r
+    // remember every item in an object individually\r
+    if (typeof arguments[0] === 'object') {\r
+      for (var key in k) {\r
+        this.remember(key, k[key])\r
+      }\r
+    } else if (arguments.length === 1) {\r
+      // retrieve memory\r
+      return this.memory()[k]\r
+    } else {\r
+      // store memory\r
+      this.memory()[k] = v\r
+    }\r
+\r
+    return this\r
+  },\r
+\r
+  // Erase a given memory\r
+  forget: function () {\r
+    if (arguments.length === 0) {\r
+      this._memory = {}\r
+    } else {\r
+      for (var i = arguments.length - 1; i >= 0; i--) {\r
+        delete this.memory()[arguments[i]]\r
+      }\r
+    }\r
+    return this\r
+  },\r
+\r
+  // Initialize or return local memory object\r
+  memory: function () {\r
+    return this._memory || (this._memory = {})\r
+  }\r
+})\r
+
+/* global idFromReference */\r
+\r
+// Method for getting an element by id\r
+SVG.get = function (id) {\r
+  var node = document.getElementById(idFromReference(id) || id)\r
+  return SVG.adopt(node)\r
+}\r
+\r
+// Select elements by query string\r
+SVG.select = function (query, parent) {\r
+  return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {\r
+    return SVG.adopt(node)\r
+  })\r
+}\r
+\r
+SVG.$$ = function (query, parent) {\r
+  return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {\r
+    return SVG.adopt(node)\r
+  })\r
+}\r
+\r
+SVG.$ = function (query, parent) {\r
+  return SVG.adopt((parent || document).querySelector(query))\r
+}\r
+\r
+SVG.extend(SVG.Parent, {\r
+  // Scoped select method\r
+  select: function (query) {\r
+    return SVG.select(query, this.node)\r
+  }\r
+})\r
+
+/* eslint no-unused-vars: 0 */\r
+\r
+function createElement (element, makeNested) {\r
+  if (element instanceof SVG.Element) return element\r
+\r
+  if (typeof element === 'object') {\r
+    return SVG.adopt(element)\r
+  }\r
+\r
+  if (element == null) {\r
+    return new SVG.Doc()\r
+  }\r
+\r
+  if (typeof element === 'string' && element.charAt(0) !== '<') {\r
+    return SVG.adopt(document.querySelector(element))\r
+  }\r
+\r
+  var node = SVG.create('svg')\r
+  node.innerHTML = element\r
+\r
+  element = SVG.adopt(node.firstElementChild)\r
+\r
+  return element\r
+}\r
+\r
+function isNulledBox (box) {\r
+  return !box.w && !box.h && !box.x && !box.y\r
+}\r
+\r
+function domContains (node) {\r
+  return (document.documentElement.contains || function (node) {\r
+    // This is IE - it does not support contains() for top-level SVGs\r
+    while (node.parentNode) {\r
+      node = node.parentNode\r
+    }\r
+    return node === document\r
+  }).call(document.documentElement, node)\r
+}\r
+\r
+function pathRegReplace (a, b, c, d) {\r
+  return c + d.replace(SVG.regex.dots, ' .')\r
+}\r
+\r
+// creates deep clone of array\r
+function arrayClone (arr) {\r
+  var clone = arr.slice(0)\r
+  for (var i = clone.length; i--;) {\r
+    if (Array.isArray(clone[i])) {\r
+      clone[i] = arrayClone(clone[i])\r
+    }\r
+  }\r
+  return clone\r
+}\r
+\r
+// tests if a given element is instance of an object\r
+function is (el, obj) {\r
+  return el instanceof obj\r
+}\r
+\r
+// tests if a given selector matches an element\r
+function matches (el, selector) {\r
+  return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector)\r
+}\r
+\r
+// Convert dash-separated-string to camelCase\r
+function camelCase (s) {\r
+  return s.toLowerCase().replace(/-(.)/g, function (m, g) {\r
+    return g.toUpperCase()\r
+  })\r
+}\r
+\r
+// Capitalize first letter of a string\r
+function capitalize (s) {\r
+  return s.charAt(0).toUpperCase() + s.slice(1)\r
+}\r
+\r
+// Ensure to six-based hex\r
+function fullHex (hex) {\r
+  return hex.length === 4\r
+    ? [ '#',\r
+      hex.substring(1, 2), hex.substring(1, 2),\r
+      hex.substring(2, 3), hex.substring(2, 3),\r
+      hex.substring(3, 4), hex.substring(3, 4)\r
+    ].join('')\r
+    : hex\r
+}\r
+\r
+// Component to hex value\r
+function compToHex (comp) {\r
+  var hex = comp.toString(16)\r
+  return hex.length === 1 ? '0' + hex : hex\r
+}\r
+\r
+// Calculate proportional width and height values when necessary\r
+function proportionalSize (element, width, height) {\r
+  if (width == null || height == null) {\r
+    var box = element.bbox()\r
+\r
+    if (width == null) {\r
+      width = box.width / box.height * height\r
+    } else if (height == null) {\r
+      height = box.height / box.width * width\r
+    }\r
+  }\r
+\r
+  return {\r
+    width: width,\r
+    height: height\r
+  }\r
+}\r
+\r
+// Delta transform point\r
+function deltaTransformPoint (matrix, x, y) {\r
+  return {\r
+    x: x * matrix.a + y * matrix.c + 0,\r
+    y: x * matrix.b + y * matrix.d + 0\r
+  }\r
+}\r
+\r
+// Map matrix array to object\r
+function arrayToMatrix (a) {\r
+  return { a: a[0], b: a[1], c: a[2], d: a[3], e: a[4], f: a[5] }\r
+}\r
+\r
+// Parse matrix if required\r
+function parseMatrix (matrix) {\r
+  if (!(matrix instanceof SVG.Matrix)) {\r
+    matrix = new SVG.Matrix(matrix)\r
+  }\r
+\r
+  return matrix\r
+}\r
+\r
+// Add centre point to transform object\r
+function ensureCentre (o, target) {\r
+  o.cx = o.cx == null ? target.bbox().cx : o.cx\r
+  o.cy = o.cy == null ? target.bbox().cy : o.cy\r
+}\r
+\r
+// PathArray Helpers\r
+function arrayToString (a) {\r
+  for (var i = 0, il = a.length, s = ''; i < il; i++) {\r
+    s += a[i][0]\r
+\r
+    if (a[i][1] != null) {\r
+      s += a[i][1]\r
+\r
+      if (a[i][2] != null) {\r
+        s += ' '\r
+        s += a[i][2]\r
+\r
+        if (a[i][3] != null) {\r
+          s += ' '\r
+          s += a[i][3]\r
+          s += ' '\r
+          s += a[i][4]\r
+\r
+          if (a[i][5] != null) {\r
+            s += ' '\r
+            s += a[i][5]\r
+            s += ' '\r
+            s += a[i][6]\r
+\r
+            if (a[i][7] != null) {\r
+              s += ' '\r
+              s += a[i][7]\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return s + ' '\r
+}\r
+\r
+// Deep new id assignment\r
+function assignNewId (node) {\r
+  // do the same for SVG child nodes as well\r
+  for (var i = node.children.length - 1; i >= 0; i--) {\r
+    assignNewId(node.children[i])\r
+  }\r
+\r
+  if (node.id) {\r
+    return SVG.adopt(node).id(SVG.eid(node.nodeName))\r
+  }\r
+\r
+  return SVG.adopt(node)\r
+}\r
+\r
+// Add more bounding box properties\r
+function fullBox (b) {\r
+  if (b.x == null) {\r
+    b.x = 0\r
+    b.y = 0\r
+    b.width = 0\r
+    b.height = 0\r
+  }\r
+\r
+  b.w = b.width\r
+  b.h = b.height\r
+  b.x2 = b.x + b.width\r
+  b.y2 = b.y + b.height\r
+  b.cx = b.x + b.width / 2\r
+  b.cy = b.y + b.height / 2\r
+\r
+  return b\r
+}\r
+\r
+// Get id from reference string\r
+function idFromReference (url) {\r
+  var m = (url || '').toString().match(SVG.regex.reference)\r
+\r
+  if (m) return m[1]\r
+}\r
+\r
+// Create matrix array for looping\r
+var abcdef = 'abcdef'.split('')\r
+
+/* globals fullBox, domContains, isNulledBox, Exception */\r
+\r
+SVG.Box = SVG.invent({\r
+  create: function (source) {\r
+    var base = [0, 0, 0, 0]\r
+    source = typeof source === 'string' ? source.split(SVG.regex.delimiter).map(parseFloat)\r
+      : Array.isArray(source) ? source\r
+      : typeof source === 'object' ? [source.left != null ? source.left\r
+      : source.x, source.top != null ? source.top : source.y, source.width, source.height]\r
+      : arguments.length === 4 ? [].slice.call(arguments)\r
+      : base\r
+\r
+    this.x = source[0]\r
+    this.y = source[1]\r
+    this.width = source[2]\r
+    this.height = source[3]\r
+\r
+    // add center, right, bottom...\r
+    fullBox(this)\r
+  },\r
+  extend: {\r
+    // Merge rect box with another, return a new instance\r
+    merge: function (box) {\r
+      var x = Math.min(this.x, box.x)\r
+      var y = Math.min(this.y, box.y)\r
+\r
+      return new SVG.Box(\r
+        x, y,\r
+        Math.max(this.x + this.width, box.x + box.width) - x,\r
+        Math.max(this.y + this.height, box.y + box.height) - y\r
+      )\r
+    },\r
+\r
+    transform: function (m) {\r
+      var xMin = Infinity\r
+      var xMax = -Infinity\r
+      var yMin = Infinity\r
+      var yMax = -Infinity\r
+\r
+      var pts = [\r
+        new SVG.Point(this.x, this.y),\r
+        new SVG.Point(this.x2, this.y),\r
+        new SVG.Point(this.x, this.y2),\r
+        new SVG.Point(this.x2, this.y2)\r
+      ]\r
+\r
+      pts.forEach(function (p) {\r
+        p = p.transform(m)\r
+        xMin = Math.min(xMin, p.x)\r
+        xMax = Math.max(xMax, p.x)\r
+        yMin = Math.min(yMin, p.y)\r
+        yMax = Math.max(yMax, p.y)\r
+      })\r
+\r
+      return new SVG.Box(\r
+        xMin, yMin,\r
+        xMax - xMin,\r
+        yMax - yMin\r
+      )\r
+    },\r
+\r
+    addOffset: function () {\r
+      // offset by window scroll position, because getBoundingClientRect changes when window is scrolled\r
+      this.x += window.pageXOffset\r
+      this.y += window.pageYOffset\r
+      return this\r
+    },\r
+    toString: function () {\r
+      return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height\r
+    },\r
+    morph: function (x, y, width, height) {\r
+      this.destination = new SVG.Box(x, y, width, height)\r
+      return this\r
+    },\r
+\r
+    at: function (pos) {\r
+      if (!this.destination) return this\r
+\r
+      return new SVG.Box(\r
+          this.x + (this.destination.x - this.x) * pos\r
+        , this.y + (this.destination.y - this.y) * pos\r
+        , this.width + (this.destination.width - this.width) * pos\r
+        , this.height + (this.destination.height - this.height) * pos\r
+      )\r
+    }\r
+  },\r
+\r
+    // Define Parent\r
+  parent: SVG.Element,\r
+\r
+  // Constructor\r
+  construct: {\r
+    // Get bounding box\r
+    bbox: function () {\r
+      var box\r
+\r
+      try {\r
+        // find native bbox\r
+        box = this.node.getBBox()\r
+\r
+        if (isNulledBox(box) && !domContains(this.node)) {\r
+          throw new Exception('Element not in the dom')\r
+        }\r
+      } catch (e) {\r
+        try {\r
+          var clone = this.clone(SVG.parser().svg).show()\r
+          box = clone.node.getBBox()\r
+          clone.remove()\r
+        } catch (e) {\r
+          console.warn('Getting a bounding box of this element is not possible')\r
+        }\r
+      }\r
+\r
+      return new SVG.Box(box)\r
+    },\r
+\r
+    rbox: function (el) {\r
+      // IE11 throws an error when element not in dom\r
+      try {\r
+        var box = new SVG.Box(this.node.getBoundingClientRect())\r
+        if (el) return box.transform(el.screenCTM().inverse())\r
+        return box.addOffset()\r
+      } catch (e) {\r
+        return new SVG.Box()\r
+      }\r
+    }\r
+  }\r
+})\r
+\r
+SVG.extend([SVG.Doc, SVG.Symbol, SVG.Image, SVG.Pattern, SVG.Marker, SVG.ForeignObject, SVG.View], {\r
+  viewbox: function (x, y, width, height) {\r
+    // act as getter\r
+    if (x == null) return new SVG.Box(this.attr('viewBox'))\r
+\r
+    // act as setter\r
+    return this.attr('viewBox', new SVG.Box(x, y, width, height))\r
+  }\r
+})\r
+
+\r
+SVG.parser = function () {\r
+  var b\r
+\r
+  if (!SVG.parser.nodes.svg.node.parentNode) {\r
+    b = document.body || document.documentElement\r
+    SVG.parser.nodes.svg.addTo(b)\r
+  }\r
+\r
+  return SVG.parser.nodes\r
+}\r
+\r
+SVG.parser.nodes = {\r
+  svg: SVG().size(2, 0).css({\r
+    opacity: 0,\r
+    position: 'absolute',\r
+    left: '-100%',\r
+    top: '-100%',\r
+    overflow: 'hidden'\r
+  })\r
+}\r
+\r
+SVG.parser.nodes.path = SVG.parser.nodes.svg.path().node\r
+\r
+\r
+return SVG\r
+\r
+}));\r
\ No newline at end of file
index 277bd403026e5adb986e9108e6126b7e447d558c..d644e9003ee24ca17c5f86655698527fa4107f24 100644 (file)
@@ -1,2 +1,2 @@
-/*! svg.js v3.0.0 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function n(t,n){if(t instanceof M.Element)return t;if("object"==typeof t)return M.adopt(t);if(null==t)return new M.Doc;if("string"==typeof t&&"<"!==t.charAt(0))return M.adopt(e.querySelector(t));var i=M.create("svg");return i.innerHTML=t,t=M.adopt(i.firstElementChild)}function i(t){return!(t.w||t.h||t.x||t.y)}function r(t){return(e.documentElement.contains||function(t){for(;t.parentNode;)t=t.parentNode;return t===e}).call(e.documentElement,t)}function s(t,e,n,i){return n+i.replace(M.regex.dots," .")}function a(t){for(var e=t.slice(0),n=e.length;n--;)Array.isArray(e[n])&&(e[n]=a(e[n]));return e}function o(t,e){return t instanceof e}function h(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function u(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function l(t){return t.charAt(0).toUpperCase()+t.slice(1)}function c(t){return 4===t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t}function f(t){var e=t.toString(16);return 1===e.length?"0"+e:e}function d(t,e,n){if(null==e||null==n){var i=t.bbox();null==e?e=i.width/i.height*n:null==n&&(n=i.height/i.width*e)}return{width:e,height:n}}function p(t,e,n){return{x:e*t.a+n*t.c+0,y:e*t.b+n*t.d+0}}function x(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function m(t){return t instanceof M.Matrix||(t=new M.Matrix(t)),t}function y(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function v(t){for(var e=0,n=t.length,i="";e<n;e++)i+=t[e][0],null!=t[e][1]&&(i+=t[e][1],null!=t[e][2]&&(i+=" ",i+=t[e][2],null!=t[e][3]&&(i+=" ",i+=t[e][3],i+=" ",i+=t[e][4],null!=t[e][5]&&(i+=" ",i+=t[e][5],i+=" ",i+=t[e][6],null!=t[e][7]&&(i+=" ",i+=t[e][7])))));return i+" "}function g(t){for(var e=t.children.length-1;e>=0;e--)g(t.children[e]);return t.id?M.adopt(t).id(M.eid(t.nodeName)):M.adopt(t)}function w(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function b(t){var e=(t||"").toString().match(M.regex.reference);if(e)return e[1]}if(!e.createElementNS||!e.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect)return{supported:!1};var M=this.SVG=function(t){if(M.supported)return t=n(t)};M.supported=!0,M.ns="http://www.w3.org/2000/svg",M.xmlns="http://www.w3.org/2000/xmlns/",M.xlink="http://www.w3.org/1999/xlink",M.svgjs="http://svgjs.com/svgjs",M.did=1e3,M.eid=function(t){return"Svgjs"+l(t)+M.did++},M.create=function(t){return e.createElementNS(this.ns,t)},M.extend=function(t,e){var n,i;for(t=Array.isArray(t)?t:[t],i=t.length-1;i>=0;i--)if(t[i])for(n in e)t[i].prototype[n]=e[n]},M.invent=function(t){var e="function"==typeof t.create?t.create:function(e){this.constructor(e||M.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&M.extend(e,t.extend),t.construct&&M.extend(t.parent||M.Container,t.construct),e},M.adopt=function(e){if(!e)return null;if(e.instance)return e.instance;if(!(e instanceof t.SVGElement))return new M.HtmlNode(e);return"svg"===e.nodeName?e.parentNode instanceof t.SVGElement?new M.Nested(e):new M.Doc(e):"linearGradient"===e.nodeName||"radialGradient"===e.nodeName?new M.Gradient(e):M[l(e.nodeName)]?new(M[l(e.nodeName)])(e):new M.Parent(e)},M.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,transforms:/\)\s*,?\s*/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,delimiter:/[\s,]+/,hyphen:/([^e])-/gi,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,numbersWithDots:/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,dots:/\./g},M.utils={map:function(t,e){var n,i=t.length,r=[];for(n=0;n<i;n++)r.push(e(t[n]));return r},filter:function(t,e){var n,i=t.length,r=[];for(n=0;n<i;n++)e(t[n])&&r.push(t[n]);return r},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(e){return this.filter(e,function(e){return e instanceof t.SVGElement})}},M.defaults={attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"}},M.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?M.regex.isRgb.test(t)?(e=M.regex.rgb.exec(t.replace(M.regex.whitespace,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):M.regex.isHex.test(t)&&(e=M.regex.hex.exec(c(t)),this.r=parseInt(e[1],16),this.g=parseInt(e[2],16),this.b=parseInt(e[3],16)):"object"==typeof t&&(this.r=t.r,this.g=t.g,this.b=t.b))},M.extend(M.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+f(this.r)+f(this.g)+f(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11},morph:function(t){return this.destination=new M.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new M.Color({r:~~(this.r+(this.destination.r-this.r)*t),g:~~(this.g+(this.destination.g-this.g)*t),b:~~(this.b+(this.destination.b-this.b)*t)})):this}}),M.Color.test=function(t){return t+="",M.regex.isHex.test(t)||M.regex.isRgb.test(t)},M.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},M.Color.isColor=function(t){return M.Color.isRgb(t)||M.Color.test(t)},M.Array=function(t,e){t=(t||[]).valueOf(),0===t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},M.extend(M.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!==this.destination.length){for(var e=this.value[this.value.length-1],n=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(n);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,n=[];t<e;t++)-1===n.indexOf(this.value[t])&&n.push(this.value[t]);return this.value=n,n},at:function(t){if(!this.destination)return this;for(var e=0,n=this.value.length,i=[];e<n;e++)i.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new M.Array(i)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:t.trim().split(M.regex.delimiter).map(parseFloat)},reverse:function(){return this.value.reverse(),this},clone:function(){var t=new this.constructor;return t.value=a(this.value),t}}),M.PointArray=function(t,e){M.Array.call(this,t,e||[[0,0]])},M.PointArray.prototype=new M.Array,M.PointArray.prototype.constructor=M.PointArray,M.extend(M.PointArray,{toString:function(){for(var t=0,e=this.value.length,n=[];t<e;t++)n.push(this.value[t].join(","));return n.join(" ")},toLine:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}},at:function(t){if(!this.destination)return this;for(var e=0,n=this.value.length,i=[];e<n;e++)i.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new M.PointArray(i)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t)){if(Array.isArray(t[0]))return t}else t=t.trim().split(M.regex.delimiter).map(parseFloat);t.length%2!=0&&t.pop();for(var n=0,i=t.length;n<i;n+=2)e.push([t[n],t[n+1]]);return e},move:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i=this.value.length-1;i>=0;i--)this.value[i]=[this.value[i][0]+t,this.value[i][1]+e];return this},size:function(t,e){var n,i=this.bbox();for(n=this.value.length-1;n>=0;n--)i.width&&(this.value[n][0]=(this.value[n][0]-i.x)*t/i.width+i.x),i.height&&(this.value[n][1]=(this.value[n][1]-i.y)*e/i.height+i.y);return this},bbox:function(){var t=-1/0,e=-1/0,n=1/0,i=1/0;return this.value.forEach(function(r){t=Math.max(r[0],t),e=Math.max(r[1],e),n=Math.min(r[0],n),i=Math.min(r[1],i)}),{x:n,y:i,width:t-n,height:e-i}}});for(var P={M:function(t,e,n){return e.x=n.x=t[0],e.y=n.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,n){return e.x=n.x,e.y=n.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},A="mlhvqtcsaz".split(""),N=0,C=A.length;N<C;++N)P[A[N]]=function(t){return function(e,n,i){if("H"===t)e[0]=e[0]+n.x;else if("V"===t)e[0]=e[0]+n.y;else if("A"===t)e[5]=e[5]+n.x,e[6]=e[6]+n.y;else for(var r=0,s=e.length;r<s;++r)e[r]=e[r]+(r%2?n.y:n.x);return P[t](e,n,i)}}(A[N].toUpperCase());M.PathArray=function(t,e){M.Array.call(this,t,e||[["M",0,0]])},M.PathArray.prototype=new M.Array,M.PathArray.prototype.constructor=M.PathArray,M.extend(M.PathArray,{toString:function(){return v(this.value)},move:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i,r=this.value.length-1;r>=0;r--)i=this.value[r][0],"M"===i||"L"===i||"T"===i?(this.value[r][1]+=t,this.value[r][2]+=e):"H"===i?this.value[r][1]+=t:"V"===i?this.value[r][1]+=e:"C"===i||"S"===i||"Q"===i?(this.value[r][1]+=t,this.value[r][2]+=e,this.value[r][3]+=t,this.value[r][4]+=e,"C"===i&&(this.value[r][5]+=t,this.value[r][6]+=e)):"A"===i&&(this.value[r][6]+=t,this.value[r][7]+=e);return this},size:function(t,e){var n,i,r=this.bbox();for(n=this.value.length-1;n>=0;n--)i=this.value[n][0],"M"===i||"L"===i||"T"===i?(this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x,this.value[n][2]=(this.value[n][2]-r.y)*e/r.height+r.y):"H"===i?this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x:"V"===i?this.value[n][1]=(this.value[n][1]-r.y)*e/r.height+r.y:"C"===i||"S"===i||"Q"===i?(this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x,this.value[n][2]=(this.value[n][2]-r.y)*e/r.height+r.y,this.value[n][3]=(this.value[n][3]-r.x)*t/r.width+r.x,this.value[n][4]=(this.value[n][4]-r.y)*e/r.height+r.y,"C"===i&&(this.value[n][5]=(this.value[n][5]-r.x)*t/r.width+r.x,this.value[n][6]=(this.value[n][6]-r.y)*e/r.height+r.y)):"A"===i&&(this.value[n][1]=this.value[n][1]*t/r.width,this.value[n][2]=this.value[n][2]*e/r.height,this.value[n][6]=(this.value[n][6]-r.x)*t/r.width+r.x,this.value[n][7]=(this.value[n][7]-r.y)*e/r.height+r.y);return this},equalCommands:function(t){var e,n,i;for(t=new M.PathArray(t),i=this.value.length===t.value.length,e=0,n=this.value.length;i&&e<n;e++)i=this.value[e][0]===t.value[e][0];return i},morph:function(t){return t=new M.PathArray(t),this.equalCommands(t)?this.destination=t:this.destination=null,this},at:function(t){if(!this.destination)return this;var e,n,i,r,s=this.value,a=this.destination.value,o=[],h=new M.PathArray;for(e=0,n=s.length;e<n;e++){for(o[e]=[s[e][0]],i=1,r=s[e].length;i<r;i++)o[e][i]=s[e][i]+(a[e][i]-s[e][i])*t;"A"===o[e][0]&&(o[e][4]=+(0!==o[e][4]),o[e][5]=+(0!==o[e][5]))}return h.value=o,h},parse:function(t){if(t instanceof M.PathArray)return t.valueOf();var e,n={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7,Z:0};t="string"==typeof t?t.replace(M.regex.numbersWithDots,s).replace(M.regex.pathLetters," $& ").replace(M.regex.hyphen,"$1 -").trim().split(M.regex.delimiter):t.reduce(function(t,e){return[].concat.call(t,e)},[]);var i=[],r=new M.Point,a=new M.Point,o=0,h=t.length;do{M.regex.isPathLetter.test(t[o])?(e=t[o],++o):"M"===e?e="L":"m"===e&&(e="l"),i.push(P[e].call(null,t.slice(o,o+=n[e.toUpperCase()]).map(parseFloat),r,a))}while(h>o);return i},bbox:function(){return M.parser().path.setAttribute("d",this.toString()),M.parser.nodes.path.getBBox()}}),M.Number=M.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(M.regex.numberAndUnit))&&(this.value=parseFloat(e[1]),"%"===e[5]?this.value/=100:"s"===e[5]&&(this.value*=1e3),this.unit=e[5]):t instanceof M.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"===this.unit?~~(1e8*this.value)/1e6:"s"===this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return t=new M.Number(t),new M.Number(this+t,this.unit||t.unit)},minus:function(t){return t=new M.Number(t),new M.Number(this-t,this.unit||t.unit)},times:function(t){return t=new M.Number(t),new M.Number(this*t,this.unit||t.unit)},divide:function(t){return t=new M.Number(t),new M.Number(this/t,this.unit||t.unit)},to:function(t){var e=new M.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new M.Number(t),t.relative&&(this.destination.value+=this.value),this},at:function(t){return this.destination?new M.Number(this.destination).minus(this).times(t).plus(this):this}}}),M.HtmlNode=M.invent({create:function(t){this.node=t},extend:{add:function(t,e){return t=n(t),t instanceof M.Nested&&(t=new M.Doc(t.node),t.setData(JSON.parse(t.node.getAttribute("svgjs:data"))||{})),null===e?this.node.appendChild(t.node):t.node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]),this},put:function(t,e){return this.add(t,e),t}}}),M.Element=M.invent({create:function(t){this._event=null,this.dom={},this.node=t,this.node&&(this.type=t.nodeName,this.node.instance=this,t.hasAttribute("svgjs:data")&&this.setData(JSON.parse(t.getAttribute("svgjs:data"))||{}))},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var n=d(this,t,e);return this.width(new M.Number(n.width)).height(new M.Number(n.height))},clone:function(t){this.writeDataToDom();var e=g(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return n(t).put(this)},putIn:function(t){return n(t).add(this)},id:function(t){return void 0!==t||this.node.id||(this.node.id=M.eid(this.type)),this.attr("id",t)},inside:function(t,e){var n=this.bbox();return t>n.x&&e>n.y&&t<n.x+n.width&&e<n.y+n.height},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},visible:function(){return"none"!==this.css("display")},toString:function(){return this.id()},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(M.regex.delimiter)},hasClass:function(t){return-1!==this.classes().indexOf(t)},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(t){return this.hasClass(t)&&this.attr("class",this.classes().filter(function(e){return e!==t}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return M.get(this.attr(t))},parent:function(e){var n=this;if(!n.node.parentNode)return null;if(n=M.adopt(n.node.parentNode),!e)return n;for(;n&&n.node instanceof t.SVGElement;){if("string"==typeof e?n.matches(e):n instanceof e)return n;n=M.adopt(n.node.parentNode)}},doc:function(){return this instanceof M.Doc?this:this.parent(M.Doc)},defs:function(){return this.doc().defs()},parents:function(t){var e=[],n=this;do{if(!(n=n.parent(t))||!n.node)break;e.push(n)}while(n.parent);return e},matches:function(t){return h(this.node,t)},native:function(){return this.node},svg:function(t){var n,i;if(!(t&&this instanceof M.Parent))return this.writeDataToDom(),this.node.outerHTML;for(n=e.createElementNS(M.ns,"svg"),n.innerHTML=t,i=n.children.length;i--;)this.node.appendChild(n.firstElementChild);return this},writeDataToDom:function(){return this.is(M.Parent)&&this.each(function(){this.writeDataToDom()}),this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return o(this,t)}}}),M.easing={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return 1-Math.cos(t*Math.PI/2)}},M.morph=function(t){return function(e,n){return new M.MorphObj(e,n).at(t)}},M.Situation=M.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new M.Number(t.duration).valueOf(),this.delay=new M.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),M.FX=M.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,n){"object"==typeof t&&(e=t.ease,n=t.delay,t=t.duration);var i=new M.Situation({duration:t||1e3,delay:n||0,ease:M.easing[e||"-"]||e});return this.queue(i),this},delay:function(t){var e=new M.Situation({duration:t,delay:0,ease:M.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof M.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=t.requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){t.cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof M.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof M.Situation?this.start():this.situation(this)),this},initAnimations:function(){var t,e,n,i=this.situation;if(i.init)return this;for(t in i.animations)for(n=this.target()[t](),Array.isArray(n)||(n=[n]),Array.isArray(i.animations[t])||(i.animations[t]=[i.animations[t]]),e=n.length;e--;)i.animations[t][e]instanceof M.Number&&(n[e]=new M.Number(n[e])),i.animations[t][e]=n[e].morph(i.animations[t][e]);for(t in i.attrs)i.attrs[t]=new M.MorphObj(this.target().attr(t),i.attrs[t]);for(t in i.styles)i.styles[t]=new M.MorphObj(this.target().css(t),i.styles[t]);return i.initialTransformation=this.target().matrixify(),i.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){var n=this.active;return this.active=!1,e&&this.clearQueue(),t&&this.situation&&(!n&&this.startCurrent(),this.atEnd()),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return!0===this.situation.loops&&(this.situation.loops=this.situation.loop+1),"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var n=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*n,this.situation.finish=this.situation.start+n,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var n=this.last();return n.loops=null==t||t,n.loop=0,e&&(n.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return e.reversed=void 0===t?!e.reversed:t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){function e(i){i.detail.situation===n&&(t.call(this,n),this.off("finished.fx",e))}var n=this.last();return this.target().on("finished.fx",e),this._callStart()},during:function(t){function e(e){e.detail.situation===n&&t.call(this,e.detail.pos,M.morph(e.detail.pos),e.detail.eased,n)}var n=this.last();return this.target().off("during.fx",e).on("during.fx",e),this.after(function(){this.off("during.fx",e)}),this._callStart()},afterAll:function(t){var e=function e(n){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this._callStart()},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,M.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)}),this._callStart()},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,n){return this.last()[n||"animations"][t]=e,this._callStart()},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),!1!==this.situation.loops){var e,n,i;e=Math.max(this.absPos,0),n=Math.floor(e),!0===this.situation.loops||n<this.situation.loops?(this.pos=e-n,i=this.situation.loop,this.situation.loop=n):(this.absPos=this.situation.loops,this.pos=1,i=this.situation.loop-1,this.situation.loop=this.situation.loops),this.situation.reversing&&(this.situation.reversed=this.situation.reversed!==Boolean((this.situation.loop-i)%2))}else this.absPos=Math.min(this.absPos,1),this.pos=this.absPos;this.pos<0&&(this.pos=0),this.situation.reversed&&(this.pos=1-this.pos);var r=this.situation.ease(this.pos);for(var s in this.situation.once)s>this.lastPos&&s<=r&&(this.situation.once[s].call(this.target(),this.pos,r),delete this.situation.once[s]);return this.active&&this.target().fire("during",{pos:this.pos,eased:r,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1===this.pos&&!this.situation.reversed||this.situation.reversed&&0===this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.situations.length||(this.target().off(".fx"),this.active=!1)),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=r,this):this},eachAt:function(){var t,e,n,i=this,r=this.target(),s=this.situation;for(t in s.animations)n=[].concat(s.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),r[t].apply(r,n);for(t in s.attrs)n=[t].concat(s.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),r.attr.apply(r,n);for(t in s.styles)n=[t].concat(s.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),r.css.apply(r,n);if(s.transforms.length){for(n=s.initialTransformation,t=0,e=s.transforms.length;t<e;t++){var a=s.transforms[t];a instanceof M.Matrix?n=a.relative?n.multiply((new M.Matrix).morph(a).at(s.ease(this.pos))):n.morph(a).at(s.ease(this.pos)):(a.relative||a.undo(n.extract()),n=n.multiply(a.at(s.ease(this.pos))))}r.matrix(n)}return this},once:function(t,e,n){var i=this.last();return n||(t=i.ease(t)),i.once[t]=e,this},_callStart:function(){return setTimeout(function(){this.start()}.bind(this),0),this}},parent:M.Element,construct:{animate:function(t,e,n){return(this.fx||(this.fx=new M.FX(this))).animate(t,e,n)},delay:function(t){return(this.fx||(this.fx=new M.FX(this))).delay(t)},stop:function(t,e){return this.fx&&this.fx.stop(t,e),this},finish:function(){return this.fx&&this.fx.finish(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this},speed:function(t){if(this.fx){if(null==t)return this.fx.speed();this.fx.speed(t)}return this}}}),M.MorphObj=M.invent({create:function(t,e){return M.Color.isColor(e)?new M.Color(t).morph(e):M.regex.delimiter.test(t)?new M.Array(t).morph(e):M.regex.numberAndUnit.test(e)?new M.Number(t).morph(e):(this.value=t,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),M.extend(M.FX,{attr:function(t,e,n){if("object"==typeof t)for(var i in t)this.attr(i,t[i]);else this.add(t,e,"attrs");return this},css:function(t,e){if("object"==typeof t)for(var n in t)this.css(n,t[n]);else this.add(t,e,"styles");return this},x:function(t,e){if(this.target()instanceof M.G)return this.transform({x:t},e),this;var n=new M.Number(t);return n.relative=e,this.add("x",n)},y:function(t,e){if(this.target()instanceof M.G)return this.transform({y:t},e),this;var n=new M.Number(t);return n.relative=e,this.add("y",n)},cx:function(t){return this.add("cx",new M.Number(t))},cy:function(t){return this.add("cy",new M.Number(t))},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target()instanceof M.Text)this.attr("font-size",t);else{var n;t&&e||(n=this.target().bbox()),t||(t=n.width/n.height*e),e||(e=n.height/n.width*t),this.add("width",new M.Number(t)).add("height",new M.Number(e))}return this},width:function(t){return this.add("width",new M.Number(t))},height:function(t){return this.add("height",new M.Number(t))},plot:function(t,e,n,i){return 4===arguments.length?this.plot([t,e,n,i]):this.add("plot",new(this.target().MorphArray)(t))},leading:function(t){return this.target().leading?this.add("leading",new M.Number(t)):this},viewbox:function(t,e,n,i){return this.target()instanceof M.Container&&this.add("viewbox",new M.Box(t,e,n,i)),this},update:function(t){if(this.target()instanceof M.Stop){if("number"==typeof t||t instanceof M.Number)return this.update({offset:arguments[0],color:arguments[1],opacity:arguments[2]});null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",t.offset)}return this}}),M.Matrix=M.invent({create:function(t){var e,n=x([1,0,0,1,0,0]);for(t=t instanceof M.Element?t.matrixify():"string"==typeof t?x(t.split(M.regex.delimiter).map(parseFloat)):6===arguments.length?x([].slice.call(arguments)):Array.isArray(t)?x(t):"object"==typeof t?t:n,e=S.length-1;e>=0;--e)this[S[e]]=null!=t[S[e]]?t[S[e]]:n[S[e]]},extend:{extract:function(){var t=p(this,0,1),e=p(this,1,0),n=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(n*Math.PI/180)+this.f*Math.sin(n*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(n*Math.PI/180)+this.e*Math.sin(-n*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-n,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:n,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new M.Matrix(this)}},clone:function(){return new M.Matrix(this)},morph:function(t){return this.destination=new M.Matrix(t),this},at:function(t){return this.destination?new M.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t}):this},multiply:function(t){return new M.Matrix(this.native().multiply(m(t).native()))},inverse:function(){return new M.Matrix(this.native().inverse())},translate:function(t,e){return new M.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,n,i){return 1===arguments.length?e=t:3===arguments.length&&(i=n,n=e,e=t),this.around(n,i,new M.Matrix(t,0,0,e,0,0))},rotate:function(t,e,n){return t=M.utils.radians(t),this.around(e,n,new M.Matrix(Math.cos(t),Math.sin(t),-Math.sin(t),Math.cos(t),0,0))},flip:function(t,e){return"x"===t?this.scale(-1,1,e,0):"y"===t?this.scale(1,-1,0,e):this.scale(-1,-1,t,null!=e?e:t)},skew:function(t,e,n,i){return 1===arguments.length?e=t:3===arguments.length&&(i=n,n=e,e=t),t=M.utils.radians(t),e=M.utils.radians(e),this.around(n,i,new M.Matrix(1,Math.tan(e),Math.tan(t),1,0,0))},skewX:function(t,e,n){return this.skew(t,0,e,n)},skewY:function(t,e,n){return this.skew(0,t,e,n)},around:function(t,e,n){return this.multiply(new M.Matrix(1,0,0,1,t||0,e||0)).multiply(n).multiply(new M.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=M.parser.nodes.svg.node.createSVGMatrix(),e=S.length-1;e>=0;e--)t[S[e]]=this[S[e]];return t},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:M.Element,construct:{ctm:function(){return new M.Matrix(this.node.getCTM())},screenCTM:function(){if(this instanceof M.Nested){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new M.Matrix(e)}return new M.Matrix(this.node.getScreenCTM())}}}),M.Point=M.invent({create:function(t,e){var n,i={x:0,y:0};n=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=t?{x:t,y:null!=e?e:t}:i,this.x=n.x,this.y=n.y},extend:{clone:function(){return new M.Point(this)},morph:function(t,e){return this.destination=new M.Point(t,e),this},at:function(t){return this.destination?new M.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t}):this},native:function(){var t=M.parser.nodes.svg.node.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new M.Point(this.native().matrixTransform(t.native()))}}}),M.extend(M.Element,{point:function(t,e){return new M.Point(t,e).transform(this.screenCTM().inverse())}}),M.extend(M.Element,{attr:function(t,e,n){if(null==t){for(t={},e=this.node.attributes,n=e.length-1;n>=0;n--)t[e[n].nodeName]=M.regex.isNumber.test(e[n].nodeValue)?parseFloat(e[n].nodeValue):e[n].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return e=this.node.getAttribute(t),null==e?M.defaults.attrs[t]:M.regex.isNumber.test(e)?parseFloat(e):e;"fill"!==t&&"stroke"!==t||(M.regex.isImage.test(e)&&(e=this.doc().defs().image(e)),e instanceof M.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new M.Number(e):M.Color.isColor(e)?e=new M.Color(e):Array.isArray(e)&&(e=new M.Array(e)),"leading"===t?this.leading&&this.leading(e):"string"==typeof n?this.node.setAttributeNS(n,t,e.toString()):this.node.setAttribute(t,e.toString()),
-!this.rebuild||"font-size"!==t&&"x"!==t||this.rebuild(t,e)}return this}}),M.extend(M.Element,{transform:function(t,e){var n,i,r=this;if("object"!=typeof t)return n=new M.Matrix(r).extract(),"string"==typeof t?n[t]:n;if(n=new M.Matrix(r),e=!!e||!!t.relative,null!=t.a)n=e?n.multiply(new M.Matrix(t)):new M.Matrix(t);else if(null!=t.rotation)y(t,r),n=e?n.rotate(t.rotation,t.cx,t.cy):n.rotate(t.rotation-n.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(y(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,!e){var s=n.extract();t.scaleX=1*t.scaleX/s.scaleX,t.scaleY=1*t.scaleY/s.scaleY}n=n.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skew||null!=t.skewX||null!=t.skewY){if(y(t,r),t.skewX=null!=t.skew?t.skew:null!=t.skewX?t.skewX:0,t.skewY=null!=t.skew?t.skew:null!=t.skewY?t.skewY:0,!e){var a=n.extract();n=n.multiply((new M.Matrix).skew(a.skewX,a.skewY,a.cx,a.cy).inverse())}n=n.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?("x"===t.flip||"y"===t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(i=r.bbox(),t.flip=i.cx,t.offset=i.cy):t.flip=t.offset,n=(new M.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(e?n=n.translate(t.x,t.y):(null!=t.x&&(n.e=t.x),null!=t.y&&(n.f=t.y)));return this.attr("transform",n)}}),M.extend(M.FX,{transform:function(t,e){var n,i,r=this.target();return"object"!=typeof t?(n=new M.Matrix(r).extract(),"string"==typeof t?n[t]:n):(e=!!e||!!t.relative,null!=t.a?n=new M.Matrix(t):null!=t.rotation?(y(t,r),n=new M.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(y(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,n=new M.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(y(t,r),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,n=new M.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?("x"===t.flip||"y"===t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(i=r.bbox(),t.flip=i.cx,t.offset=i.cy):t.flip=t.offset,n=(new M.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(n=new M.Translate(t.x,t.y)),n?(n.relative=e,this.last().transforms.push(n),this._callStart()):this)}}),M.extend(M.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){return(this.attr("transform")||"").split(M.regex.transforms).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(M.regex.delimiter).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"===e[0]?t.multiply(x(e[1])):t[e[0]].apply(t,e[1])},new M.Matrix)},toParent:function(t){if(this===t)return this;var e=this.screenCTM(),n=t.screenCTM().inverse();return this.addTo(t).untransform().transform(n.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),M.Transformation=M.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.constructor.bind(this)([].slice.call(arguments));var n,i;if(Array.isArray(t))for(n=0,i=this.arguments.length;n<i;++n)this[this.arguments[n]]=t[n];else if("object"==typeof t)for(n=0,i=this.arguments.length;n<i;++n)this[this.arguments[n]]=t[this.arguments[n]];this.inversed=!1,!0===e&&(this.inversed=!0)},extend:{arguments:[],method:"",at:function(t){for(var e=[],n=0,i=this.arguments.length;n<i;++n)e.push(this[this.arguments[n]]);var r=this._undo||new M.Matrix;return r=(new M.Matrix).morph(M.Matrix.prototype[this.method].apply(r,e)).at(t),this.inversed?r.inverse():r},undo:function(t){for(var e=0,n=this.arguments.length;e<n;++e)t[this.arguments[e]]=void 0===this[this.arguments[e]]?0:t[this.arguments[e]];return t.cx=this.cx,t.cy=this.cy,this._undo=new(M[l(this.method)])(t,!0).at(1),this}}}),M.Translate=M.invent({parent:M.Matrix,inherit:M.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["transformedX","transformedY"],method:"translate"}}),M.Rotate=M.invent({parent:M.Matrix,inherit:M.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["rotation","cx","cy"],method:"rotate",at:function(t){var e=(new M.Matrix).rotate((new M.Number).morph(this.rotation-(this._undo?this._undo.rotation:0)).at(t),this.cx,this.cy);return this.inversed?e.inverse():e},undo:function(t){return this._undo=t,this}}}),M.Scale=M.invent({parent:M.Matrix,inherit:M.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["scaleX","scaleY","cx","cy"],method:"scale"}}),M.Skew=M.invent({parent:M.Matrix,inherit:M.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["skewX","skewY","cx","cy"],method:"skew"}}),M.extend(M.Element,{css:function(t,e){var n,i,r={};if(0===arguments.length)return this.node.style.cssText.split(/\s*;\s*/).filter(function(t){return!!t.length}).forEach(function(t){n=t.split(/\s*:\s*/),r[n[0]]=n[1]}),r;if(arguments.length<2){if(Array.isArray(t)){for(i=t.length;i--;)r[u(t[i])]=this.node.style[u(t[i])];return r}if("string"==typeof t)return this.node.style[u(t)];if("object"==typeof t)for(i in t)this.node.style[u(i)]=null==t[i]||M.regex.isBlank.test(t[i])?"":t[i]}return 2===arguments.length&&(this.node.style[u(t)]=null==e||M.regex.isBlank.test(e)?"":e),this}}),M.Parent=M.invent({create:function(t){this.constructor(t)},inherit:M.Element,extend:{children:function(){return M.utils.map(this.node.children,function(t){return M.adopt(t)})},add:function(t,e){return t=n(t),null==e?this.node.appendChild(t.node):t.node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]),this},put:function(t,e){return this.add(t,e),t.instance||t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.children).indexOf(t.node)},get:function(t){return M.adopt(this.node.children[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.children.length-1)},each:function(t,e){var n,i,r=this.children();for(n=0,i=r.length;n<i;n++)r[n]instanceof M.Element&&t.apply(r[n],[n,r]),e&&r[n]instanceof M.Parent&&r[n].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this}}}),M.extend(M.Parent,{flatten:function(t){return this instanceof M.Defs?this:(t=t||(this instanceof M.Doc?this:this.parent(M.Parent)),this.each(function(){return this instanceof M.Defs?this:this instanceof M.Parent?this.flatten(t):this.toParent(t)}),this.node.firstElementChild||this.remove(),this)}}),M.Container=M.invent({create:function(t){this.constructor(t)},inherit:M.Parent}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){M.Element.prototype[t]=function(e){return M.on(this,t,e),this}}),M.listeners=[],M.handlerMap=[],M.listenerId=0,M.on=function(t,e,n,i,r){e.split(M.regex.delimiter).forEach(function(e){var s=n.bind(i||t),a=t instanceof M.Element?t.node:t,o=(M.handlerMap.indexOf(a)+1||M.handlerMap.push(a))-1,h=e.split(".")[0],u=e.split(".")[1]||"*";M.listeners[o]=M.listeners[o]||{},M.listeners[o][h]=M.listeners[o][h]||{},M.listeners[o][h][u]=M.listeners[o][h][u]||{},n._svgjsListenerId||(n._svgjsListenerId=++M.listenerId),M.listeners[o][h][u][n._svgjsListenerId]=s,a.addEventListener(h,s,r||!1)})},M.off=function(t,e,n){var i=M.handlerMap.indexOf(t),r=e&&e.split(".")[0],s=e&&e.split(".")[1],a="";if(-1!==i)if(n){if("function"==typeof n&&(n=n._svgjsListenerId),!n)return;M.listeners[i][r]&&M.listeners[i][r][s||"*"]&&(t.removeEventListener(r,M.listeners[i][r][s||"*"][n],!1),delete M.listeners[i][r][s||"*"][n])}else if(s&&r){if(M.listeners[i][r]&&M.listeners[i][r][s]){for(n in M.listeners[i][r][s])M.off(t,[r,s].join("."),n);delete M.listeners[i][r][s]}}else if(s)for(e in M.listeners[i])for(a in M.listeners[i][e])s===a&&M.off(t,[e,s].join("."));else if(r){if(M.listeners[i][r]){for(a in M.listeners[i][r])M.off(t,[r,a].join("."));delete M.listeners[i][r]}}else{for(e in M.listeners[i])M.off(t,e);delete M.listeners[i],delete M.handlerMap[i]}},M.extend(M.Element,{on:function(t,e,n,i){return M.on(this,t,e,n,i),this},off:function(t,e){return M.off(this.node,t,e),this},fire:function(e,n){return e instanceof t.Event?this.node.dispatchEvent(e):this.node.dispatchEvent(e=new t.CustomEvent(e,{detail:n,cancelable:!0})),this._event=e,this},event:function(){return this._event}}),M.Defs=M.invent({create:"defs",inherit:M.Container}),M.G=M.invent({create:"g",inherit:M.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new M.G)}}}),M.extend(M.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},prev:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof M.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof M.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),M.Mask=M.invent({create:"mask",inherit:M.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unmask()}),M.Element.prototype.remove.call(this)},targets:function(){return M.select('svg [mask*="'+this.id()+'"]')}},construct:{mask:function(){return this.defs().put(new M.Mask)}}}),M.extend(M.Element,{maskWith:function(t){var e=t instanceof M.Mask?t:this.parent().mask().add(t);return this.attr("mask",'url("#'+e.id()+'")')},unmask:function(){return this.attr("mask",null)},masker:function(){return this.reference("mask")}}),M.ClipPath=M.invent({create:"clipPath",inherit:M.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unclip()}),M.Element.prototype.remove.call(this)},targets:function(){return M.select('svg [clip-path*="'+this.id()+'"]')}},construct:{clip:function(){return this.defs().put(new M.ClipPath)}}}),M.extend(M.Element,{clipWith:function(t){var e=t instanceof M.ClipPath?t:this.parent().clip().add(t);return this.attr("clip-path",'url("#'+e.id()+'")')},unclip:function(){return this.attr("clip-path",null)},clipper:function(){return this.reference("clip-path")}}),M.Gradient=M.invent({create:function(t){this.constructor("object"==typeof t?t:M.create(t+"Gradient"))},inherit:M.Container,extend:{stop:function(t,e,n){return this.put(new M.Stop).update(t,e,n)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},url:function(){return"url(#"+this.id()+")"},toString:function(){return this.url()},attr:function(t,e,n){return"transform"===t&&(t="gradientTransform"),M.Container.prototype.attr.call(this,t,e,n)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),M.extend([M.Gradient,M.FX],{from:function(t,e){return"radialGradient"===(this._target||this).type?this.attr({fx:new M.Number(t),fy:new M.Number(e)}):this.attr({x1:new M.Number(t),y1:new M.Number(e)})},to:function(t,e){return"radialGradient"===(this._target||this).type?this.attr({cx:new M.Number(t),cy:new M.Number(e)}):this.attr({x2:new M.Number(t),y2:new M.Number(e)})}}),M.extend(M.Defs,{gradient:function(t,e){return this.put(new M.Gradient(t)).update(e)}}),M.Stop=M.invent({create:"stop",inherit:M.Element,extend:{update:function(t){return("number"==typeof t||t instanceof M.Number)&&(t={offset:arguments[0],color:arguments[1],opacity:arguments[2]}),null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new M.Number(t.offset)),this}}}),M.Pattern=M.invent({create:"pattern",inherit:M.Container,extend:{url:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.url()},attr:function(t,e,n){return"transform"===t&&(t="patternTransform"),M.Container.prototype.attr.call(this,t,e,n)}},construct:{pattern:function(t,e,n){return this.defs().pattern(t,e,n)}}}),M.extend(M.Defs,{pattern:function(t,e,n){return this.put(new M.Pattern).update(n).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),M.Doc=M.invent({create:function(t){this.constructor(t||M.create("svg")),this.namespace().defs()},inherit:M.Container,extend:{namespace:function(){return this.attr({xmlns:M.ns,version:"1.1"}).attr("xmlns:xlink",M.xlink,M.xmlns).attr("xmlns:svgjs",M.svgjs,M.xmlns)},defs:function(){return M.adopt(this.node.getElementsByTagName("defs")[0])||this.put(new M.Defs)},parent:function(){return"#document"===this.node.parentNode.nodeName?null:this.node.parentNode},remove:function(){return this.parent()&&this.parent().removeChild(this.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this},toNested:function(){var t=M.create("svg");return this.node.instance=null,t.appendChild(this.node),M.adopt(this.node)}}}),M.Shape=M.invent({create:function(t){this.constructor(t)},inherit:M.Element}),M.Bare=M.invent({create:function(t,e){if(this.constructor(M.create(t)),e)for(var n in e.prototype)"function"==typeof e.prototype[n]&&(this[n]=e.prototype[n])},inherit:M.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),M.extend(M.Parent,{element:function(t,e){return this.put(new M.Bare(t,e))}}),M.Symbol=M.invent({create:"symbol",inherit:M.Container,construct:{symbol:function(){return this.put(new M.Symbol)}}}),M.Use=M.invent({create:"use",inherit:M.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,M.xlink)}},construct:{use:function(t,e){return this.put(new M.Use).element(t,e)}}}),M.Rect=M.invent({create:"rect",inherit:M.Shape,construct:{rect:function(t,e){return this.put(new M.Rect).size(t,e)}}}),M.Circle=M.invent({create:"circle",inherit:M.Shape,construct:{circle:function(t){return this.put(new M.Circle).rx(new M.Number(t).divide(2)).move(0,0)}}}),M.extend([M.Circle,M.FX],{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),M.Ellipse=M.invent({create:"ellipse",inherit:M.Shape,construct:{ellipse:function(t,e){return this.put(new M.Ellipse).size(t,e).move(0,0)}}}),M.extend([M.Ellipse,M.Rect,M.FX],{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),M.extend([M.Circle,M.Ellipse],{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new M.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new M.Number(t).divide(2))},size:function(t,e){var n=d(this,t,e);return this.rx(new M.Number(n.width).divide(2)).ry(new M.Number(n.height).divide(2))}}),M.Line=M.invent({create:"line",inherit:M.Shape,extend:{array:function(){return new M.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,n,i){return null==t?this.array():(t=void 0!==e?{x1:t,y1:e,x2:n,y2:i}:new M.PointArray(t).toLine(),this.attr(t))},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var n=d(this,t,e);return this.attr(this.array().size(n.width,n.height).toLine())}},construct:{line:function(t,e,n,i){return M.Line.prototype.plot.apply(this.put(new M.Line),null!=t?[t,e,n,i]:[0,0,0,0])}}}),M.Polyline=M.invent({create:"polyline",inherit:M.Shape,construct:{polyline:function(t){return this.put(new M.Polyline).plot(t||new M.PointArray)}}}),M.Polygon=M.invent({create:"polygon",inherit:M.Shape,construct:{polygon:function(t){return this.put(new M.Polygon).plot(t||new M.PointArray)}}}),M.extend([M.Polyline,M.Polygon],{array:function(){return this._array||(this._array=new M.PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new M.PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var n=d(this,t,e);return this.attr("points",this.array().size(n.width,n.height))}}),M.extend([M.Line,M.Polyline,M.Polygon],{MorphArray:M.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),M.Path=M.invent({create:"path",inherit:M.Shape,extend:{MorphArray:M.PathArray,array:function(){return this._array||(this._array=new M.PathArray(this.attr("d")))},plot:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new M.PathArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var n=d(this,t,e);return this.attr("d",this.array().size(n.width,n.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new M.Path).plot(t||new M.PathArray)}}}),M.Image=M.invent({create:"image",inherit:M.Shape,extend:{load:function(e,n){if(!e)return this;var i=new t.Image;return M.on(i,"load",function(t){var r=this.parent(M.Pattern);0===this.width()&&0===this.height()&&this.size(i.width,i.height),r instanceof M.Pattern&&0===r.width()&&0===r.height()&&r.size(this.width(),this.height()),"function"==typeof n&&n.call(this,{width:i.width,height:i.height,ratio:i.width/i.height,url:e})},this),M.on(i,"load error",function(){M.off(i)}),this.attr("href",i.src=e,M.xlink)}},construct:{image:function(t,e){return this.put(new M.Image).size(0,0).load(t,e)}}}),M.Text=M.invent({create:function(t){this.constructor(t||M.create("text")),this.dom.leading=new M.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",M.defaults.attrs["font-family"])},inherit:M.Parent,extend:{x:function(t){return null==t?this.attr("x"):this.attr("x",t)},y:function(t){var e=this.attr("y"),n="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-n:e:this.attr("y","number"==typeof t?t+n:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if(void 0===t){var e=this.node.childNodes,n=0;t="";for(var i=0,r=e.length;i<r;++i)"textPath"!==e[i].nodeName?(i!==n&&3!==e[i].nodeType&&!0===M.adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent):0===i&&(n=1);return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var s=0,a=t.length;s<a;s++)this.tspan(t[s]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new M.Number(t),this.rebuild())},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,n=0,i=this.dom.leading*new M.Number(this.attr("font-size"));this.each(function(){this.dom.newLined&&(this.attr("x",e.attr("x")),"\n"===this.text()?n+=i:(this.attr("dy",i+n),n=0))}),this.fire("rebuild")}return this},build:function(t){return this._build=!!t,this},setData:function(t){return this.dom=t,this.dom.leading=new M.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new M.Text).text(t)},plain:function(t){return this.put(new M.Text).plain(t)}}}),M.Tspan=M.invent({create:"tspan",inherit:M.Parent,extend:{text:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){var t=this.parent(M.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),M.extend([M.Text,M.Tspan],{plain:function(t){return!1===this._build&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=new M.Tspan;return this._build||this.clear(),this.node.appendChild(e.node),e.text(t)},length:function(){return this.node.getComputedTextLength()}}),M.TextPath=M.invent({create:"textPath",inherit:M.Text,parent:M.Parent,extend:{MorphArray:M.PathArray,array:function(){var t=this.track();return t?t.array():null},plot:function(t){var e=this.track(),n=null;return e&&(n=e.plot(t)),null==t?n:this},track:function(){return this.reference("href")}},construct:{textPath:function(t,e){return this.defs().path(e).text(t).addTo(this)}}}),M.extend([M.Text],{path:function(t){var e=new M.TextPath;return t instanceof M.Path||(t=this.doc().defs().path(t)),e.attr("href","#"+t,M.xlink),this.put(e)},textPath:function(){return this.select("textPath")}}),M.extend([M.Path],{text:function(t){if(t instanceof M.Text){var e=t.text();return t.clear().path(this).text(e)}return this.parent().put(new M.Text).path(this).text(t)}}),M.Nested=M.invent({create:"svg",inherit:M.Container,construct:{nested:function(){return this.put(new M.Nested)}}}),M.A=M.invent({create:"a",inherit:M.Container,extend:{to:function(t){return this.attr("href",t,M.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new M.A).to(t)}}}),M.extend(M.Element,{linkTo:function(t){var e=new M.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),M.Marker=M.invent({create:"marker",inherit:M.Container,extend:{width:function(t){return this.attr("markerWidth",t)},height:function(t){return this.attr("markerHeight",t)},ref:function(t,e){return this.attr("refX",t).attr("refY",e)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return"url(#"+this.id()+")"}},construct:{marker:function(t,e,n){return this.defs().marker(t,e,n)}}}),M.extend(M.Defs,{marker:function(t,e,n){return this.put(new M.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(n)}}),M.extend([M.Line,M.Polyline,M.Polygon,M.Path],{marker:function(t,e,n,i){var r=["marker"];return"all"!==t&&r.push(t),r=r.join("-"),t=arguments[1]instanceof M.Marker?arguments[1]:this.doc().marker(e,n,i),this.attr(r,t)}});var k={stroke:["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],fill:["color","opacity","rule"],prefix:function(t,e){return"color"===e?t:t+"-"+e}};["fill","stroke"].forEach(function(t){var e,n={};n[t]=function(n){if(void 0===n)return this;if("string"==typeof n||M.Color.isRgb(n)||n&&"function"==typeof n.fill)this.attr(t,n);else for(e=k[t].length-1;e>=0;e--)null!=n[k[t][e]]&&this.attr(k.prefix(t,k[t][e]),n[k[t][e]]);return this},M.extend([M.Element,M.FX],n)}),M.extend([M.Element,M.FX],{rotate:function(t,e,n){return this.transform({rotation:t,cx:e,cy:n})},skew:function(t,e,n,i){return 1===arguments.length||3===arguments.length?this.transform({skew:t,cx:e,cy:n}):this.transform({skewX:t,skewY:e,cx:n,cy:i})},scale:function(t,e,n,i){return 1===arguments.length||3===arguments.length?this.transform({scale:t,cx:e,cy:n}):this.transform({scaleX:t,scaleY:e,cx:n,cy:i})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return e="number"==typeof t?t:e,this.transform({flip:t||"both",offset:e})},matrix:function(t){return this.attr("transform",new M.Matrix(6===arguments.length?[].slice.call(arguments):t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x(new M.Number(t).plus(this instanceof M.FX?0:this.x()),!0)},dy:function(t){return this.y(new M.Number(t).plus(this instanceof M.FX?0:this.y()),!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),M.extend([M.Rect,M.Ellipse,M.Circle,M.Gradient,M.FX],{radius:function(t,e){var n=(this._target||this).type;return"radialGradient"===n||"radialGradient"===n?this.attr("r",new M.Number(t)):this.rx(t).ry(null==e?t:e)}}),M.extend(M.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return new M.Point(this.node.getPointAtLength(t))}}),M.extend([M.Parent,M.Text,M.Tspan,M.FX],{font:function(t,e){if("object"==typeof t)for(e in t)this.font(e,t[e]);return"leading"===t?this.leading(e):"anchor"===t?this.attr("text-anchor",e):"size"===t||"family"===t||"weight"===t||"stretch"===t||"variant"===t||"style"===t?this.attr("font-"+t,e):this.attr(t,e)}}),M.extend(M.Element,{data:function(t,e,n){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(arguments.length<2)try{return JSON.parse(this.attr("data-"+t))}catch(e){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:!0===n||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),M.extend(M.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var n in t)this.remember(n,t[n]);else{if(1===arguments.length)return this.memory()[t];this.memory()[t]=e}return this},forget:function(){if(0===arguments.length)this._memory={};else for(var t=arguments.length-1;t>=0;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory||(this._memory={})}}),M.get=function(t){var n=e.getElementById(b(t)||t);return M.adopt(n)},M.select=function(t,n){return M.utils.map((n||e).querySelectorAll(t),function(t){return M.adopt(t)})},M.$$=function(t,n){return M.utils.map((n||e).querySelectorAll(t),function(t){return M.adopt(t)})},M.$=function(t,n){return M.adopt((n||e).querySelector(t))},M.extend(M.Parent,{select:function(t){return M.select(t,this.node)}});var S="abcdef".split("");return M.Box=M.invent({create:function(t){var e=[0,0,0,0];t="string"==typeof t?t.split(M.regex.delimiter).map(parseFloat):Array.isArray(t)?t:"object"==typeof t?[null!=t.left?t.left:t.x,null!=t.top?t.top:t.y,t.width,t.height]:4===arguments.length?[].slice.call(arguments):e,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3],w(this)},extend:{merge:function(t){var e=Math.min(this.x,t.x),n=Math.min(this.y,t.y);return new M.Box(e,n,Math.max(this.x+this.width,t.x+t.width)-e,Math.max(this.y+this.height,t.y+t.height)-n)},transform:function(t){var e=1/0,n=-1/0,i=1/0,r=-1/0;return[new M.Point(this.x,this.y),new M.Point(this.x2,this.y),new M.Point(this.x,this.y2),new M.Point(this.x2,this.y2)].forEach(function(s){s=s.transform(t),e=Math.min(e,s.x),n=Math.max(n,s.x),i=Math.min(i,s.y),r=Math.max(r,s.y)}),new M.Box(e,i,n-e,r-i)},addOffset:function(){return this.x+=t.pageXOffset,this.y+=t.pageYOffset,this},toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t,e,n,i){return this.destination=new M.Box(t,e,n,i),this},at:function(t){return this.destination?new M.Box(this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t):this}},parent:M.Element,construct:{bbox:function(){var t;try{if(t=this.node.getBBox(),i(t)&&!r(this.node))throw new Exception("Element not in the dom")}catch(n){try{var e=this.clone(M.parser().svg).show();t=e.node.getBBox(),e.remove()}catch(t){console.warn("Getting a bounding box of this element is not possible")}}return new M.Box(t)},rbox:function(t){try{var e=new M.Box(this.node.getBoundingClientRect());return t?e.transform(t.screenCTM().inverse()):e.addOffset()}catch(t){return new M.Box}}}}),M.extend([M.Doc,M.Nested,M.Symbol,M.Image,M.Pattern,M.Marker,M.ForeignObject,M.View],{viewbox:function(t,e,n,i){return null==t?new M.Box(this.attr("viewBox")):this.attr("viewBox",new M.Box(t,e,n,i))}}),M.parser=function(){var t;return M.parser.nodes.svg.node.parentNode||(t=e.body||e.documentElement,M.parser.nodes.svg.addTo(t)),M.parser.nodes},M.parser.nodes={svg:(new M.Nested).size(2,0).css({opacity:0,position:"absolute",left:"-100%",top:"-100%",overflow:"hidden"})},M.parser.nodes.path=M.parser.nodes.svg.path().node,M});
\ No newline at end of file
+/*! svg.js v3.0.0 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function n(t,n){if(t instanceof P.Element)return t;if("object"==typeof t)return P.adopt(t);if(null==t)return new P.Doc;if("string"==typeof t&&"<"!==t.charAt(0))return P.adopt(e.querySelector(t));var i=P.create("svg");return i.innerHTML=t,t=P.adopt(i.firstElementChild)}function i(t){return!(t.w||t.h||t.x||t.y)}function r(t){return(e.documentElement.contains||function(t){for(;t.parentNode;)t=t.parentNode;return t===e}).call(e.documentElement,t)}function s(t,e,n,i){return n+i.replace(P.regex.dots," .")}function o(t){for(var e=t.slice(0),n=e.length;n--;)Array.isArray(e[n])&&(e[n]=o(e[n]));return e}function a(t,e){return t instanceof e}function h(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function u(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function l(t){return t.charAt(0).toUpperCase()+t.slice(1)}function c(t){return 4===t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t}function f(t){var e=t.toString(16);return 1===e.length?"0"+e:e}function d(t,e,n){if(null==e||null==n){var i=t.bbox();null==e?e=i.width/i.height*n:null==n&&(n=i.height/i.width*e)}return{width:e,height:n}}function p(t,e,n){return{x:e*t.a+n*t.c+0,y:e*t.b+n*t.d+0}}function m(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function x(t){return t instanceof P.Matrix||(t=new P.Matrix(t)),t}function y(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function v(t){for(var e=0,n=t.length,i="";e<n;e++)i+=t[e][0],null!=t[e][1]&&(i+=t[e][1],null!=t[e][2]&&(i+=" ",i+=t[e][2],null!=t[e][3]&&(i+=" ",i+=t[e][3],i+=" ",i+=t[e][4],null!=t[e][5]&&(i+=" ",i+=t[e][5],i+=" ",i+=t[e][6],null!=t[e][7]&&(i+=" ",i+=t[e][7])))));return i+" "}function g(t){for(var e=t.children.length-1;e>=0;e--)g(t.children[e]);return t.id?P.adopt(t).id(P.eid(t.nodeName)):P.adopt(t)}function w(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function b(t){var e=(t||"").toString().match(P.regex.reference);if(e)return e[1]}if(!e.createElementNS||!e.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect)return{supported:!1};var P=this.SVG=function(t){if(P.supported)return t=n(t)};P.supported=!0,P.ns="http://www.w3.org/2000/svg",P.xmlns="http://www.w3.org/2000/xmlns/",P.xlink="http://www.w3.org/1999/xlink",P.svgjs="http://svgjs.com/svgjs",P.did=1e3,P.eid=function(t){return"Svgjs"+l(t)+P.did++},P.create=function(t){return e.createElementNS(this.ns,t)},P.extend=function(t,e){var n,i;for(t=Array.isArray(t)?t:[t],i=t.length-1;i>=0;i--)if(t[i])for(n in e)t[i].prototype[n]=e[n]},P.invent=function(t){var e="function"==typeof t.create?t.create:function(e){this.constructor(e||P.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&P.extend(e,t.extend),t.construct&&P.extend(t.parent||P.Container,t.construct),e},P.adopt=function(e){if(!e)return null;if(e.instance instanceof P.Element)return e.instance;if(!(e instanceof t.SVGElement))return new P.HtmlNode(e);return"svg"===e.nodeName?new P.Doc(e):"linearGradient"===e.nodeName||"radialGradient"===e.nodeName?new P.Gradient(e):P[l(e.nodeName)]?new(P[l(e.nodeName)])(e):new P.Parent(e)},P.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,transforms:/\)\s*,?\s*/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,delimiter:/[\s,]+/,hyphen:/([^e])-/gi,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,numbersWithDots:/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,dots:/\./g},P.utils={map:function(t,e){var n,i=t.length,r=[];for(n=0;n<i;n++)r.push(e(t[n]));return r},filter:function(t,e){var n,i=t.length,r=[];for(n=0;n<i;n++)e(t[n])&&r.push(t[n]);return r},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(e){return this.filter(e,function(e){return e instanceof t.SVGElement})}},P.defaults={attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"}},P.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?P.regex.isRgb.test(t)?(e=P.regex.rgb.exec(t.replace(P.regex.whitespace,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):P.regex.isHex.test(t)&&(e=P.regex.hex.exec(c(t)),this.r=parseInt(e[1],16),this.g=parseInt(e[2],16),this.b=parseInt(e[3],16)):"object"==typeof t&&(this.r=t.r,this.g=t.g,this.b=t.b))},P.extend(P.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+f(this.r)+f(this.g)+f(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11},morph:function(t){return this.destination=new P.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new P.Color({r:~~(this.r+(this.destination.r-this.r)*t),g:~~(this.g+(this.destination.g-this.g)*t),b:~~(this.b+(this.destination.b-this.b)*t)})):this}}),P.Color.test=function(t){return t+="",P.regex.isHex.test(t)||P.regex.isRgb.test(t)},P.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},P.Color.isColor=function(t){return P.Color.isRgb(t)||P.Color.test(t)},P.Array=function(t,e){t=(t||[]).valueOf(),0===t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},P.extend(P.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!==this.destination.length){for(var e=this.value[this.value.length-1],n=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(n);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,n=[];t<e;t++)-1===n.indexOf(this.value[t])&&n.push(this.value[t]);return this.value=n,n},at:function(t){if(!this.destination)return this;for(var e=0,n=this.value.length,i=[];e<n;e++)i.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new P.Array(i)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:t.trim().split(P.regex.delimiter).map(parseFloat)},reverse:function(){return this.value.reverse(),this},clone:function(){var t=new this.constructor;return t.value=o(this.value),t}}),P.PointArray=function(t,e){P.Array.call(this,t,e||[[0,0]])},P.PointArray.prototype=new P.Array,P.PointArray.prototype.constructor=P.PointArray,P.extend(P.PointArray,{toString:function(){for(var t=0,e=this.value.length,n=[];t<e;t++)n.push(this.value[t].join(","));return n.join(" ")},toLine:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}},at:function(t){if(!this.destination)return this;for(var e=0,n=this.value.length,i=[];e<n;e++)i.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new P.PointArray(i)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t)){if(Array.isArray(t[0]))return t}else t=t.trim().split(P.regex.delimiter).map(parseFloat);t.length%2!=0&&t.pop();for(var n=0,i=t.length;n<i;n+=2)e.push([t[n],t[n+1]]);return e},move:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i=this.value.length-1;i>=0;i--)this.value[i]=[this.value[i][0]+t,this.value[i][1]+e];return this},size:function(t,e){var n,i=this.bbox();for(n=this.value.length-1;n>=0;n--)i.width&&(this.value[n][0]=(this.value[n][0]-i.x)*t/i.width+i.x),i.height&&(this.value[n][1]=(this.value[n][1]-i.y)*e/i.height+i.y);return this},bbox:function(){var t=-1/0,e=-1/0,n=1/0,i=1/0;return this.value.forEach(function(r){t=Math.max(r[0],t),e=Math.max(r[1],e),n=Math.min(r[0],n),i=Math.min(r[1],i)}),{x:n,y:i,width:t-n,height:e-i}}});for(var M={M:function(t,e,n){return e.x=n.x=t[0],e.y=n.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,n){return e.x=n.x,e.y=n.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},A="mlhvqtcsaz".split(""),N=0,C=A.length;N<C;++N)M[A[N]]=function(t){return function(e,n,i){if("H"===t)e[0]=e[0]+n.x;else if("V"===t)e[0]=e[0]+n.y;else if("A"===t)e[5]=e[5]+n.x,e[6]=e[6]+n.y;else for(var r=0,s=e.length;r<s;++r)e[r]=e[r]+(r%2?n.y:n.x);return M[t](e,n,i)}}(A[N].toUpperCase());P.PathArray=function(t,e){P.Array.call(this,t,e||[["M",0,0]])},P.PathArray.prototype=new P.Array,P.PathArray.prototype.constructor=P.PathArray,P.extend(P.PathArray,{toString:function(){return v(this.value)},move:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i,r=this.value.length-1;r>=0;r--)i=this.value[r][0],"M"===i||"L"===i||"T"===i?(this.value[r][1]+=t,this.value[r][2]+=e):"H"===i?this.value[r][1]+=t:"V"===i?this.value[r][1]+=e:"C"===i||"S"===i||"Q"===i?(this.value[r][1]+=t,this.value[r][2]+=e,this.value[r][3]+=t,this.value[r][4]+=e,"C"===i&&(this.value[r][5]+=t,this.value[r][6]+=e)):"A"===i&&(this.value[r][6]+=t,this.value[r][7]+=e);return this},size:function(t,e){var n,i,r=this.bbox();for(n=this.value.length-1;n>=0;n--)i=this.value[n][0],"M"===i||"L"===i||"T"===i?(this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x,this.value[n][2]=(this.value[n][2]-r.y)*e/r.height+r.y):"H"===i?this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x:"V"===i?this.value[n][1]=(this.value[n][1]-r.y)*e/r.height+r.y:"C"===i||"S"===i||"Q"===i?(this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x,this.value[n][2]=(this.value[n][2]-r.y)*e/r.height+r.y,this.value[n][3]=(this.value[n][3]-r.x)*t/r.width+r.x,this.value[n][4]=(this.value[n][4]-r.y)*e/r.height+r.y,"C"===i&&(this.value[n][5]=(this.value[n][5]-r.x)*t/r.width+r.x,this.value[n][6]=(this.value[n][6]-r.y)*e/r.height+r.y)):"A"===i&&(this.value[n][1]=this.value[n][1]*t/r.width,this.value[n][2]=this.value[n][2]*e/r.height,this.value[n][6]=(this.value[n][6]-r.x)*t/r.width+r.x,this.value[n][7]=(this.value[n][7]-r.y)*e/r.height+r.y);return this},equalCommands:function(t){var e,n,i;for(t=new P.PathArray(t),i=this.value.length===t.value.length,e=0,n=this.value.length;i&&e<n;e++)i=this.value[e][0]===t.value[e][0];return i},morph:function(t){return t=new P.PathArray(t),this.equalCommands(t)?this.destination=t:this.destination=null,this},at:function(t){if(!this.destination)return this;var e,n,i,r,s=this.value,o=this.destination.value,a=[],h=new P.PathArray;for(e=0,n=s.length;e<n;e++){for(a[e]=[s[e][0]],i=1,r=s[e].length;i<r;i++)a[e][i]=s[e][i]+(o[e][i]-s[e][i])*t;"A"===a[e][0]&&(a[e][4]=+(0!==a[e][4]),a[e][5]=+(0!==a[e][5]))}return h.value=a,h},parse:function(t){if(t instanceof P.PathArray)return t.valueOf();var e,n={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7,Z:0};t="string"==typeof t?t.replace(P.regex.numbersWithDots,s).replace(P.regex.pathLetters," $& ").replace(P.regex.hyphen,"$1 -").trim().split(P.regex.delimiter):t.reduce(function(t,e){return[].concat.call(t,e)},[]);var i=[],r=new P.Point,o=new P.Point,a=0,h=t.length;do{P.regex.isPathLetter.test(t[a])?(e=t[a],++a):"M"===e?e="L":"m"===e&&(e="l"),i.push(M[e].call(null,t.slice(a,a+=n[e.toUpperCase()]).map(parseFloat),r,o))}while(h>a);return i},bbox:function(){return P.parser().path.setAttribute("d",this.toString()),P.parser.nodes.path.getBBox()}}),P.Number=P.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(P.regex.numberAndUnit))&&(this.value=parseFloat(e[1]),"%"===e[5]?this.value/=100:"s"===e[5]&&(this.value*=1e3),this.unit=e[5]):t instanceof P.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"===this.unit?~~(1e8*this.value)/1e6:"s"===this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return t=new P.Number(t),new P.Number(this+t,this.unit||t.unit)},minus:function(t){return t=new P.Number(t),new P.Number(this-t,this.unit||t.unit)},times:function(t){return t=new P.Number(t),new P.Number(this*t,this.unit||t.unit)},divide:function(t){return t=new P.Number(t),new P.Number(this/t,this.unit||t.unit)},to:function(t){var e=new P.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new P.Number(t),t.relative&&(this.destination.value+=this.value),this},at:function(t){return this.destination?new P.Number(this.destination).minus(this).times(t).plus(this):this}}}),P.HtmlNode=P.invent({create:function(t){this.node=t},extend:{add:function(t,e){return t=n(t),t.node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]||null),this},put:function(t,e){return this.add(t,e),t}}}),P.Element=P.invent({create:function(t){this.events={},this.dom={},this.node=t,this.node&&(this.type=t.nodeName,this.node.instance=this,this.events=t.events||{},t.hasAttribute("svgjs:data")&&this.setData(JSON.parse(t.getAttribute("svgjs:data"))||{}))},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var n=d(this,t,e);return this.width(new P.Number(n.width)).height(new P.Number(n.height))},clone:function(t){this.writeDataToDom();var e=g(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return n(t).put(this)},putIn:function(t){return n(t).add(this)},id:function(t){return void 0!==t||this.node.id||(this.node.id=P.eid(this.type)),this.attr("id",t)},inside:function(t,e){var n=this.bbox();return t>n.x&&e>n.y&&t<n.x+n.width&&e<n.y+n.height},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},visible:function(){return"none"!==this.css("display")},toString:function(){return this.id()},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(P.regex.delimiter)},hasClass:function(t){return-1!==this.classes().indexOf(t)},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(t){return this.hasClass(t)&&this.attr("class",this.classes().filter(function(e){return e!==t}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return P.get(this.attr(t))},parent:function(e){var n=this;if(!n.node.parentNode)return null;if(n=P.adopt(n.node.parentNode),!e)return n;for(;n&&n.node instanceof t.SVGElement;){if("string"==typeof e?n.matches(e):n instanceof e)return n;n=P.adopt(n.node.parentNode)}},doc:function(){var t=this.parent(P.Doc);return t&&t.doc()},defs:function(){return this.doc().defs()},parents:function(t){var e=[],n=this;do{if(!(n=n.parent(t))||!n.node)break;e.push(n)}while(n.parent);return e},matches:function(t){return h(this.node,t)},native:function(){return this.node},svg:function(t){var n,i;if(!(t&&this instanceof P.Parent))return this.writeDataToDom(),this.node.outerHTML;for(n=e.createElementNS(P.ns,"svg"),n.innerHTML=t,i=n.children.length;i--;)this.node.appendChild(n.firstElementChild);return this},writeDataToDom:function(){return this.is(P.Parent)&&this.each(function(){this.writeDataToDom()}),this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return a(this,t)}}}),P.easing={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return 1-Math.cos(t*Math.PI/2)}},P.morph=function(t){return function(e,n){return new P.MorphObj(e,n).at(t)}},P.Situation=P.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new P.Number(t.duration).valueOf(),this.delay=new P.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),P.FX=P.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,n){"object"==typeof t&&(e=t.ease,n=t.delay,t=t.duration);var i=new P.Situation({duration:t||1e3,delay:n||0,ease:P.easing[e||"-"]||e});return this.queue(i),this},delay:function(t){var e=new P.Situation({duration:t,delay:0,ease:P.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof P.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=t.requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){t.cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof P.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof P.Situation?this.start():this.situation(this)),this},initAnimations:function(){var t,e,n,i=this.situation;if(i.init)return this;for(t in i.animations)for(n=this.target()[t](),Array.isArray(n)||(n=[n]),Array.isArray(i.animations[t])||(i.animations[t]=[i.animations[t]]),e=n.length;e--;)i.animations[t][e]instanceof P.Number&&(n[e]=new P.Number(n[e])),i.animations[t][e]=n[e].morph(i.animations[t][e]);for(t in i.attrs)i.attrs[t]=new P.MorphObj(this.target().attr(t),i.attrs[t]);for(t in i.styles)i.styles[t]=new P.MorphObj(this.target().css(t),i.styles[t]);return i.initialTransformation=this.target().matrixify(),i.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){var n=this.active;return this.active=!1,e&&this.clearQueue(),t&&this.situation&&(!n&&this.startCurrent(),this.atEnd()),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return!0===this.situation.loops&&(this.situation.loops=this.situation.loop+1),"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var n=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*n,this.situation.finish=this.situation.start+n,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var n=this.last();return n.loops=null==t||t,n.loop=0,e&&(n.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return e.reversed=void 0===t?!e.reversed:t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){function e(i){i.detail.situation===n&&(t.call(this,n),this.off("finished.fx",e))}var n=this.last();return this.target().on("finished.fx",e),this._callStart()},during:function(t){function e(e){e.detail.situation===n&&t.call(this,e.detail.pos,P.morph(e.detail.pos),e.detail.eased,n)}var n=this.last();return this.target().off("during.fx",e).on("during.fx",e),this.after(function(){this.off("during.fx",e)}),this._callStart()},afterAll:function(t){var e=function e(n){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this._callStart()},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,P.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)}),this._callStart()},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,n){return this.last()[n||"animations"][t]=e,this._callStart()},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),!1!==this.situation.loops){var e,n,i;e=Math.max(this.absPos,0),n=Math.floor(e),!0===this.situation.loops||n<this.situation.loops?(this.pos=e-n,i=this.situation.loop,this.situation.loop=n):(this.absPos=this.situation.loops,this.pos=1,i=this.situation.loop-1,this.situation.loop=this.situation.loops),this.situation.reversing&&(this.situation.reversed=this.situation.reversed!==Boolean((this.situation.loop-i)%2))}else this.absPos=Math.min(this.absPos,1),this.pos=this.absPos;this.pos<0&&(this.pos=0),this.situation.reversed&&(this.pos=1-this.pos);var r=this.situation.ease(this.pos);for(var s in this.situation.once)s>this.lastPos&&s<=r&&(this.situation.once[s].call(this.target(),this.pos,r),delete this.situation.once[s]);return this.active&&this.target().fire("during",{pos:this.pos,eased:r,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1===this.pos&&!this.situation.reversed||this.situation.reversed&&0===this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.situations.length||(this.target().off(".fx"),this.active=!1)),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=r,this):this},eachAt:function(){var t,e,n,i=this,r=this.target(),s=this.situation;for(t in s.animations)n=[].concat(s.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),r[t].apply(r,n);for(t in s.attrs)n=[t].concat(s.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),r.attr.apply(r,n);for(t in s.styles)n=[t].concat(s.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),r.css.apply(r,n);if(s.transforms.length){for(n=s.initialTransformation,t=0,e=s.transforms.length;t<e;t++){var o=s.transforms[t];o instanceof P.Matrix?n=o.relative?n.multiply((new P.Matrix).morph(o).at(s.ease(this.pos))):n.morph(o).at(s.ease(this.pos)):(o.relative||o.undo(n.extract()),n=n.multiply(o.at(s.ease(this.pos))))}r.matrix(n)}return this},once:function(t,e,n){var i=this.last();return n||(t=i.ease(t)),i.once[t]=e,this},_callStart:function(){return setTimeout(function(){this.start()}.bind(this),0),this}},parent:P.Element,construct:{animate:function(t,e,n){return(this.fx||(this.fx=new P.FX(this))).animate(t,e,n)},delay:function(t){return(this.fx||(this.fx=new P.FX(this))).delay(t)},stop:function(t,e){return this.fx&&this.fx.stop(t,e),this},finish:function(){return this.fx&&this.fx.finish(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this},speed:function(t){if(this.fx){if(null==t)return this.fx.speed();this.fx.speed(t)}return this}}}),P.MorphObj=P.invent({create:function(t,e){return P.Color.isColor(e)?new P.Color(t).morph(e):P.regex.delimiter.test(t)?new P.Array(t).morph(e):P.regex.numberAndUnit.test(e)?new P.Number(t).morph(e):(this.value=t,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),P.extend(P.FX,{attr:function(t,e,n){if("object"==typeof t)for(var i in t)this.attr(i,t[i]);else this.add(t,e,"attrs");return this},css:function(t,e){if("object"==typeof t)for(var n in t)this.css(n,t[n]);else this.add(t,e,"styles");return this},x:function(t,e){if(this.target()instanceof P.G)return this.transform({x:t},e),this;var n=new P.Number(t);return n.relative=e,this.add("x",n)},y:function(t,e){if(this.target()instanceof P.G)return this.transform({y:t},e),this;var n=new P.Number(t);return n.relative=e,this.add("y",n)},cx:function(t){return this.add("cx",new P.Number(t))},cy:function(t){return this.add("cy",new P.Number(t))},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target()instanceof P.Text)this.attr("font-size",t);else{var n;t&&e||(n=this.target().bbox()),t||(t=n.width/n.height*e),e||(e=n.height/n.width*t),this.add("width",new P.Number(t)).add("height",new P.Number(e))}return this},width:function(t){return this.add("width",new P.Number(t))},height:function(t){return this.add("height",new P.Number(t))},plot:function(t,e,n,i){return 4===arguments.length?this.plot([t,e,n,i]):this.add("plot",new(this.target().MorphArray)(t))},leading:function(t){return this.target().leading?this.add("leading",new P.Number(t)):this},viewbox:function(t,e,n,i){return this.target()instanceof P.Container&&this.add("viewbox",new P.Box(t,e,n,i)),this},update:function(t){if(this.target()instanceof P.Stop){if("number"==typeof t||t instanceof P.Number)return this.update({offset:arguments[0],color:arguments[1],opacity:arguments[2]});null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",t.offset)}return this}}),P.Matrix=P.invent({create:function(t){var e,n=m([1,0,0,1,0,0]);for(t=t instanceof P.Element?t.matrixify():"string"==typeof t?m(t.split(P.regex.delimiter).map(parseFloat)):6===arguments.length?m([].slice.call(arguments)):Array.isArray(t)?m(t):"object"==typeof t?t:n,e=S.length-1;e>=0;--e)this[S[e]]=null!=t[S[e]]?t[S[e]]:n[S[e]]},extend:{extract:function(){var t=p(this,0,1),e=p(this,1,0),n=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(n*Math.PI/180)+this.f*Math.sin(n*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(n*Math.PI/180)+this.e*Math.sin(-n*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-n,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:n,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new P.Matrix(this)}},clone:function(){return new P.Matrix(this)},morph:function(t){return this.destination=new P.Matrix(t),this},at:function(t){return this.destination?new P.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t}):this},multiply:function(t){return new P.Matrix(this.native().multiply(x(t).native()))},inverse:function(){return new P.Matrix(this.native().inverse())},translate:function(t,e){return new P.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,n,i){return 1===arguments.length?e=t:3===arguments.length&&(i=n,n=e,e=t),this.around(n,i,new P.Matrix(t,0,0,e,0,0))},rotate:function(t,e,n){return t=P.utils.radians(t),this.around(e,n,new P.Matrix(Math.cos(t),Math.sin(t),-Math.sin(t),Math.cos(t),0,0))},flip:function(t,e){return"x"===t?this.scale(-1,1,e,0):"y"===t?this.scale(1,-1,0,e):this.scale(-1,-1,t,null!=e?e:t)},skew:function(t,e,n,i){return 1===arguments.length?e=t:3===arguments.length&&(i=n,n=e,e=t),t=P.utils.radians(t),e=P.utils.radians(e),this.around(n,i,new P.Matrix(1,Math.tan(e),Math.tan(t),1,0,0))},skewX:function(t,e,n){return this.skew(t,0,e,n)},skewY:function(t,e,n){return this.skew(0,t,e,n)},around:function(t,e,n){return this.multiply(new P.Matrix(1,0,0,1,t||0,e||0)).multiply(n).multiply(new P.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=P.parser.nodes.svg.node.createSVGMatrix(),e=S.length-1;e>=0;e--)t[S[e]]=this[S[e]];return t},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:P.Element,construct:{ctm:function(){return new P.Matrix(this.node.getCTM())},screenCTM:function(){if(this instanceof P.Doc&&!this.isRoot()){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new P.Matrix(e)}return new P.Matrix(this.node.getScreenCTM())}}}),P.Point=P.invent({create:function(t,e){var n,i={x:0,y:0};n=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=t?{x:t,y:null!=e?e:t}:i,this.x=n.x,this.y=n.y},extend:{clone:function(){return new P.Point(this)},morph:function(t,e){return this.destination=new P.Point(t,e),this},at:function(t){return this.destination?new P.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t}):this},native:function(){var t=P.parser.nodes.svg.node.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new P.Point(this.native().matrixTransform(t.native()))}}}),P.extend(P.Element,{point:function(t,e){return new P.Point(t,e).transform(this.screenCTM().inverse())}}),P.extend(P.Element,{attr:function(t,e,n){if(null==t){for(t={},e=this.node.attributes,n=e.length-1;n>=0;n--)t[e[n].nodeName]=P.regex.isNumber.test(e[n].nodeValue)?parseFloat(e[n].nodeValue):e[n].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return e=this.node.getAttribute(t),null==e?P.defaults.attrs[t]:P.regex.isNumber.test(e)?parseFloat(e):e;"fill"!==t&&"stroke"!==t||(P.regex.isImage.test(e)&&(e=this.doc().defs().image(e)),e instanceof P.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new P.Number(e):P.Color.isColor(e)?e=new P.Color(e):Array.isArray(e)&&(e=new P.Array(e)),"leading"===t?this.leading&&this.leading(e):"string"==typeof n?this.node.setAttributeNS(n,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!==t&&"x"!==t||this.rebuild(t,e)}return this}}),P.extend(P.Element,{transform:function(t,e){var n,i,r=this
+;if("object"!=typeof t)return n=new P.Matrix(r).extract(),"string"==typeof t?n[t]:n;if(n=new P.Matrix(r),e=!!e||!!t.relative,null!=t.a)n=e?n.multiply(new P.Matrix(t)):new P.Matrix(t);else if(null!=t.rotation)y(t,r),n=e?n.rotate(t.rotation,t.cx,t.cy):n.rotate(t.rotation-n.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(y(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,!e){var s=n.extract();t.scaleX=1*t.scaleX/s.scaleX,t.scaleY=1*t.scaleY/s.scaleY}n=n.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skew||null!=t.skewX||null!=t.skewY){if(y(t,r),t.skewX=null!=t.skew?t.skew:null!=t.skewX?t.skewX:0,t.skewY=null!=t.skew?t.skew:null!=t.skewY?t.skewY:0,!e){var o=n.extract();n=n.multiply((new P.Matrix).skew(o.skewX,o.skewY,o.cx,o.cy).inverse())}n=n.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?("x"===t.flip||"y"===t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(i=r.bbox(),t.flip=i.cx,t.offset=i.cy):t.flip=t.offset,n=(new P.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(e?n=n.translate(t.x,t.y):(null!=t.x&&(n.e=t.x),null!=t.y&&(n.f=t.y)));return this.attr("transform",n)}}),P.extend(P.FX,{transform:function(t,e){var n,i,r=this.target();return"object"!=typeof t?(n=new P.Matrix(r).extract(),"string"==typeof t?n[t]:n):(e=!!e||!!t.relative,null!=t.a?n=new P.Matrix(t):null!=t.rotation?(y(t,r),n=new P.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(y(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,n=new P.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(y(t,r),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,n=new P.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?("x"===t.flip||"y"===t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(i=r.bbox(),t.flip=i.cx,t.offset=i.cy):t.flip=t.offset,n=(new P.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(n=new P.Translate(t.x,t.y)),n?(n.relative=e,this.last().transforms.push(n),this._callStart()):this)}}),P.extend(P.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){return(this.attr("transform")||"").split(P.regex.transforms).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(P.regex.delimiter).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"===e[0]?t.multiply(m(e[1])):t[e[0]].apply(t,e[1])},new P.Matrix)},toParent:function(t){if(this===t)return this;var e=this.screenCTM(),n=t.screenCTM().inverse();return this.addTo(t).untransform().transform(n.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),P.Transformation=P.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.constructor.bind(this)([].slice.call(arguments));var n,i;if(Array.isArray(t))for(n=0,i=this.arguments.length;n<i;++n)this[this.arguments[n]]=t[n];else if("object"==typeof t)for(n=0,i=this.arguments.length;n<i;++n)this[this.arguments[n]]=t[this.arguments[n]];this.inversed=!1,!0===e&&(this.inversed=!0)},extend:{arguments:[],method:"",at:function(t){for(var e=[],n=0,i=this.arguments.length;n<i;++n)e.push(this[this.arguments[n]]);var r=this._undo||new P.Matrix;return r=(new P.Matrix).morph(P.Matrix.prototype[this.method].apply(r,e)).at(t),this.inversed?r.inverse():r},undo:function(t){for(var e=0,n=this.arguments.length;e<n;++e)t[this.arguments[e]]=void 0===this[this.arguments[e]]?0:t[this.arguments[e]];return t.cx=this.cx,t.cy=this.cy,this._undo=new(P[l(this.method)])(t,!0).at(1),this}}}),P.Translate=P.invent({parent:P.Matrix,inherit:P.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["transformedX","transformedY"],method:"translate"}}),P.Rotate=P.invent({parent:P.Matrix,inherit:P.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["rotation","cx","cy"],method:"rotate",at:function(t){var e=(new P.Matrix).rotate((new P.Number).morph(this.rotation-(this._undo?this._undo.rotation:0)).at(t),this.cx,this.cy);return this.inversed?e.inverse():e},undo:function(t){return this._undo=t,this}}}),P.Scale=P.invent({parent:P.Matrix,inherit:P.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["scaleX","scaleY","cx","cy"],method:"scale"}}),P.Skew=P.invent({parent:P.Matrix,inherit:P.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["skewX","skewY","cx","cy"],method:"skew"}}),P.extend(P.Element,{css:function(t,e){var n,i,r={};if(0===arguments.length)return this.node.style.cssText.split(/\s*;\s*/).filter(function(t){return!!t.length}).forEach(function(t){n=t.split(/\s*:\s*/),r[n[0]]=n[1]}),r;if(arguments.length<2){if(Array.isArray(t)){for(i=t.length;i--;)r[u(t[i])]=this.node.style[u(t[i])];return r}if("string"==typeof t)return this.node.style[u(t)];if("object"==typeof t)for(i in t)this.node.style[u(i)]=null==t[i]||P.regex.isBlank.test(t[i])?"":t[i]}return 2===arguments.length&&(this.node.style[u(t)]=null==e||P.regex.isBlank.test(e)?"":e),this}}),P.Parent=P.invent({create:function(t){this.constructor(t)},inherit:P.Element,extend:{children:function(){return P.utils.map(this.node.children,function(t){return P.adopt(t)})},add:function(t,e){return t=n(t),t.node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]||null),this},put:function(t,e){return this.add(t,e),t.instance||t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.children).indexOf(t.node)},get:function(t){return P.adopt(this.node.children[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.children.length-1)},each:function(t,e){var n,i,r=this.children();for(n=0,i=r.length;n<i;n++)r[n]instanceof P.Element&&t.apply(r[n],[n,r]),e&&r[n]instanceof P.Parent&&r[n].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this}}}),P.extend(P.Parent,{flatten:function(t){return this instanceof P.G||this instanceof P.Doc?(t=t||(this instanceof P.Doc&&this.isRoot()?this:this.parent(P.Parent)),this.each(function(){return this instanceof P.Defs?this:this instanceof P.Parent?this.flatten(t):this.toParent(t)}),this.node.firstElementChild||this.remove(),this):this},ungroup:function(t){return this instanceof P.G||this instanceof P.Doc&&!this.isRoot()?(t=t||this.parent(P.Parent),this.each(function(){return this.toParent(t)}),this.remove(),this):this}}),P.Container=P.invent({create:function(t){this.constructor(t)},inherit:P.Parent}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){P.Element.prototype[t]=function(e){return P.on(this,t,e),this}}),P.listenerId=0,P.on=function(t,e,n,i,r){var s=n.bind(i||t),o=t instanceof P.Element?t.node:t;o.instance=o.instance||{events:{}};var a=o.instance.events;n._svgjsListenerId||(n._svgjsListenerId=++P.listenerId),e.split(P.regex.delimiter).forEach(function(t){var e=t.split(".")[0],i=t.split(".")[1]||"*";a[e]=a[e]||{},a[e][i]=a[e][i]||{},a[e][i][n._svgjsListenerId]=s,o.addEventListener(e,s,r||!1)})},P.off=function(t,e,n,i){var r=t instanceof P.Element?t.node:t;if(r.instance&&("function"!=typeof n||(n=n._svgjsListenerId))){var s=r.instance.events;(e||"").split(P.regex.delimiter).forEach(function(t){var e,o,a=t&&t.split(".")[0],h=t&&t.split(".")[1];if(n)s[a]&&s[a][h||"*"]&&(r.removeEventListener(a,s[a][h||"*"][n],i||!1),delete s[a][h||"*"][n]);else if(a&&h){if(s[a]&&s[a][h]){for(o in s[a][h])P.off(r,[a,h].join("."),o);delete s[a][h]}}else if(h)for(t in s)for(e in s[t])h===e&&P.off(r,[t,h].join("."));else if(a){if(s[a]){for(e in s[a])P.off(r,[a,e].join("."));delete s[a]}}else{for(t in s)P.off(r,t);r.instance.events={}}})}},P.extend(P.Element,{on:function(t,e,n,i){return P.on(this,t,e,n,i),this},off:function(t,e){return P.off(this.node,t,e),this},dispatch:function(e,n){return e instanceof t.Event?this.node.dispatchEvent(e):this.node.dispatchEvent(e=new t.CustomEvent(e,{detail:n,cancelable:!0})),e},fire:function(t,e){return this.dispatch(t,e),this}}),P.Defs=P.invent({create:"defs",inherit:P.Container}),P.G=P.invent({create:"g",inherit:P.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new P.G)}}}),P.extend(P.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},prev:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof P.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof P.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),P.Mask=P.invent({create:"mask",inherit:P.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unmask()}),P.Element.prototype.remove.call(this)},targets:function(){return P.select('svg [mask*="'+this.id()+'"]')}},construct:{mask:function(){return this.defs().put(new P.Mask)}}}),P.extend(P.Element,{maskWith:function(t){var e=t instanceof P.Mask?t:this.parent().mask().add(t);return this.attr("mask",'url("#'+e.id()+'")')},unmask:function(){return this.attr("mask",null)},masker:function(){return this.reference("mask")}}),P.ClipPath=P.invent({create:"clipPath",inherit:P.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unclip()}),P.Element.prototype.remove.call(this)},targets:function(){return P.select('svg [clip-path*="'+this.id()+'"]')}},construct:{clip:function(){return this.defs().put(new P.ClipPath)}}}),P.extend(P.Element,{clipWith:function(t){var e=t instanceof P.ClipPath?t:this.parent().clip().add(t);return this.attr("clip-path",'url("#'+e.id()+'")')},unclip:function(){return this.attr("clip-path",null)},clipper:function(){return this.reference("clip-path")}}),P.Gradient=P.invent({create:function(t){this.constructor("object"==typeof t?t:P.create(t+"Gradient"))},inherit:P.Container,extend:{stop:function(t,e,n){return this.put(new P.Stop).update(t,e,n)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},url:function(){return"url(#"+this.id()+")"},toString:function(){return this.url()},attr:function(t,e,n){return"transform"===t&&(t="gradientTransform"),P.Container.prototype.attr.call(this,t,e,n)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),P.extend([P.Gradient,P.FX],{from:function(t,e){return"radialGradient"===(this._target||this).type?this.attr({fx:new P.Number(t),fy:new P.Number(e)}):this.attr({x1:new P.Number(t),y1:new P.Number(e)})},to:function(t,e){return"radialGradient"===(this._target||this).type?this.attr({cx:new P.Number(t),cy:new P.Number(e)}):this.attr({x2:new P.Number(t),y2:new P.Number(e)})}}),P.extend(P.Defs,{gradient:function(t,e){return this.put(new P.Gradient(t)).update(e)}}),P.Stop=P.invent({create:"stop",inherit:P.Element,extend:{update:function(t){return("number"==typeof t||t instanceof P.Number)&&(t={offset:arguments[0],color:arguments[1],opacity:arguments[2]}),null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new P.Number(t.offset)),this}}}),P.Pattern=P.invent({create:"pattern",inherit:P.Container,extend:{url:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.url()},attr:function(t,e,n){return"transform"===t&&(t="patternTransform"),P.Container.prototype.attr.call(this,t,e,n)}},construct:{pattern:function(t,e,n){return this.defs().pattern(t,e,n)}}}),P.extend(P.Defs,{pattern:function(t,e,n){return this.put(new P.Pattern).update(n).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),P.Doc=P.invent({create:function(t){this.constructor(t||P.create("svg")),this.namespace()},inherit:P.Container,extend:{isRoot:function(){return!(this.node.parentNode&&this.node.parentNode instanceof t.SVGElement&&"#document"!==this.node.parentNode.nodeName)},doc:function(){return this.isRoot()?this:P.Element.prototype.doc.call(this)},namespace:function(){return this.isRoot()?this.attr({xmlns:P.ns,version:"1.1"}).attr("xmlns:xlink",P.xlink,P.xmlns).attr("xmlns:svgjs",P.svgjs,P.xmlns):this.doc().namespace()},defs:function(){return this.isRoot()?P.adopt(this.node.getElementsByTagName("defs")[0])||this.put(new P.Defs):this.doc().defs()},parent:function(t){return this.isRoot()?"#document"===this.node.parentNode.nodeName?null:this.node.parentNode:P.Element.prototype.parent.call(this,t)},remove:function(){return this.isRoot()?(this.parent()&&this.parent().removeChild(this.node),this):P.Element.prototype.remove.call(this)},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this}},construct:{nested:function(){return this.put(new P.Doc)}}}),P.Shape=P.invent({create:function(t){this.constructor(t)},inherit:P.Element}),P.Bare=P.invent({create:function(t,e){if(this.constructor(P.create(t)),e)for(var n in e.prototype)"function"==typeof e.prototype[n]&&(this[n]=e.prototype[n])},inherit:P.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),P.extend(P.Parent,{element:function(t,e){return this.put(new P.Bare(t,e))}}),P.Symbol=P.invent({create:"symbol",inherit:P.Container,construct:{symbol:function(){return this.put(new P.Symbol)}}}),P.Use=P.invent({create:"use",inherit:P.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,P.xlink)}},construct:{use:function(t,e){return this.put(new P.Use).element(t,e)}}}),P.Rect=P.invent({create:"rect",inherit:P.Shape,construct:{rect:function(t,e){return this.put(new P.Rect).size(t,e)}}}),P.Circle=P.invent({create:"circle",inherit:P.Shape,construct:{circle:function(t){return this.put(new P.Circle).rx(new P.Number(t).divide(2)).move(0,0)}}}),P.extend([P.Circle,P.FX],{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),P.Ellipse=P.invent({create:"ellipse",inherit:P.Shape,construct:{ellipse:function(t,e){return this.put(new P.Ellipse).size(t,e).move(0,0)}}}),P.extend([P.Ellipse,P.Rect,P.FX],{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),P.extend([P.Circle,P.Ellipse],{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new P.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new P.Number(t).divide(2))},size:function(t,e){var n=d(this,t,e);return this.rx(new P.Number(n.width).divide(2)).ry(new P.Number(n.height).divide(2))}}),P.Line=P.invent({create:"line",inherit:P.Shape,extend:{array:function(){return new P.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,n,i){return null==t?this.array():(t=void 0!==e?{x1:t,y1:e,x2:n,y2:i}:new P.PointArray(t).toLine(),this.attr(t))},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var n=d(this,t,e);return this.attr(this.array().size(n.width,n.height).toLine())}},construct:{line:function(t,e,n,i){return P.Line.prototype.plot.apply(this.put(new P.Line),null!=t?[t,e,n,i]:[0,0,0,0])}}}),P.Polyline=P.invent({create:"polyline",inherit:P.Shape,construct:{polyline:function(t){return this.put(new P.Polyline).plot(t||new P.PointArray)}}}),P.Polygon=P.invent({create:"polygon",inherit:P.Shape,construct:{polygon:function(t){return this.put(new P.Polygon).plot(t||new P.PointArray)}}}),P.extend([P.Polyline,P.Polygon],{array:function(){return this._array||(this._array=new P.PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new P.PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var n=d(this,t,e);return this.attr("points",this.array().size(n.width,n.height))}}),P.extend([P.Line,P.Polyline,P.Polygon],{MorphArray:P.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),P.Path=P.invent({create:"path",inherit:P.Shape,extend:{MorphArray:P.PathArray,array:function(){return this._array||(this._array=new P.PathArray(this.attr("d")))},plot:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new P.PathArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var n=d(this,t,e);return this.attr("d",this.array().size(n.width,n.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new P.Path).plot(t||new P.PathArray)}}}),P.Image=P.invent({create:"image",inherit:P.Shape,extend:{load:function(e,n){if(!e)return this;var i=new t.Image;return P.on(i,"load",function(t){var r=this.parent(P.Pattern);0===this.width()&&0===this.height()&&this.size(i.width,i.height),r instanceof P.Pattern&&0===r.width()&&0===r.height()&&r.size(this.width(),this.height()),"function"==typeof n&&n.call(this,{width:i.width,height:i.height,ratio:i.width/i.height,url:e})},this),P.on(i,"load error",function(){P.off(i)}),this.attr("href",i.src=e,P.xlink)}},construct:{image:function(t,e){return this.put(new P.Image).size(0,0).load(t,e)}}}),P.Text=P.invent({create:function(t){this.constructor(t||P.create("text")),this.dom.leading=new P.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",P.defaults.attrs["font-family"])},inherit:P.Parent,extend:{x:function(t){return null==t?this.attr("x"):this.attr("x",t)},y:function(t){var e=this.attr("y"),n="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-n:e:this.attr("y","number"==typeof t?t+n:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if(void 0===t){var e=this.node.childNodes,n=0;t="";for(var i=0,r=e.length;i<r;++i)"textPath"!==e[i].nodeName?(i!==n&&3!==e[i].nodeType&&!0===P.adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent):0===i&&(n=1);return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var s=0,o=t.length;s<o;s++)this.tspan(t[s]).newLine()}return this.build(!1).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new P.Number(t),this.rebuild())},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,n=0,i=this.dom.leading*new P.Number(this.attr("font-size"));this.each(function(){this.dom.newLined&&(this.attr("x",e.attr("x")),"\n"===this.text()?n+=i:(this.attr("dy",i+n),n=0))}),this.fire("rebuild")}return this},build:function(t){return this._build=!!t,this},setData:function(t){return this.dom=t,this.dom.leading=new P.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new P.Text).text(t)},plain:function(t){return this.put(new P.Text).plain(t)}}}),P.Tspan=P.invent({create:"tspan",inherit:P.Parent,extend:{text:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){var t=this.parent(P.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),P.extend([P.Text,P.Tspan],{plain:function(t){return!1===this._build&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=new P.Tspan;return this._build||this.clear(),this.node.appendChild(e.node),e.text(t)},length:function(){return this.node.getComputedTextLength()}}),P.TextPath=P.invent({create:"textPath",inherit:P.Text,parent:P.Parent,extend:{MorphArray:P.PathArray,array:function(){var t=this.track();return t?t.array():null},plot:function(t){var e=this.track(),n=null;return e&&(n=e.plot(t)),null==t?n:this},track:function(){return this.reference("href")}},construct:{textPath:function(t,e){return this.defs().path(e).text(t).addTo(this)}}}),P.extend([P.Text],{path:function(t){var e=new P.TextPath;return t instanceof P.Path||(t=this.doc().defs().path(t)),e.attr("href","#"+t,P.xlink),this.put(e)},textPath:function(){return this.select("textPath")}}),P.extend([P.Path],{text:function(t){if(t instanceof P.Text){var e=t.text();return t.clear().path(this).text(e)}return this.parent().put(new P.Text).path(this).text(t)}}),P.A=P.invent({create:"a",inherit:P.Container,extend:{to:function(t){return this.attr("href",t,P.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new P.A).to(t)}}}),P.extend(P.Element,{linkTo:function(t){var e=new P.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),P.Marker=P.invent({create:"marker",inherit:P.Container,extend:{width:function(t){return this.attr("markerWidth",t)},height:function(t){return this.attr("markerHeight",t)},ref:function(t,e){return this.attr("refX",t).attr("refY",e)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return"url(#"+this.id()+")"}},construct:{marker:function(t,e,n){return this.defs().marker(t,e,n)}}}),P.extend(P.Defs,{marker:function(t,e,n){return this.put(new P.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(n)}}),P.extend([P.Line,P.Polyline,P.Polygon,P.Path],{marker:function(t,e,n,i){var r=["marker"];return"all"!==t&&r.push(t),r=r.join("-"),t=arguments[1]instanceof P.Marker?arguments[1]:this.doc().marker(e,n,i),this.attr(r,t)}});var k={stroke:["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],fill:["color","opacity","rule"],prefix:function(t,e){return"color"===e?t:t+"-"+e}};["fill","stroke"].forEach(function(t){var e,n={};n[t]=function(n){if(void 0===n)return this;if("string"==typeof n||P.Color.isRgb(n)||n&&"function"==typeof n.fill)this.attr(t,n);else for(e=k[t].length-1;e>=0;e--)null!=n[k[t][e]]&&this.attr(k.prefix(t,k[t][e]),n[k[t][e]]);return this},P.extend([P.Element,P.FX],n)}),P.extend([P.Element,P.FX],{rotate:function(t,e,n){return this.transform({rotation:t,cx:e,cy:n})},skew:function(t,e,n,i){return 1===arguments.length||3===arguments.length?this.transform({skew:t,cx:e,cy:n}):this.transform({skewX:t,skewY:e,cx:n,cy:i})},scale:function(t,e,n,i){return 1===arguments.length||3===arguments.length?this.transform({scale:t,cx:e,cy:n}):this.transform({scaleX:t,scaleY:e,cx:n,cy:i})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return e="number"==typeof t?t:e,this.transform({flip:t||"both",offset:e})},matrix:function(t){return this.attr("transform",new P.Matrix(6===arguments.length?[].slice.call(arguments):t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x(new P.Number(t).plus(this instanceof P.FX?0:this.x()),!0)},dy:function(t){return this.y(new P.Number(t).plus(this instanceof P.FX?0:this.y()),!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),P.extend([P.Rect,P.Ellipse,P.Circle,P.Gradient,P.FX],{radius:function(t,e){var n=(this._target||this).type;return"radialGradient"===n||"radialGradient"===n?this.attr("r",new P.Number(t)):this.rx(t).ry(null==e?t:e)}}),P.extend(P.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return new P.Point(this.node.getPointAtLength(t))}}),P.extend([P.Parent,P.Text,P.Tspan,P.FX],{font:function(t,e){if("object"==typeof t)for(e in t)this.font(e,t[e]);return"leading"===t?this.leading(e):"anchor"===t?this.attr("text-anchor",e):"size"===t||"family"===t||"weight"===t||"stretch"===t||"variant"===t||"style"===t?this.attr("font-"+t,e):this.attr(t,e)}}),P.extend(P.Element,{data:function(t,e,n){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(arguments.length<2)try{return JSON.parse(this.attr("data-"+t))}catch(e){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:!0===n||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),P.extend(P.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var n in t)this.remember(n,t[n]);else{if(1===arguments.length)return this.memory()[t];this.memory()[t]=e}return this},forget:function(){if(0===arguments.length)this._memory={};else for(var t=arguments.length-1;t>=0;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory||(this._memory={})}}),P.get=function(t){var n=e.getElementById(b(t)||t);return P.adopt(n)},P.select=function(t,n){return P.utils.map((n||e).querySelectorAll(t),function(t){return P.adopt(t)})},P.$$=function(t,n){return P.utils.map((n||e).querySelectorAll(t),function(t){return P.adopt(t)})},P.$=function(t,n){return P.adopt((n||e).querySelector(t))},P.extend(P.Parent,{select:function(t){return P.select(t,this.node)}});var S="abcdef".split("");return P.Box=P.invent({create:function(t){var e=[0,0,0,0];t="string"==typeof t?t.split(P.regex.delimiter).map(parseFloat):Array.isArray(t)?t:"object"==typeof t?[null!=t.left?t.left:t.x,null!=t.top?t.top:t.y,t.width,t.height]:4===arguments.length?[].slice.call(arguments):e,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3],w(this)},extend:{merge:function(t){var e=Math.min(this.x,t.x),n=Math.min(this.y,t.y);return new P.Box(e,n,Math.max(this.x+this.width,t.x+t.width)-e,Math.max(this.y+this.height,t.y+t.height)-n)},transform:function(t){var e=1/0,n=-1/0,i=1/0,r=-1/0;return[new P.Point(this.x,this.y),new P.Point(this.x2,this.y),new P.Point(this.x,this.y2),new P.Point(this.x2,this.y2)].forEach(function(s){s=s.transform(t),e=Math.min(e,s.x),n=Math.max(n,s.x),i=Math.min(i,s.y),r=Math.max(r,s.y)}),new P.Box(e,i,n-e,r-i)},addOffset:function(){return this.x+=t.pageXOffset,this.y+=t.pageYOffset,this},toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t,e,n,i){return this.destination=new P.Box(t,e,n,i),this},at:function(t){return this.destination?new P.Box(this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t):this}},parent:P.Element,construct:{bbox:function(){var t;try{if(t=this.node.getBBox(),i(t)&&!r(this.node))throw new Exception("Element not in the dom")}catch(n){try{var e=this.clone(P.parser().svg).show();t=e.node.getBBox(),e.remove()}catch(t){console.warn("Getting a bounding box of this element is not possible")}}return new P.Box(t)},rbox:function(t){try{var e=new P.Box(this.node.getBoundingClientRect());return t?e.transform(t.screenCTM().inverse()):e.addOffset()}catch(t){return new P.Box}}}}),P.extend([P.Doc,P.Symbol,P.Image,P.Pattern,P.Marker,P.ForeignObject,P.View],{viewbox:function(t,e,n,i){return null==t?new P.Box(this.attr("viewBox")):this.attr("viewBox",new P.Box(t,e,n,i))}}),P.parser=function(){var t;return P.parser.nodes.svg.node.parentNode||(t=e.body||e.documentElement,P.parser.nodes.svg.addTo(t)),P.parser.nodes},P.parser.nodes={svg:P().size(2,0).css({opacity:0,position:"absolute",left:"-100%",top:"-100%",overflow:"hidden"})},P.parser.nodes.path=P.parser.nodes.svg.path().node,P});
\ No newline at end of file
index 61533dea3d510773c255c809ace9e491af0a2e41..2a3f3f81c1fe2bcfd315298a32aa4ae72955aac5 100644 (file)
@@ -133,13 +133,6 @@ describe('Text', function() {
     })
   })
 
-  describe('size()', function() {
-    it('should define the width and height of the element', function() {
-      text.size(50)
-      expect(text.attr('font-size').valueOf()).toBe(50)
-    })
-  })
-
   describe('translate()', function() {
     it('sets the translation of an element', function() {
       text.transform({ x: 12, y: 12 })
index 4242547bd9eb82e6ac850cb8b30df34c3fea11c8..b210c7bdb7d67c2858b2ac53949ca9acee50ce7e 100644 (file)
@@ -90,10 +90,6 @@ SVG.Text = SVG.invent({
       // disable build mode and rebuild lines
       return this.build(false).rebuild()
     },
-    // Set font size
-    size: function (size) {
-      return this.attr('font-size', size).rebuild()
-    },
     // Set / get leading
     leading: function (value) {
       // act as getter
@@ -197,7 +193,7 @@ SVG.Tspan = SVG.invent({
       // mark new line
       this.dom.newLined = true
 
-      // apply new hy¡n
+      // apply new position
       return this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x())
     }
   }