text: /**
   * Modules in this bundle
   * @license
   *
   * svg2pdf.js:
   *   license: MIT (http://opensource.org/licenses/MIT)
   *   author: yFiles for HTML Support Team <yfileshtml@yworks.com>
   *   homepage: https://github.com/yWorks/svg2pdf.js#readme
   *   version: 1.1.0
   *
   * svgpath:
   *   license: MIT (http://opensource.org/licenses/MIT)
   *   maintainers: vitaly <vitaly@rcdesign.ru>
   *   homepage: https://github.com/fontello/svgpath#readme
   *   version: 2.2.1
   *
   * This header is generated by licensify (https://github.com/twada/licensify)
   */
  (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.svg2pdf = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  'use strict';
  
  module.exports = require('./lib/svgpath');
  
  },{"./lib/svgpath":6}],2:[function(require,module,exports){
  // Convert an arc to a sequence of cubic bézier curves
  //
  'use strict';
  
  
  var TAU = Math.PI * 2;
  
  
  /* eslint-disable space-infix-ops */
  
  // Calculate an angle between two vectors
  //
  function vector_angle(ux, uy, vx, vy) {
    var sign = (ux * vy - uy * vx < 0) ? -1 : 1;
    var umag = Math.sqrt(ux * ux + uy * uy);
    var vmag = Math.sqrt(ux * ux + uy * uy);
    var dot  = ux * vx + uy * vy;
    var div  = dot / (umag * vmag);
  
    // rounding errors, e.g. -1.0000000000000002 can screw up this
    if (div >  1.0) { div =  1.0; }
    if (div < -1.0) { div = -1.0; }
  
    return sign * Math.acos(div);
  }
  
  
  // Convert from endpoint to center parameterization,
  // see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
  //
  // Return [cx, cy, theta1, delta_theta]
  //
  function get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi) {
    // Step 1.
    //
    // Moving an ellipse so origin will be the middlepoint between our two
    // points. After that, rotate it to line up ellipse axes with coordinate
    // axes.
    //
    var x1p =  cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
    var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
  
    var rx_sq  =  rx * rx;
    var ry_sq  =  ry * ry;
    var x1p_sq = x1p * x1p;
    var y1p_sq = y1p * y1p;
  
    // Step 2.
    //
    // Compute coordinates of the centre of this ellipse (cx', cy')
    // in the new coordinate system.
    //
    var radicant = (rx_sq * ry_sq) - (rx_sq * y1p_sq) - (ry_sq * x1p_sq);
  
    if (radicant < 0) {
      // due to rounding errors it might be e.g. -1.3877787807814457e-17
      radicant = 0;
    }
  
    radicant /=   (rx_sq * y1p_sq) + (ry_sq * x1p_sq);
    radicant = Math.sqrt(radicant) * (fa === fs ? -1 : 1);
  
    var cxp = radicant *  rx/ry * y1p;
    var cyp = radicant * -ry/rx * x1p;
  
    // Step 3.
    //
    // Transform back to get centre coordinates (cx, cy) in the original
    // coordinate system.
    //
    var cx = cos_phi*cxp - sin_phi*cyp + (x1+x2)/2;
    var cy = sin_phi*cxp + cos_phi*cyp + (y1+y2)/2;
  
    // Step 4.
    //
    // Compute angles (theta1, delta_theta).
    //
    var v1x =  (x1p - cxp) / rx;
    var v1y =  (y1p - cyp) / ry;
    var v2x = (-x1p - cxp) / rx;
    var v2y = (-y1p - cyp) / ry;
  
    var theta1 = vector_angle(1, 0, v1x, v1y);
    var delta_theta = vector_angle(v1x, v1y, v2x, v2y);
  
    if (fs === 0 && delta_theta > 0) {
      delta_theta -= TAU;
    }
    if (fs === 1 && delta_theta < 0) {
      delta_theta += TAU;
    }
  
    return [ cx, cy, theta1, delta_theta ];
  }
  
  //
  // Approximate one unit arc segment with bézier curves,
  // see http://math.stackexchange.com/questions/873224
  //
  function approximate_unit_arc(theta1, delta_theta) {
    var alpha = 4/3 * Math.tan(delta_theta/4);
  
    var x1 = Math.cos(theta1);
    var y1 = Math.sin(theta1);
    var x2 = Math.cos(theta1 + delta_theta);
    var y2 = Math.sin(theta1 + delta_theta);
  
    return [ x1, y1, x1 - y1*alpha, y1 + x1*alpha, x2 + y2*alpha, y2 - x2*alpha, x2, y2 ];
  }
  
  module.exports = function a2c(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
    var sin_phi = Math.sin(phi * TAU / 360);
    var cos_phi = Math.cos(phi * TAU / 360);
  
    // Make sure radii are valid
    //
    var x1p =  cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
    var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
  
    if (x1p === 0 && y1p === 0) {
      // we're asked to draw line to itself
      return [];
    }
  
    if (rx === 0 || ry === 0) {
      // one of the radii is zero
      return [];
    }
  
  
    // Compensate out-of-range radii
    //
    rx = Math.abs(rx);
    ry = Math.abs(ry);
  
    var lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
    if (lambda > 1) {
      rx *= Math.sqrt(lambda);
      ry *= Math.sqrt(lambda);
    }
  
  
    // Get center parameters (cx, cy, theta1, delta_theta)
    //
    var cc = get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi);
  
    var result = [];
    var theta1 = cc[2];
    var delta_theta = cc[3];
  
    // Split an arc to multiple segments, so each segment
    // will be less than τ/4 (= 90°)
    //
    var segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1);
    delta_theta /= segments;
  
    for (var i = 0; i < segments; i++) {
      result.push(approximate_unit_arc(theta1, delta_theta));
      theta1 += delta_theta;
    }
  
    // We have a bezier approximation of a unit circle,
    // now need to transform back to the original ellipse
    //
    return result.map(function (curve) {
      for (var i = 0; i < curve.length; i += 2) {
        var x = curve[i + 0];
        var y = curve[i + 1];
  
        // scale
        x *= rx;
        y *= ry;
  
        // rotate
        var xp = cos_phi*x - sin_phi*y;
        var yp = sin_phi*x + cos_phi*y;
  
        // translate
        curve[i + 0] = xp + cc[0];
        curve[i + 1] = yp + cc[1];
      }
  
      return curve;
    });
  };
  
  },{}],3:[function(require,module,exports){
  'use strict';
  
  /* eslint-disable space-infix-ops */
  
  // The precision used to consider an ellipse as a circle
  //
  var epsilon = 0.0000000001;
  
  // To convert degree in radians
  //
  var torad = Math.PI / 180;
  
  // Class constructor :
  //  an ellipse centred at 0 with radii rx,ry and x - axis - angle ax.
  //
  function Ellipse(rx, ry, ax) {
    if (!(this instanceof Ellipse)) { return new Ellipse(rx, ry, ax); }
    this.rx = rx;
    this.ry = ry;
    this.ax = ax;
  }
  
  // Apply a linear transform m to the ellipse
  // m is an array representing a matrix :
  //    -         -
  //   | m[0] m[2] |
  //   | m[1] m[3] |
  //    -         -
  //
  Ellipse.prototype.transform = function (m) {
    // We consider the current ellipse as image of the unit circle
    // by first scale(rx,ry) and then rotate(ax) ...
    // So we apply ma =  m x rotate(ax) x scale(rx,ry) to the unit circle.
    var c = Math.cos(this.ax * torad), s = Math.sin(this.ax * torad);
    var ma = [
      this.rx * (m[0]*c + m[2]*s),
      this.rx * (m[1]*c + m[3]*s),
      this.ry * (-m[0]*s + m[2]*c),
      this.ry * (-m[1]*s + m[3]*c)
    ];
  
    // ma * transpose(ma) = [ J L ]
    //                      [ L K ]
    // L is calculated later (if the image is not a circle)
    var J = ma[0]*ma[0] + ma[2]*ma[2],
        K = ma[1]*ma[1] + ma[3]*ma[3];
  
    // the discriminant of the characteristic polynomial of ma * transpose(ma)
    var D = ((ma[0]-ma[3])*(ma[0]-ma[3]) + (ma[2]+ma[1])*(ma[2]+ma[1])) *
            ((ma[0]+ma[3])*(ma[0]+ma[3]) + (ma[2]-ma[1])*(ma[2]-ma[1]));
  
    // the "mean eigenvalue"
    var JK = (J + K) / 2;
  
    // check if the image is (almost) a circle
    if (D < epsilon * JK) {
      // if it is
      this.rx = this.ry = Math.sqrt(JK);
      this.ax = 0;
      return this;
    }
  
    // if it is not a circle
  es,
  // see http://math.stackexchange.com/questions/873224
  //
  function approximate_unit_arc(theta1, delta_theta) {
    var alpha = 4/3 * Math.tan(delta_theta/4);
  
    var x1 = Math.cos(theta1);
    var y1 = Math.sin(theta1);
    var x2 = Math.cos(theta1 + delta_theta);
    var y2 = Math.sin(theta1 + delta_theta);
  
    return [ x1, y1, x1 - y1*alpha, y1 + x1*alpha, x2 + y2*alpha, y2 - x2*alpha, x2, y2 ];
  }
  
  module.exports = function a2c(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
    var sin_phi = Math.sin(phi * TAU / 360);
    var cos_phi = Math.cos(phi * TAU / 360);
  
    // Make sure radii are valid
    //
    var x1p =  cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
    var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
  
    if (x1p === 0 && y1p === 0) {
      // we're asked to draw line to itself
      return [];
    }
  
    if (rx === 0 || ry === 0) {
      // one of the radii is zero
      return [];
    }
  
  
    // Compensate out-of-range radii
    //
    rx = Math.abs(rx);
    ry = Math.abs(ry);
  
    var lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
    if (lambda > 1) {
      rx *= Math.sqrt(lambda);
      ry *= Math.sqrt(lambda);
    }
  
  
    // Get center parameters (cx, cy, theta1, delta_theta)
    //
    var cc = get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi);
  
    var result = [];
    var theta1 = cc[2];
    var delta_theta = cc[3];
  
    // Split an arc to multiple segments, so each segment
    // will be less than τ/4 (= 90°)
    //
    var segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1);
    delta_theta /= segments;
  
    for (var i = 0; i < segments; i++) {
      result.push(approximate_unit_arc(theta1, delta_theta));
      theta1 += delta_theta;
    }
  
    // We have a bezier approximation of a unit circle,
    // now need to transform back to the original ellipse
    //
    return result.map(function (curve) {
      for (var i = 0; i < curve.length; i += 2) {
        var x = curve[i + 0];
        var y = curve[i + 1];
  
        // scale
        x *= rx;
        y *= ry;
  
        // rotate
        var xp = cos_phi*x - sin_phi*y;
        var yp = sin_phi*x + cos_phi*y;
  
        // translate
        curve[i + 0] = xp + cc[0];
        curve[i + 1] = yp + cc[1];
      }
  
      return curve;
    });
  };
  
  },{}],3:[function(require,module,exports){
  'use strict';
  
  /* eslint-disable space-infix-ops */
  
  // The precision used to consider an ellipse as a circle
  //
  var epsilon = 0.0000000001;
  
  // To convert degree in radians
  //
  var torad = Math.PI / 180;
  
  // Class constructor :
  //  an ellipse centred at 0 with radii rx,ry and x - axis - angle ax.
  //
  function Ellipse(rx, ry, ax) {
    if (!(this instanceof Ellipse)) { return new Ellipse(rx, ry, ax); }
    this.rx = rx;
    this.ry = ry;
    this.ax = ax;
  }
  
  // Apply a linear transform m to the ellipse
  // m is an array representing a matrix :
  //    -         -
  //   | m[0] m[2] |
  //   | m[1] m[3] |
  //    -         -
  //
  Ellipse.prototype.transform = function (m) {
    // We consider the current ellipse as image of the unit circle
    // by first scale(rx,ry) and then rotate(ax) ...
    // So we apply ma =  m x rotate(ax) x scale(rx,ry) to the unit circle.
    var c = Math.cos(this.ax * torad), s = Math.sin(this.ax * torad);
    var ma = [
      this.rx * (m[0]*c + m[2]*s),
      this.rx * (m[1]*c + m[3]*s),
      this.ry * (-m[0]*s + m[2]*c),
      this.ry * (-m[1]*s + m[3]*c)
    ];
  
    // ma * transpose(ma) = [ J L ]
    //                      [ L K ]
    // L is calculated later (if the image is not a circle)
    var J = ma[0]*ma[0] + ma[2]*ma[2],
        K = ma[1]*ma[1] + ma[3]*ma[3];
  
    // the discriminant of the characteristic polynomial of ma * transpose(ma)
    var D = ((ma[0]-ma[3])*(ma[0]-ma[3]) + (ma[2]+ma[1])*(ma[2]+ma[1])) *
            ((ma[0]+ma[3])*(ma[0]+ma[3]) + (ma[2]-ma[1])*(ma[2]-ma[1]));
  
    // the "mean eigenvalue"
    var JK = (J + K) / 2;
  
    // check if the image is (almost) a circle
    if (D < epsilon * JK) {
      // if it is
      this.rx = this.ry = Math.sqrt(JK);
      this.ax = 0;
      return this;
    }
  
    // if it is not a circle
    var L = ma[0]*ma[1] + ma[2]*ma[3];
  
    D = Math.sqrt(D);
  
    // {l1,l2} = the two eigen values of ma * transpose(ma)
    var l1 = JK + D/2,
        l2 = JK - D/2;
    // the x - axis - rotation angle is the argument of the l1 - eigenvector
    this.ax = (Math.abs(L) < epsilon && Math.abs(l1 - K) < epsilon) ?
      90
    :
      Math.atan(Math.abs(L) > Math.abs(l1 - K) ?
        (l1 - J) / L
      :
        L / (l1 - K)
      ) * 180 / Math.PI;
  
    // if ax > 0 => rx = sqrt(l1), ry = sqrt(l2), else exchange axes and ax += 90
    if (this.ax >= 0) {
      // if ax in [0,90]
      this.rx = Math.sqrt(l1);
      this.ry = Math.sqrt(l2);
    } else {
      // if ax in ]-90,0[ => exchange axes
      this.ax += 90;
      this.rx = Math.sqrt(l2);
      this.ry = Math.sqrt(l1);
    }
  
    return this;
  };
  
  // Check if the ellipse is (almost) degenerate, i.e. rx = 0 or ry = 0
  //
  Ellipse.prototype.isDegenerate = function () {
    return (this.rx < epsilon * this.ry || this.ry < epsilon * this.rx);
  };
  
  module.exports = Ellipse;
  
  },{}],4:[function(require,module,exports){
  'use strict';
  
  // combine 2 matrixes
  // m1, m2 - [a, b, c, d, e, g]
  //
  function combine(m1, m2) {
    return [
      m1[0] * m2[0] + m1[2] * m2[1],
      m1[1] * m2[0] + m1[3] * m2[1],
      m1[0] * m2[2] + m1[2] * m2[3],
      m1[1] * m2[2] + m1[3] * m2[3],
      m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
      m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
    ];
  }
  
  
  function Matrix() {
    if (!(this instanceof Matrix)) { return new Matrix(); }
    this.queue = [];   // list of matrixes to apply
    this.cache = null; // combined matrix cache
  }
  
  
  Matrix.prototype.matrix = function (m) {
    if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) {
      return this;
    }
    this.cache = null;
    this.queue.push(m);
    return this;
  };
  
  
  Matrix.prototype.translate = function (tx, ty) {
    if (tx !== 0 || ty !== 0) {
      this.cache = null;
      this.queue.push([ 1, 0, 0, 1, tx, ty ]);
    }
    return this;
  };
  
  
  Matrix.prototype.scale = function (sx, sy) {
    if (sx !== 1 || sy !== 1) {
      this.cache = null;
      this.queue.push([ sx, 0, 0, sy, 0, 0 ]);
    }
    return this;
  };
  
  
  Matrix.prototype.rotate = function (angle, rx, ry) {
    var rad, cos, sin;
  
    if (angle !== 0) {
      this.translate(rx, ry);
  
      rad = angle * Math.PI / 180;
      cos = Math.cos(rad);
      sin = Math.sin(rad);
  
      this.queue.push([ cos, sin, -sin, cos, 0, 0 ]);
      this.cache = null;
  
      this.translate(-rx, -ry);
    }
    return this;
  };
  
  
  Matrix.prototype.skewX = function (angle) {
    if (angle !== 0) {
      this.cache = null;
      this.queue.push([ 1, 0, Math.tan(angle * Math.PI / 180), 1, 0, 0 ]);
    }
    return this;
  };
  
  
  Matrix.prototype.skewY = function (angle) {
    if (angle !== 0) {
      this.cache = null;
      this.queue.push([ 1, Math.tan(angle * Math.PI / 180), 0, 1, 0, 0 ]);
    }
    return this;
  };
  
  
  // Flatten queue
  //
  Matrix.prototype.toArray = function () {
    if (this.cache) {
      return this.cache;
    }
  
    if (!this.queue.length) {
      this.cache = [ 1, 0, 0, 1, 0, 0 ];
      return this.cache;
    }
  
    this.cache = this.queue[0];
  
    if (this.queue.length === 1) {
      return this.cache;
    }
  
    for (var i = 1; i < this.queue.length; i++) {
      this.cache = combine(this.cache, this.queue[i]);
    }
  
    return this.cache;
  };
  
  
  // Apply list of matrixes to (x,y) point.
  // If `isRelative` set, `translate` component of matrix will be skipped
  //
  Matrix.prototype.calc = function (x, y, isRelative) {
    var m;
  
    // Don't change point on empty transforms queue
    if (!this.queue.length) { return [ x, y ]; }
  
    // Calculate final matrix, if not exists
    //
    // NB. if you deside to apply transforms to point one-by-one,
    // they should be taken in reverse order
  
    if (!this.cache) {
      this.cache = this.toArray();
    }
  
    m = this.cache;
  
    // Apply matrix to point
    return [
      x * m[0] + y * m[2] + (isRelative ? 0 : m[4]),
      x * m[1] + y * m[3] + (isRelative ? 0 : m[5])
    ];
  };
  
  
  module.exports = Matrix;
  
  },{}],5:[function(require,module,exports){
  'use strict';
  
  
  var paramCounts = { a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0 };
  
  var SPECIAL_SPACES = [
    0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
    0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF
  ];
  
  function isSpace(ch) {
    return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) || // Line terminators
      // White spaces
      (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
      (ch >= 0x1680 && SPECIAL_SPACES.indexOf(ch) >= 0);
  }
  
  function isCommand(code) {
    /*eslint-disable no-bitwise*/
    switch (code | 0x20) {
      case 0x6D/* m */:
      case 0x7A/* z */:
      case 0x6C/* l */:
      case 0x68/* h */:
      case 0x76/* v */:
      case 0x63/* c */:
      case 0x73/* s */:
      case 0x71/* q */:
      case 0x74/* t */:
      case 0x61/* a */:
      case 0x72/* r */:
        return true;
    }
    return false;
  }
  
  function isDigit(code) {
    return (code >= 48 && code <= 57);   // 0..9
  }
  
  function isDigitStart(code) {
    return (code >= 48 && code <= 57) || /* 0..9 */
            code === 0x2B || /* + */
            code === 0x2D || /* - */
            code === 0x2E;   /* . */
  }
  
  
  function State(path) {
    this.index  = 0;
    this.path   = path;
    this.max    = path.length;
    this.result = [];
    this.param  = 0.0;
    this.err    = '';
    this.segmentStart = 0;
    this.data   = [];
  }
  
  function skipSpaces(state) {
    while (state.index < state.max && isSpace(state.path.charCodeAt(state.index))) {
      state.index++;
    }
  }
  
  
  function scanParam(state) {
    var start = state.index,
        index = start,
        max = state.max,
        zeroFirst = false,
        hasCeiling = false,
        hasDecimal = false,
        hasDot = false,
        ch;
  
    if (index >= max) {
      state.err = 'SvgPath: missed param (at pos ' + index + ')';
      return;
    }
    ch = state.path.charCodeAt(index);
  
    if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {
      index++;
      ch = (index < max) ? state.path.charCodeAt(index) : 0;
    }
  
    // This logic is shamelessly borrowed from Esprima
    // https://github.com/ariya/esprimas
    //
    if (!isDigit(ch) && ch !== 0x2E/* . */) {
      state.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')';
      return;
    }
  
    if (ch !== 0x2E/* . */) {
      zeroFirst = (ch === 0x30/* 0 */);
      index++;
  
      ch = (index < max) ? state.path.charCodeAt(index) : 0;
  
      if (zeroFirst && index < max) {
        // decimal number starts with '0' such as '09' is illegal.
        if (ch && isDigit(ch)) {
          state.err = 'SvgPath: numbers started with `0` such as `09` are ilegal (at pos ' + start + ')';
          return;
        }
      }
  
      while (index < max && isDigit(state.path.charCodeAt(index))) {
        index++;
        hasCeiling = true;
      }
      ch = (index < max) ? state.path.charCodeAt(index) : 0;
    }
  
    if (ch === 0x2E/* . */) {
      hasDot = true;
      index++;
      while (isDigit(state.path.charCodeAt(index))) {
        index++;
        hasDecimal = true;
      }
      ch = (index < max) ? state.path.charCodeAt(index) : 0;
    }
  
    if (ch === 0x65/* e */ || ch === 0x45/* E */) {
      if (hasDot && !hasCeiling && !hasDecimal) {
        state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
        return;
      }
  
      index++;
  
      ch = (index < max) ? state.path.charCodeAt(index) : 0;
      if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {
        index++;
      }
      if (index < max && isDigit(state.path.charCodeAt(index))) {
        while (index < max && isDigit(state.path.charCodeAt(index))) {
          index++;
        }
      } else {
        state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
        return;
      }
    }
  
    state.index = index;
    state.param = parseFloat(state.path.slice(start, index)) + 0.0;
  }
  
  
  function finalizeSegment(state) {
    var cmd, cmdLC;
  
    // Process duplicated commands (without comand name)
  m.calc(x, s[1], false);
          result = (p[0] === m.calc(x, y, false)[0]) ? [ 'V', p[1] ] : [ 'L', p[0], p[1] ];
          break;
  
        case 'h':
          p      = m.calc(s[1], 0, true);
          result = (p[1] === 0) ? [ 'h', p[0] ] : [ 'l', p[0], p[1] ];
          break;
  
        case 'H':
          p      = m.calc(s[1], y, false);
          result = (p[1] === m.calc(x, y, false)[1]) ? [ 'H', p[0] ] : [ 'L', p[0], p[1] ];
          break;
  
        case 'a':
        case 'A':
          // ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
  
          // Drop segment if arc is empty (end point === start point)
          /*if ((s[0] === 'A' && s[6] === x && s[7] === y) ||
              (s[0] === 'a' && s[6] === 0 && s[7] === 0)) {
            return [];
          }*/
  
          // Transform rx, ry and the x-axis-rotation
          var ma = m.toArray();
          var e = ellipse(s[1], s[2], s[3]).transform(ma);
  
          // flip sweep-flag if matrix is not orientation-preserving
          if (ma[0] * ma[3] - ma[1] * ma[2] < 0) {
            s[5] = s[5] ? '0' : '1';
          }
  
          // Transform end point as usual (without translation for relative notation)
          p = m.calc(s[6], s[7], s[0] === 'a');
  
          // Empty arcs can be ignored by renderer, but should not be dropped
          // to avoid collisions with `S A S` and so on. Replace with empty line.
          if ((s[0] === 'A' && s[6] === x && s[7] === y) ||
              (s[0] === 'a' && s[6] === 0 && s[7] === 0)) {
            result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ];
            break;
          }
  
          // if the resulting ellipse is (almost) a segment ...
          if (e.isDegenerate()) {
            // replace the arc by a line
            result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ];
          } else {
            // if it is a real ellipse
            // s[0], s[4] and s[5] are not modified
            result = [ s[0], e.rx, e.ry, e.ax, s[4], s[5], p[0], p[1] ];
          }
  
          break;
  
        case 'm':
          // Edge case. The very first `m` should be processed as absolute, if happens.
          // Make sense for coord shift transforms.
          isRelative = index > 0;
  
          p = m.calc(s[1], s[2], isRelative);
          result = [ 'm', p[0], p[1] ];
          break;
  
        default:
          name       = s[0];
          result     = [ name ];
          isRelative = (name.toLowerCase() === name);
  
          // Apply transformations to the segment
          for (i = 1; i < s.length; i += 2) {
            p = m.calc(s[i], s[i + 1], isRelative);
            result.push(p[0], p[1]);
          }
      }
  
      self.segments[index] = result;
    }, true);
  };
  
  
  // Apply stacked commands
  //
  SvgPath.prototype.__evaluateStack = function () {
    var m, i;
  
    if (!this.__stack.length) { return; }
  
    if (this.__stack.length === 1) {
      this.__matrix(this.__stack[0]);
      this.__stack = [];
      return;
    }
  
    m = matrix();
    i = this.__stack.length;
  
    while (--i >= 0) {
      m.matrix(this.__stack[i].toArray());
    }
  
    this.__matrix(m);
    this.__stack = [];
  };
  
  
  // Convert processed SVG Path back to string
  //
  SvgPath.prototype.toString = function () {
    var elements = [], skipCmd, cmd;
  
    this.__evaluateStack();
  
    for (var i = 0; i < this.segments.length; i++) {
      // remove repeating commands names
      cmd = this.segments[i][0];
      skipCmd = i > 0 && cmd !== 'm' && cmd !== 'M' && cmd === this.segments[i - 1][0];
      elements = elements.concat(skipCmd ? this.segments[i].slice(1) : this.segments[i]);
    }
  
    return elements.join(' ')
              // Optimizations: remove spaces around commands & before `-`
              //
              // We could also remove leading zeros for `0.5`-like values,
              // but their count is too small to spend time for.
              .replace(/ ?([achlmqrstvz]) ?/gi, '$1')
              .replace(/ \-/g, '-')
              // workaround for FontForge SVG importing bug
              .replace(/zm/g, 'z m');
  };
  
  
  // Translate path to (x [, y])
  //
  SvgPath.prototype.translate = function (x, y) {
    this.__stack.push(matrix().translate(x, y || 0));
    return this;
  };
  
  
  // Scale path to (sx [, sy])
  // sy = sx if not defined
  //
  SvgPath.prototype.scale = function (sx, sy) {
    this.__stack.push(matrix().scale(sx, (!sy && (sy !== 0)) ? sx : sy));
    return this;
  };
  
  
  // Rotate path around point (sx [, sy])
  // sy = sx if not defined
  //
  SvgPath.prototype.rotate = function (angle, rx, ry) {
    this.__stack.push(matrix().rotate(angle, rx || 0, ry || 0));
    return this;
  };
  
  
  // Skew path along the X axis by `degrees` angle
  //
  SvgPath.prototype.skewX = function (degrees) {
    this.__stack.push(matrix().skewX(degrees));
    return this;
  };
  
  
  // Skew path along the Y axis by `degrees` angle
  //
  SvgPath.prototype.skewY = function (degrees) {
    this.__stack.push(matrix().skewY(degrees));
    return this;
  };
  
  
  // Apply matrix transform (array of 6 elements)
  //
  SvgPath.prototype.matrix = function (m) {
    this.__stack.push(matrix().matrix(m));
    return this;
  };
  
  
  // Transform path according to "transform" attr of SVG spec
  //
  SvgPath.prototype.transform = function (transformString) {
    if (!transformString.trim()) {
      return this;
    }
    this.__stack.push(transformParse(transformString));
    return this;
  };
  
  
  // Round coords with given decimal precition.
  // 0 by default (to integers)
  //
  SvgPath.prototype.round = function (d) {
    var contourStartDeltaX = 0, contourStartDeltaY = 0, deltaX = 0, deltaY = 0, l;
  
    d = d || 0;
  
    this.__evaluateStack();
  
    this.segments.forEach(function (s) {
      var isRelative = (s[0].toLowerCase() === s[0]);
  
      switch (s[0]) {
        case 'H':
        case 'h':
          if (isRelative) { s[1] += deltaX; }
          deltaX = s[1] - s[1].toFixed(d);
          s[1] = +s[1].toFixed(d);
          return;
  
        case 'V':
        case 'v':
          if (isRelative) { s[1] += deltaY; }
          deltaY = s[1] - s[1].toFixed(d);
          s[1] = +s[1].toFixed(d);
          return;
  
        case 'Z':
        case 'z':
          deltaX = contourStartDeltaX;
          deltaY = contourStartDeltaY;
          return;
  
        case 'M':
        case 'm':
          if (isRelative) {
            s[1] += deltaX;
            s[2] += deltaY;
          }
  
          deltaX = s[1] - s[1].toFixed(d);
          deltaY = s[2] - s[2].toFixed(d);
  
          contourStartDeltaX = deltaX;
          contourStartDeltaY = deltaY;
  
          s[1] = +s[1].toFixed(d);
          s[2] = +s[2].toFixed(d);
          return;
  
        case 'A':
        case 'a':
          // [cmd, rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
          if (isRelative) {
            s[6] += deltaX;
            s[7] += deltaY;
          }
  
          deltaX = s[6] - s[6].toFixed(d);
          deltaY = s[7] - s[7].toFixed(d);
  
          s[1] = +s[1].toFixed(d);
          s[2] = +s[2].toFixed(d);
          s[3] = +s[3].toFixed(d + 2); // better precision for rotation
          s[6] = +s[6].toFixed(d);
          s[7] = +s[7].toFixed(d);
          return;
  
        default:
          // a c l q s t
          l = s.length;
  
          if (isRelative) {
            s[l - 2] += deltaX;
            s[l - 1] += deltaY;
          }
  
          deltaX = s[l - 2] - s[l - 2].toFixed(d);
          deltaY = s[l - 1] - s[l - 1].toFixed(d);
  
          s.forEach(function (val, i) {
            if (!i) { return; }
            s[i] = +s[i].toFixed(d);
          });
          return;
      }
    });
  
    return this;
  };
  
  
  // Apply iterator function to all segments. If function returns result,
  // current segment will be replaced to array of returned segments.
  // If empty array is returned, current regment will be deleted.
  //
  SvgPath.prototype.iterate = function (iterator, keepLazyStack) {
    var segments = this.segments,
        replacements = {},
        needReplace = false,
        lastX = 0,
        lastY = 0,
        countourStartX = 0,
        countourStartY = 0;
    var i, j, newSegments;
  
    if (!keepLazyStack) {
      this.__evaluateStack();
    }
  
    segments.forEach(function (s, index) {
  
      var res = iterator(s, index, lastX, lastY);
  
      if (Array.isArray(res)) {
        replacements[index] = res;
        needReplace = true;
      }
  
      var isRelative = (s[0] === s[0].toLowerCase());
  
      // calculate absolute X and Y
      switch (s[0]) {
        case 'm':
        case 'M':
          lastX = s[1] + (isRelative ? lastX : 0);
          lastY = s[2] + (isRelative ? lastY : 0);
          countourStartX = lastX;
          countourStartY = lastY;
          return;
  
        case 'h':
        case 'H':
          lastX = s[1] + (isRelative ? lastX : 0);
          return;
  
        case 'v':
        case 'V':
          lastY = s[1] + (isRelative ? lastY : 0);
          return;
  
        case 'z':
        case 'Z':
          // That make sence for multiple contours
          lastX = countourStartX;
          lastY = countourStartY;
          return;
  
        default:
          lastX = s[s.length - 2] + (isRelative ? lastX : 0);
          lastY = s[s.length - 1] + (isRelative ? lastY : 0);
      }
    });
  
    // Replace segments if iterator return results
  
    if (!needReplace) { return this; }
  
    newSegments = [];
  
    for (i = 0; i < segments.length; i++) {
      if (typeof replacements[i] !== 'undefined') {
        for (j = 0; j < replacements[i].length; j++) {
          newSegments.push(replacements[i][j]);
        }
      } else {
        newSegments.push(segments[i]);
      }
    }
  
    this.segments = newSegments;
  
    return this;
  };
  
  
  // Converts segments from relative to absolute
  //
  SvgPath.prototype.abs = function () {
  
    this.iterate(function (s, index, x, y) {
      var name = s[0],
          nameUC = name.toUpperCase(),
          i;
  
      // Skip absolute commands
      if (name === nameUC) { return; }
  
      s[0] = nameUC;
  
      switch (name) {
        case 'v':
          // v has shifted coords parity
          s[1] += y;
          return;
  
        case 'a':
          // ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
          // touch x, y only
          s[6] += x;
          s[7] += y;
          return;
  
        default:
          for (i = 1; i < s.length; i++) {
            s[i] += i % 2 ? x : y; // odd values are X, even - Y
          }
      }
    }, true);
  
    return this;
  };
  
  
  // Converts segments from absolute to relative
  //
  SvgPath.prototype.rel = function () {
  
    this.iterate(function (s, index, x, y) {
      var name = s[0],
          nameLC = name.toLowerCase(),
          i;
  
      // Skip relative commands
      if (name === nameLC) { return; }
  
      // Don't touch the first M to avoid potential confusions.
      if (index === 0 && name === 'M') { return; }
  
      s[0] = nameLC;
  
      switch (name) {
        case 'V':
          // V has shifted coords parity
          s[1] -= y;
          return;
  
        case 'A':
          // ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
          // touch x, y only
          s[6] -= x;
          s[7] -= y;
          return;
  
        default:
          for (i = 1; i < s.length; i++) {
            s[i] -= i % 2 ? x : y; // odd values are X, even - Y
          }
      }
    }, true);
  
    return this;
  };
  
  
  // Converts arcs to cubic bézier curves
  //
  SvgPath.prototype.unarc = function () {
    this.iterate(function (s, index, x, y) {
      var new_segments, nextX, nextY, result = [], name = s[0];
  
      // Skip anything except arcs
      if (name !== 'A' && name !== 'a') { return null; }
  
      if (name === 'a') {
        // convert relative arc coordinates to absolute
        nextX = x + s[6];
        nextY = y + s[7];
      } else {
        nextX = s[6];
        nextY = s[7];
      }
  
      new_segments = a2c(x, y, nextX, nextY, s[4], s[5], s[1], s[2], s[3]);
  
      // Degenerated arcs can be ignored by renderer, but should not be dropped
      // to avoid collisions with `S A S` and so on. Replace with empty line.
      if (new_segments.length === 0) {
        return [ [ s[0] === 'a' ? 'l' : 'L', s[6], s[7] ] ];
      }
  
      new_segments.forEach(function (s) {
        result.push([ 'C', s[2], s[3], s[4], s[5], s[6], s[7] ]);
      });
  
      return result;
    });
  
    return this;
  };
  
  
  // Converts smooth curves (with missed control point) to generic curves
  //
  SvgPath.prototype.unshort = function () {
    var segments = this.segments;
    var prevControlX, prevControlY, prevSegment;
    var curControlX, curControlY;
  
    // TODO: add lazy evaluation flag when relative commands supported
  
    this.iterate(function (s, idx, x, y) {
      var name = s[0], nameUC = name.toUpperCase(), isRelative;
  
      // First command MUST be M|m, it's safe to skip.
      // Protect from access to [-1] for sure.
      if (!idx) { return; }
  
      if (nameUC === 'T') { // quadratic curve
        isRelative = (name === 't');
  
        prevSegment = segments[idx - 1];
  
        if (prevSegment[0] === 'Q') {
          prevControlX = prevSegment[1] - x;
          prevControlY = prevSegment[2] - y;
        } else if (prevSegment[0] === 'q') {
          prevControlX = prevSegment[1] - prevSegment[3];
          prevControlY = prevSegment[2] - prevSegment[4];
        } else {
          prevControlX = 0;
          prevControlY = 0;
        }
  
        curControlX = -prevControlX;
        curControlY = -prevControlY;
  
        if (!isRelative) {
          curControlX += x;
          curControlY += y;
        }
  
        segments[idx] = [
          isRelative ? 'q' : 'Q',
          curControlX, curControlY,
          s[1], s[2]
        ];
  
      } else if (nameUC === 'S') { // cubic curve
        isRelative = (name === 's');
  
        prevSegment = segments[idx - 1];
  
        if (prevSegment[0] === 'C') {
          prevControlX = prevSegment[3] - x;
          prevControlY = prevSegment[4] - y;
        } else if (prevSegment[0] === 'c') {
          prevControlX = prevSegment[3] - prevSegment[5];
          prevControlY = prevSegment[4] - prevSegment[6];
        } else {
          prevControlX = 0;
          prevControlY = 0;
        }
  
        curControlX = -prevControlX;
        curControlY = -prevControlY;
  
        if (!isRelative) {
          curControlX += x;
          curControlY += y;
        }
  
        segments[idx] = [
          isRelative ? 'c' : 'C',
          curControlX, curControlY,
          s[1], s[2], s[3], s[4]
        ];
      }
    });
  
    return this;
  };
  
  
  module.exports = SvgPath;
  
  },{"./a2c":2,"./ellipse":3,"./matrix":4,"./path_parse":5,"./transform_parse":7}],7:[function(require,module,exports){
  'use strict';
  
  
  var Matrix = require('./matrix');
  
  var operations = {
    matrix: true,
    scale: true,
    rotate: true,
    translate: true,
    skewX: true,
    skewY: true
  };
  
  var CMD_SPLIT_RE    = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/;
  var PARAMS_SPLIT_RE = /[\s,]+/;
  
  
  module.exports = function transformParse(transformString) {
    var matrix = new Matrix();
    var cmd, params;
  
    // Split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate',  '-45', '']
    transformString.split(CMD_SPLIT_RE).forEach(function (item) {
  
      // Skip empty elements
      if (!item.length) { return; }
  
      // remember operation
      if (typeof operations[item] !== 'undefined') {
        cmd = item;
        return;
      }
  
      // extract params & att operation to matrix
      params = item.split(PARAMS_SPLIT_RE).map(function (i) {
        return +i || 0;
      });
  
      // If params count is not correct - ignore command
      switch (cmd) {
        case 'matrix':
          if (params.length === 6) {
            matrix.matrix(params);
          }
          return;
  
        case 'scale':
          if (params.length === 1) {
            matrix.scale(params[0], params[0]);
          } else if (params.length === 2) {
            matrix.scale(params[0], params[1]);
          }
          return;
  
        case 'rotate':
          if (params.length === 1) {
            matrix.rotate(params[0], 0, 0);
          } else if (params.length === 3) {
            matrix.rotate(params[0], params[1], params[2]);
          }
          return;
  
        case 'translate':
          if (params.length === 1) {
            matrix.translate(params[0], 0);
          } else if (params.length === 2) {
            matrix.translate(params[0], params[1]);
          }
          return;
  
        case 'skewX':
          if (params.length === 1) {
            matrix.skewX(params[0]);
          }
          return;
  
        case 'skewY':
          if (params.length === 1) {
            matrix.skewY(params[0]);
          }
          return;
      }
    });
  
    return matrix;
  };
  
  },{"./matrix":4}],8:[function(require,module,exports){
  /**
   * A class to parse color values
   * @author Stoyan Stefanov <sstoo@gmail.com>
   * @link   http://www.phpied.com/rgb-color-parser-in-javascript/
   * @license Use it if you like it
   */
  (function (global) {
  function RGBColor(color_string)
  {
    this.ok = false;
  
    // strip any leading #
    if (color_string.charAt(0) == '#') { // remove # if any
      color_string = color_string.substr(1,6);
    }
  
    color_string = color_string.replace(/ /g,'');
    color_string = color_string.toLowerCase();
  
    // before getting into regexps, try simple matches
    // and overwrite the input
    var simple_colors = {
      aliceblue: 'f0f8ff',
      antiquewhite: 'faebd7',
      aqua: '00ffff',
      aquamarine: '7fffd4',
      azure: 'f0ffff',
      beige: 'f5f5dc',
      bisque: 'ffe4c4',
      black: '000000',
      blanchedalmond: 'ffebcd',
      blue: '0000ff',
      blueviolet: '8a2be2',
      brown: 'a52a2a',
      burlywood: 'deb887',
      cadetblue: '5f9ea0',
      chartreuse: '7fff00',
      chocolate: 'd2691e',
      coral: 'ff7f50',
      cornflowerblue: '6495ed',
      cornsilk: 'fff8dc',
      crimson: 'dc143c',
      cyan: '00ffff',
      darkblue: '00008b',
      darkcyan: '008b8b',
      darkgoldenrod: 'b8860b',
      darkgray: 'a9a9a9',
      darkgreen: '006400',
      darkkhaki: 'bdb76b',
      darkmagenta: '8b008b',
      darkolivegreen: '556b2f',
      darkorange: 'ff8c00',
      darkorchid: '9932cc',
      darkred: '8b0000',
      darksalmon: 'e9967a',
      darkseagreen: '8fbc8f',
      darkslateblue: '483d8b',
      darkslategray: '2f4f4f',
      darkturquoise: '00ced1',
      darkviolet: '9400d3',
      deeppink: 'ff1493',
      deepskyblue: '00bfff',
      dimgray: '696969',
      dodgerblue: '1e90ff',
      feldspar: 'd19275',
      firebrick: 'b22222',
      floralwhite: 'fffaf0',
      forestgreen: '228b22',
      fuchsia: 'ff00ff',
      gainsboro: 'dcdcdc',
      ghostwhite: 'f8f8ff',
      gold: 'ffd700',
      goldenrod: 'daa520',
      gray: '808080',
      green: '008000',
      greenyellow: 'adff2f',
      honeydew: 'f0fff0',
      hotpink: 'ff69b4',
      indianred : 'cd5c5c',
      indigo : '4b0082',
      ivory: 'fffff0',
      khaki: 'f0e68c',
      lavender: 'e6e6fa',
      lavenderblush: 'fff0f5',
      lawngreen: '7cfc00',
      lemonchiffon: 'fffacd',
      lightblue: 'add8e6',
      lightcoral: 'f08080',
      lightcyan: 'e0ffff',
      lightgoldenrodyellow: 'fafad2',
      lightgrey: 'd3d3d3',
      lightgreen: '90ee90',
      lightpink: 'ffb6c1',
      lightsalmon: 'ffa07a',
      lightseagreen: '20b2aa',
      lightskyblue: '87cefa',
      lightslateblue: '8470ff',
      lightslategray: '778899',
      lightsteelblue: 'b0c4de',
      lightyellow: 'ffffe0',
      lime: '00ff00',
      limegreen: '32cd32',
      linen: 'faf0e6',
      magenta: 'ff00ff',
      maroon: '800000',
      mediumaquamarine: '66cdaa',
      mediumblue: '0000cd',
      mediumorchid: 'ba55d3',
      mediumpurple: '9370d8',
      mediumseagreen: '3cb371',
      mediumslateblue: '7b68ee',
      mediumspringgreen: '00fa9a',
      mediumturquoise: '48d1cc',
      mediumvioletred: 'c71585',
      midnightblue: '191970',
      mintcream: 'f5fffa',
      mistyrose: 'ffe4e1',
      moccasin: 'ffe4b5',
      navajowhite: 'ffdead',
      navy: '000080',
      oldlace: 'fdf5e6',
      olive: '808000',
      olivedrab: '6b8e23',
      orange: 'ffa500',
      orangered: 'ff4500',
      orchid: 'da70d6',
      palegoldenrod: 'eee8aa',
      palegreen: '98fb98',
      paleturquoise: 'afeeee',
      palevioletred: 'd87093',
      papayawhip: 'ffefd5',
      peachpuff: 'ffdab9',
      peru: 'cd853f',
      pink: 'ffc0cb',
      plum: 'dda0dd',
      powderblue: 'b0e0e6',
      purple: '800080',
      red: 'ff0000',
      rosybrown: 'bc8f8f',
      royalblue: '4169e1',
      saddlebrown: '8b4513',
      salmon: 'fa8072',
      sandybrown: 'f4a460',
      seagreen: '2e8b57',
      seashell: 'fff5ee',
      sienna: 'a0522d',
      silver: 'c0c0c0',
      skyblue: '87ceeb',
      slateblue: '6a5acd',
      slategray: '708090',
      snow: 'fffafa',
      springgreen: '00ff7f',
      steelblue: '4682b4',
      tan: 'd2b48c',
      teal: '008080',
      thistle: 'd8bfd8',
      tomato: 'ff6347',
      turquoise: '40e0d0',
      violet: 'ee82ee',
      violetred: 'd02090',
      wheat: 'f5deb3',
      white: 'ffffff',
      whitesmoke: 'f5f5f5',
      yellow: 'ffff00',
      yellowgreen: '9acd32'
    };
    for (var key in simple_colors) {
      if (color_string == key) {
        color_string = simple_colors[key];
      }
    }
    // emd of simple type-in colors
  
    // array of color definition objects
    var color_defs = [
      {
        re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
        example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
        process: function (bits){
          return [
            parseInt(bits[1]),
            parseInt(bits[2]),
            parseInt(bits[3])
          ];
        }
      },
      {
        re: /^(\w{2})(\w{2})(\w{2})$/,
        example: ['#00ff00', '336699'],
        process: function (bits){
          return [
            parseInt(bits[1], 16),
            parseInt(bits[2], 16),
            parseInt(bits[3], 16)
          ];
        }
      },
      {
        re: /^(\w{1})(\w{1})(\w{1})$/,
        example: ['#fb0', 'f0f'],
        process: function (bits){
          return [
            parseInt(bits[1] + bits[1], 16),
            parseInt(bits[2] + bits[2], 16),
            parseInt(bits[3] + bits[3], 16)
          ];
        }
      }
    ];
  
    // search through the definitions to find a match
    for (var i = 0; i < color_defs.length; i++) {
      var re = color_defs[i].re;
      var processor = color_defs[i].process;
      var bits = re.exec(color_string);
      if (bits) {
        var channels = processor(bits);
        this.r = channels[0];
        this.g = channels[1];
        this.b = channels[2];
        this.ok = true;
      }
  
    }
  
    // validate/cleanup values
    this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
    this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
    this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
  
    // some getters
    this.toRGB = function () {
      return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
    }
    this.toHex = function () {
      var r = this.r.toString(16);
      var g = this.g.toString(16);
      var b = this.b.toString(16);
      if (r.length == 1) r = '0' + r;
      if (g.length == 1) g = '0' + g;
      if (b.length == 1) b = '0' + b;
      return '#' + r + g + b;
    }
  
    // help
    this.getHelpXML = function () {
  
      var examples = new Array();
      // add regexps
      for (var i = 0; i < color_defs.length; i++) {
        var example = color_defs[i].example;
        for (var j = 0; j < example.length; j++) {
          examples[examples.length] = example[j];
        }
      }
      // add type-in colors
      for (var sc in simple_colors) {
        examples[examples.length] = sc;
      }
  
      var xml = document.createElement('ul');
      xml.setAttribute('id', 'rgbcolor-examples');
      for (var i = 0; i < examples.length; i++) {
        try {
          var list_item = document.createElement('li');
          var list_color = new RGBColor(examples[i]);
          var example_div = document.createElement('div');
          example_div.style.cssText =
              'margin: 3px; '
              + 'border: 1px solid black; '
              + 'background:' + list_color.toHex() + '; '
              + 'color:' + list_color.toHex()
          ;
          example_div.appendChild(document.createTextNode('test'));
          var list_item_value = document.createTextNode(
              ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex()
          );
          list_item.appendChild(example_div);
          list_item.appendChild(list_item_value);
          xml.appendChild(list_item);
  
        } catch(e){}
      }
      return xml;
  
    }
  
  }
  if (typeof define === "function" && define.amd) {
    define(function () {
      return RGBColor;
    });
  } else if (typeof module !== "undefined" && module.exports) {
    module.exports = RGBColor;
  } else {
    global.RGBColor = RGBColor;
  }
  return RGBColor;
  })(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this);
  
  },{}],9:[function(require,module,exports){
  /*
  The MIT License (MIT)
  
  Copyright (c) 2015-2016 yWorks GmbH
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
  */
  
  /**
   * Renders an svg element to a jsPDF document.
   * For accurate results a DOM document is required (mainly used for text size measurement and image format conversion)
   * @param element {HTMLElement} The svg element, which will be cloned, so the original stays unchanged.
   * @param pdf {jsPDF} The jsPDF object.
   * @param options {object} An object that may contain render options. Currently supported are:
   *                         scale: The global factor by which everything is scaled.
   *                         xOffset, yOffset: Offsets that are added to every coordinate AFTER scaling (They are not
   *                            influenced by the scale attribute).
   */
  (function (global) {
    var RGBColor;
    var SvgPath;
  
    var _pdf; // jsPDF pdf-document
  
    var cToQ = 2 / 3; // ratio to convert quadratic bezier curves to cubic ones
  
    var iriReference = /url\(#([^)]+)\)/;
  
  
    // pathSegList is marked deprecated in chrome, so parse the d attribute manually if necessary
    var getPathSegList = function (node) {
      var d = node.getAttribute("d");
  
      // Replace arcs before path segment list is handled
      if (SvgPath) {
        d = SvgPath(d).unshort().unarc().abs().toString();
        node.setAttribute('d', d);
      }
  
      var pathSegList = node.pathSegList;
      
      if (pathSegList) {
        return pathSegList;
      }
  
      pathSegList = [];
  
      var regex = /([a-df-zA-DF-Z])([^a-df-zA-DF-Z]*)/g,
          match;
      while (match = regex.exec(d)) {
        var coords = parseFloats(match[2]);
  
        var type = match[1];
        var length = "zZ".indexOf(type) >= 0 ? 0 :
            "hHvV".indexOf(type) >= 0  ? 1 :
            "mMlLtT".indexOf(type) >= 0  ? 2 :
            "sSqQ".indexOf(type) >= 0  ? 4 :
            "aA".indexOf(type) >= 0  ? 7 :
            "cC".indexOf(type) >= 0  ? 6 : -1;
  
        var i = 0;
        do {
          var pathSeg = {pathSegTypeAsLetter: type};
          switch (type) {
            case "h":
            case "H":
              pathSeg.x = coords[i];
              break;
  
            case "v":
            case "V":
              pathSeg.y = coords[i];
              break;
  
            case "c":
            case "C":
              pathSeg.x1 = coords[i + length - 6];
              pathSeg.y1 = coords[i + length - 5];
            case "s":
            case "S":
              pathSeg.x2 = coords[i + length - 4];
              pathSeg.y2 = coords[i + length - 3];
            case "t":
            case "T":
            case "l":
            case "L":
            case "m":
            case "M":
              pathSeg.x = coords[i + length - 2];
              pathSeg.y = coords[i + length - 1];
              break;
  
            case "q":
            case "Q":
              pathSeg.x1 = coords[i];
              pathSeg.y1 = coords[i + 1];
              pathSeg.x = coords[i + 2];
              pathSeg.y = coords[i + 3];
              break;
            case "a":
            case "A":
              throw new Error("Cannot convert Arcs without SvgPath package");
          }
  
          pathSegList.push(pathSeg);
  
          // "If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit
          // lineto commands"
          if (type === "m") {
            type = "l";
          } else if (type === "M") {
            type = "L";
          }
  
          i += length;
        } while(i < coords.length);
      }
  
      pathSegList.getItem = function (i) {
        return this[i]
      };
      pathSegList.numberOfItems = pathSegList.length;
  
      return pathSegList;
    };
  
    // returns an attribute of a node, either from the node directly or from css
    var getAttribute = function (node, propertyNode, propertyCss) {
      propertyCss = propertyCss || propertyNode;
      return node.getAttribute(propertyNode) || node.style[propertyCss];
    };
  
    var nodeIs = function (node, tagsString) {
      return tagsString.split(",").indexOf(node.tagName.toLowerCase()) >= 0;
    };
  
    var forEachChild = function (node, fn) {
      // copy list of children, as the original might be modified
      var children = [];
      for (var i = 0; i < node.childNodes.length; i++) {
        var childNode = node.childNodes[i];
        if (childNode.nodeName.charAt(0) !== "#")
          children.push(childNode);
      }
      for (i = 0; i < children.length; i++) {
        fn(i, children[i]);
      }
    };
  
    var getAngle = function (from, to) {
      return Math.atan2(to[1] - from[1], to[0] - from[0]);
    };
  
    function normalize(v) {
      var length = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
      return [v[0] / length, v[1] / length];
    }
  
    function getDirectionVector(from, to) {
      var v = [to[0] - from[0], to[1] - from[1]];
      return normalize(v);
    }
  
    function addVectors(v1, v2) {
      return [v1[0] + v2[0], v1[1] + v2[1]];
    }
  
    // mirrors p1 at p2
    var mirrorPoint = function (p1, p2) {
      var dx = p2[0] - p1[0];
      var dy = p2[1] - p1[1];
  
      return [p1[0] + 2 * dx, p1[1] + 2 * dy];
    };
  
    // transforms a cubic bezier control point to a quadratic one: returns from + (2/3) * (to - from)
    var toCubic = function (from, to) {
      return [cToQ * (to[0] - from[0]) + from[0], cToQ * (to[1] - from[1]) + from[1]];
    };
  
    // extracts a control point from a previous path segment (for t,T,s,S segments)
    var getControlPointFromPrevious = function (i, from, list, prevX, prevY) {
      var prev = list.getItem(i - 1);
      var p2;
      if (i > 0 && (prev.pathSegTypeAsLetter === "C" || prev.pathSegTypeAsLetter === "S")) {
        p2 = mirrorPoint([prev.x2, prev.y2], from);
      } else if (i > 0 && (prev.pathSegTypeAsLetter === "c" || prev.pathSegTypeAsLetter === "s")) {
        p2 = mirrorPoint([prev.x2 + prevX, prev.y2 + prevY], from);
      } else {
        p2 = [from[0], from[1]];
      }
      return p2;
    };
  
    // an id prefix to handle duplicate ids
    var SvgPrefix = function (prefix) {
      this.prefix = prefix;
      this.id = 0;
      this.nextChild = function () {
        return new SvgPrefix("_" + this.id++ + "_" + this.get());
      };
      this.get = function () {
        return this.prefix;
      }
    };
  
    var AttributeState = function () {
      this.fillMode = "F";
      this.strokeMode = "";
  
      this.color = new RGBColor("rgb(0, 0, 0)");
      this.fill = new RGBColor("rgb(0, 0, 0)");
      this.fillOpacity = 1.0;
      // this.fillRule = "nonzero";
      this.fontFamily = "times";
      this.fontSize = 16;
      // this.fontStyle = "normal";
      // this.fontVariant = "normal";
      // this.fontWeight = "normal";
      this.opacity = 1.0;
      this.stroke = null;
      this.strokeDasharray = null;
      this.strokeDashoffset = null;
      this.strokeLinecap = "butt";
      this.strokeLinejoin = "miter";
      this.strokeMiterlimit = 4.0;
      this.strokeOpacity = 1.0;
      this.strokeWidth = 1.0;
      // this.textAlign = "start";
      this.textAnchor = "start";
      this.visibility = "visible";
    };
  
    AttributeState.prototype.clone = function () {
      var clone = new AttributeState();
      Object.getOwnPropertyNames(this).forEach(function (name) {
        clone[name] = this[name];
      }, this);
      return clone;
    };
  
    /**
     * @constructor
     * @property {Marker[]} markers
     */
    function MarkerList() {
      this.markers = [];
    }
  
    /**
     * @param {Marker} marker
     */
    MarkerList.prototype.addMarker = function addMarker(marker) {
      this.markers.push(marker);
    };
  
    MarkerList.prototype.draw = function (tfMatrix, attributeState) {
      for (var i = 0; i < this.markers.length; i++) {
        var marker = this.markers[i];
  
        var tf;
        var angle = marker.angle, anchor = marker.anchor;
        var cos = Math.cos(angle);
        var sin = Math.sin(angle);
        // position at and rotate around anchor
        tf = new _pdf.Matrix(cos, sin, -sin, cos, anchor[0], anchor[1]);
        // scale with stroke-width
        tf = _pdf.matrixMult(new _pdf.Matrix(attributeState.strokeWidth, 0, 0, attributeState.strokeWidth, 0, 0), tf);
  
        tf = _pdf.matrixMult(tf, tfMatrix);
  
        // as the marker is already scaled by the current line width we must not apply the line width twice!
        _pdf.saveGraphicsState();
        _pdf.setLineWidth(1.0);
        _pdf.doFormObject(marker.id, tf);
        _pdf.restoreGraphicsState();
      }
    };
  
    /**
     * @param {string} id
     * @param {[number,number]} anchor
     * @param {number} angle
     */
    function Marker(id, anchor, angle) {
      this.id = id;
      this.anchor = anchor;
      this.angle = angle;
    }
  
    // returns the node for the specified id or incrementally removes prefixes to search "higher" levels
    var getFromDefs = function (id, defs) {
      var regExp = /_\d+_/;
      while (!defs[id] && regExp.exec(id)) {
        id = id.replace(regExp, "");
      }
      return defs[id];
    };
  
    // replace any newline characters by space and trim
    var removeNewlinesAndTrim = function (str) {
      return str.replace(/[\n\s\r]+/, " ").trim();
    };
  
    // clones the defs object (or basically any object)
    var cloneDefs = function (defs) {
      var clone = {};
      for (var key in defs) {
        if (defs.hasOwnProperty(key)) {
          clone[key] = defs[key];
        }
      }
      return clone;
    };
  
    function computeViewBoxTransform(node, bounds, eX, eY, eWidth, eHeight) {
      var vbX = bounds[0];
      var vbY = bounds[1];
      var vbWidth = bounds[2];
      var vbHeight = bounds[3];
  
      var scaleX = eWidth / vbWidth;
      var scaleY = eHeight / vbHeight;
  
      var align, meetOrSlice;
      var preserveAspectRatio = node.getAttribute("preserveAspectRatio");
      if (preserveAspectRatio) {
        var alignAndMeetOrSlice = preserveAspectRatio.split(" ");
        align = alignAndMeetOrSlice[0];
        meetOrSlice = alignAndMeetOrSlice[1] || "meet";
      } else {
        align = "xMidYMid";
        meetOrSlice = "meet"
      }
  
      if (align !== "none") {
        if (meetOrSlice === "meet") {
          // uniform scaling with min scale
          scaleX = scaleY = Math.min(scaleX, scaleY);
        } else if (meetOrSlice === "slice") {
          // uniform scaling with max scale
          scaleX = scaleY = Math.max(scaleX, scaleY);
        }
      }
  
      var translateX = eX - (vbX * scaleX);
      var translateY = eY - (vbY * scaleY);
  
      if (align.indexOf("xMid") >= 0) {
        translateX += (eWidth - vbWidth * scaleX) / 2;
      } else if (align.indexOf("xMax") >= 0) {
        translateX += eWidth - vbWidth * scaleX;
      }
  
      if (align.indexOf("yMid") >= 0) {
        translateY += (eHeight - vbHeight * scaleY) / 2;
      } else if (align.indexOf("yMax") >= 0) {
        translateY += (eHeight - vbHeight * scaleY);
      }
  
      var translate = new _pdf.Matrix(1, 0, 0, 1, translateX, translateY);
      var scale = new _pdf.Matrix(scaleX, 0, 0, scaleY, 0, 0);
  
      return _pdf.matrixMult(scale, translate);
    }
  
    // computes the transform directly applied at the node (such as viewbox scaling and the "transform" atrribute)
    // x,y,cx,cy,r,... are omitted
    var computeNodeTransform = function (node) {
      var viewBox, x, y;
      var nodeTransform = _pdf.unitMatrix;
      if (nodeIs(node, "svg,g")) {
        x = parseFloat(node.getAttribute("x")) || 0;
        y = parseFloat(node.getAttribute("y")) || 0;
  
        viewBox = node.getAttribute("viewBox");
        if (viewBox) {
          var width = parseFloat(node.getAttribute("width"));
          var height = parseFloat(node.getAttribute("height"));
          nodeTransform = computeViewBoxTransform(node, parseFloats(viewBox), x, y, width, height)
        } else {
          nodeTransform = new _pdf.Matrix(1, 0, 0, 1, x, y);
        }
      } else if (nodeIs(node, "marker")) {
        x = parseFloat(node.getAttribute("refX")) || 0;
        y = parseFloat(node.getAttribute("refY")) || 0;
  
        viewBox = node.getAttribute("viewBox");
        if (viewBox) {
          var bounds = parseFloats(viewBox);
          bounds[0] = bounds[1] = 0; // for some reason vbX anc vbY seem to be ignored for markers
          nodeTransform = computeViewBoxTransform(node, bounds, 0, 0, node.getAttribute("markerWidth"), node.getAttribute("markerHeight"));
          nodeTransform = _pdf.matrixMult(new _pdf.Matrix(1, 0, 0, 1, -x, -y), nodeTransform);
        } else {
          nodeTransform = new _pdf.Matrix(1, 0, 0, 1, -x, -y);
        }
      }
  
      var transformString = node.getAttribute("transform");
      if (!transformString)
        return nodeTransform;
      else
        return _pdf.matrixMult(nodeTransform, parseTransform(transformString));
    };
  
    // parses the "points" string used by polygons and returns an array of points
    var parsePointsString = function (string) {
      var floats = parseFloats(string);
      var result = [];
      for (var i = 0; i < floats.length - 1; i += 2) {
        var x = floats[i];
        var y = floats[i + 1];
        result.push([x, y]);
      }
      return result;
    };
  
    // parses the "transform" string
    var parseTransform = function (transformString) {
      if (!transformString)
        return _pdf.unitMatrix;
  
      var mRegex = /^\s*matrix\(([^\)]+)\)\s*/,
          tRegex = /^\s*translate\(([^\)]+)\)\s*/,
          rRegex = /^\s*rotate\(([^\)]+)\)\s*/,
          sRegex = /^\s*scale\(([^\)]+)\)\s*/,
          sXRegex = /^\s*skewX\(([^\)]+)\)\s*/,
          sYRegex = /^\s*skewY\(([^\)]+)\)\s*/;
  
      var resultMatrix = _pdf.unitMatrix, m;
  
      while (transformString.length > 0) {
        var match = mRegex.exec(transformString);
        if (match) {
          m = parseFloats(match[1]);
          resultMatrix = _pdf.matrixMult(new _pdf.Matrix(m[0], m[1], m[2], m[3], m[4], m[5]), resultMatrix);
          transformString = transformString.substr(match[0].length);
        }
        match = rRegex.exec(transformString);
        if (match) {
          m = parseFloats(match[1]);
          var a = Math.PI * m[0] / 180;
          resultMatrix = _pdf.matrixMult(new _pdf.Matrix(Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0), resultMatrix);
          if (m[1] && m[2]) {
            var t1 = new _pdf.Matrix(1, 0, 0, 1, m[1], m[2]);
            var t2 = new _pdf.Matrix(1, 0, 0, 1, -m[1], -m[2]);
            resultMatrix = _pdf.matrixMult(t2, _pdf.matrixMult(resultMatrix, t1));
          }
          transformString = transformString.substr(match[0].length);
        }
        match = tRegex.exec(transformString);
        if (match) {
          m = parseFloats(match[1]);
          resultMatrix = _pdf.matrixMult(new _pdf.Matrix(1, 0, 0, 1, m[0], m[1] || 0), resultMatrix);
          transformString = transformString.substr(match[0].length);
        }
        match = sRegex.exec(transformString);
        if (match) {
          m = parseFloats(match[1]);
          if (!m[1])
            m[1] = m[0];
          resultMatrix = _pdf.matrixMult(new _pdf.Matrix(m[0], 0, 0, m[1], 0, 0), resultMatrix);
          transformString = transformString.substr(match[0].length);
        }
        match = sXRegex.exec(transformString);
        if (match) {
          m = parseFloat(match[1]);
          resultMatrix = _pdf.matrixMult(new _pdf.Matrix(1, 0, Math.tan(m), 1, 0, 0), resultMatrix);
          transformString = transformString.substr(match[0].length);
        }
        match = sYRegex.exec(transformString);
        if (match) {
          m = parseFloat(match[1]);
          resultMatrix = _pdf.matrixMult(new _pdf.Matrix(1, Math.tan(m), 0, 1, 0, 0), resultMatrix);
          transformString = transformString.substr(match[0].length);
        }
      }
      return resultMatrix;
    };
  
    // parses a comma, sign and/or whitespace separated string of floats and returns the single floats in an array
    var parseFloats = function (str) {
      var floats = [], match,
          regex = /[+-]?(?:(?:\d+\.?\d*)|(?:\d*\.?\d+))(?:[eE][+-]?\d+)?/g;
      while(match = regex.exec(str)) {
        floats.push(parseFloat(match[0]));
      }
      return floats;
    };
  
    // extends RGBColor by rgba colors as RGBColor is not capable of it
    var parseColor = function (colorString) {
      var match = /\s*rgba\(((?:[^,\)]*,){3}[^,\)]*)\)\s*/.exec(colorString);
      if (match) {
        var floats = parseFloats(match[1]);
        var color = new RGBColor("rgb(" + floats.slice(0,3).join(",") + ")");
        color.a = floats[3];
        return color;
      } else {
        return new RGBColor(colorString);
      }
    };
  
    // multiplies a vector with a matrix: vec' = vec * matrix
    var multVecMatrix = function (vec, matrix) {
      var x = vec[0];
      var y = vec[1];
      return [
        matrix.a * x + matrix.c * y + matrix.e,
        matrix.b * x + matrix.d * y + matrix.f
      ];
    };
  
    // returns the untransformed bounding box [x, y, width, height] of an svg element (quite expensive for path and polygon objects, as
    // the whole points/d-string has to be processed)
    var getUntransformedBBox = function (node) {
      if (getAttribute(node, "display") === "none") {
        return [0, 0, 0, 0];
      }
  
      var i, minX, minY, maxX, maxY, viewBox, vb, boundingBox;
      var pf = parseFloat;
  
      if (nodeIs(node, "polygon")) {
        var points = parsePointsString(node.getAttribute("points"));
        minX = Number.POSITIVE_INFINITY;
        minY = Number.POSITIVE_INFINITY;
        maxX = Number.NEGATIVE_INFINITY;
        maxY = Number.NEGATIVE_INFINITY;
        for (i = 0; i < points.length; i++) {
          var point = points[i];
          minX = Math.min(minX, point[0]);
          maxX = Math.max(maxX, point[0]);
          minY = Math.min(minY, point[1]);
          maxY = Math.max(maxY, point[1]);
        }
        boundingBox = [
          minX,
          minY,
          maxX - minX,
          maxY - minY
        ];
      } else if (nodeIs(node, "path")) {
        var list = getPathSegList(node);
        minX = Number.POSITIVE_INFINITY;
        minY = Number.POSITIVE_INFINITY;
        maxX = Number.NEGATIVE_INFINITY;
        maxY = Number.NEGATIVE_INFINITY;
        var x = 0, y = 0;
        var prevX, prevY, newX, newY;
        var p2, p3, to;
        for (i = 0; i < list.numberOfItems; i++) {
          var seg = list.getItem(i);
          var cmd = seg.pathSegTypeAsLetter;
          switch (cmd) {
            case "H":
              newX = seg.x;
              newY = y;
              break;
            case "h":
              newX = seg.x + x;
              newY = y;
              break;
            case "V":
              newX = x;
              newY = seg.y;
              break;
            case "v":
              newX = x;
              newY = seg.y + y;
              break;
            case "C":
              p2 = [seg.x1, seg.y1];
              p3 = [seg.x2, seg.y2];
              to = [seg.x, seg.y];
              break;
            case "c":
              p2 = [seg.x1 + x, seg.y1 + y];
              p3 = [seg.x2 + x, seg.y2 + y];
              to = [seg.x + x, seg.y + y];
              break;
            case "S":
              p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
              p3 = [seg.x2, seg.y2];
              to = [seg.x, seg.y];
              break;
            case "s":
              p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
              p3 = [seg.x2 + x, seg.y2 + y];
              to = [seg.x + x, seg.y + y];
              break;
            case "Q":
              pf = [seg.x1, seg.y1];
              p2 = toCubic([x, y], pf);
              p3 = toCubic([seg.x, seg.y], pf);
              to = [seg.x, seg.y];
              break;
            case "q":
              pf = [seg.x1 + x, seg.y1 + y];
              p2 = toCubic([x, y], pf);
              p3 = toCubic([x + seg.x, y + seg.y], pf);
              to = [seg.x + x, seg.y + y];
              break;
            case "T":
              p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
              p2 = toCubic([x, y], pf);
              p3 = toCubic([seg.x, seg.y], pf);
              to = [seg.x, seg.y];
              break;
            case "t":
              pf = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
              p2 = toCubic([x, y], pf);
              p3 = toCubic([x + seg.x, y + seg.y], pf);
              to = [seg.x + x, seg.y + y];
              break;
            // TODO: A,a
          }
          if ("sScCqQtT".indexOf(cmd) >= 0) {
            prevX = x;
            prevY = y;
          }
          if ("MLCSQT".indexOf(cmd) >= 0) {
            x = seg.x;
            y = seg.y;
          } else if ("mlcsqt".indexOf(cmd) >= 0) {
            x = seg.x + x;
            y = seg.y + y;
          } else if ("zZ".indexOf(cmd) < 0) {
            x = newX;
            y = newY;
          }
          if ("CSQTcsqt".indexOf(cmd) >= 0) {
            minX = Math.min(minX, x, p2[0], p3[0], to[0]);
            maxX = Math.max(maxX, x, p2[0], p3[0], to[0]);
            minY = Math.min(minY, y, p2[1], p3[1], to[1]);
            maxY = Math.max(maxY, y, p2[1], p3[1], to[1]);
          } else {
            minX = Math.min(minX, x);
            maxX = Math.max(maxX, x);
            minY = Math.min(minY, y);
            maxY = Math.max(maxY, y);
          }
        }
        boundingBox = [
          minX,
          minY,
          maxX - minX,
          maxY - minY
        ];
      } else if (nodeIs(node, "svg")) {
        viewBox = node.getAttribute("viewBox");
        if (viewBox) {
          vb = parseFloats(viewBox);
        }
        return [
          pf(node.getAttribute("x")) || (vb && vb[0]) || 0,
          pf(node.getAttribute("y")) || (vb && vb[1]) || 0,
          pf(node.getAttribute("width")) || (vb && vb[2]) || 0,
          pf(node.getAttribute("height")) || (vb && vb[3]) || 0
        ];
      } else if (nodeIs(node, "g")) {
        boundingBox = [0, 0, 0, 0];
        forEachChild(node, function (i, node) {
          var nodeBox = getUntransformedBBox(node);
          boundingBox = [
              Math.min(boundingBox[0], nodeBox[0]),
              Math.min(boundingBox[1], nodeBox[1]),
              Math.max(boundingBox[0] + boundingBox[2], nodeBox[0] + nodeBox[2]) - Math.min(boundingBox[0], nodeBox[0]),
              Math.max(boundingBox[1] + boundingBox[3], nodeBox[1] + nodeBox[3]) - Math.min(boundingBox[1], nodeBox[1])
          ];
        });
      } else if (nodeIs(node, "marker")) {
        viewBox = node.getAttribute("viewBox");
        if (viewBox) {
          vb = parseFloats(viewBox);
        }
        return [
          (vb && vb[0]) || 0,
          (vb && vb[1]) || 0,
          (vb && vb[2]) || pf(node.getAttribute("marker-width")) || 0,
          (vb && vb[3]) || pf(node.getAttribute("marker-height")) || 0
        ];
      } else if (nodeIs(node, "pattern")) {
        return [
            pf(node.getAttribute("x")) || 0,
            pf(node.getAttribute("y")) || 0,
            pf(node.getAttribute("width")) || 0,
            pf(node.getAttribute("height")) || 0
        ]
      } else {
        // TODO: check if there are other possible coordinate attributes
        var x1 = pf(node.getAttribute("x1")) || pf(node.getAttribute("x")) || pf((node.getAttribute("cx")) - pf(node.getAttribute("r"))) || 0;
        var x2 = pf(node.getAttribute("x2")) || (x1 + pf(node.getAttribute("width"))) || (pf(node.getAttribute("cx")) + pf(node.getAttribute("r"))) || 0;
        var y1 = pf(node.getAttribute("y1")) || pf(node.getAttribute("y")) || (pf(node.getAttribute("cy")) - pf(node.getAttribute("r"))) || 0;
        var y2 = pf(node.getAttribute("y2")) || (y1 + pf(node.getAttribute("height"))) || (pf(node.getAttribute("cy")) + pf(node.getAttribute("r"))) || 0;
        boundingBox = [
          Math.min(x1, x2),
          Math.min(y1, y2),
          Math.max(x1, x2) - Math.min(x1, x2),
          Math.max(y1, y2) - Math.min(y1, y2)
        ];
      }
  
      if (!nodeIs(node, "marker,svg,g")) {
        // add line-width
        var lineWidth = getAttribute(node, "stroke-width") || 1;
        var miterLimit = getAttribute(node, "stroke-miterlimit");
        // miterLength / lineWidth = 1 / sin(phi / 2)
        miterLimit && (lineWidth *= 0.5 / (Math.sin(Math.PI / 12)));
        return [
            boundingBox[0] - lineWidth,
            boundingBox[1] - lineWidth,
            boundingBox[2] + 2 * lineWidth,
            boundingBox[3] + 2 * lineWidth
        ];
      }
  
      return boundingBox;
    };
  
    // transforms a bounding box and returns a new rect that contains it
    var transformBBox = function (box, matrix) {
      var bl = multVecMatrix([box[0], box[1]], matrix);
      var br = multVecMatrix([box[0] + box[2], box[1]], matrix);
      var tl = multVecMatrix([box[0], box[1] + box[3]], matrix);
      var tr = multVecMatrix([box[0] + box[2], box[1] + box[3]], matrix);
  
      var bottom = Math.min(bl[1], br[1], tl[1], tr[1]);
      var left = Math.min(bl[0], br[0], tl[0], tr[0]);
      var top = Math.max(bl[1], br[1], tl[1], tr[1]);
      var right = Math.max(bl[0], br[0], tl[0], tr[0]);
  
      return [
        left,
        bottom,
        right - left,
        top - bottom
      ]
    };
  
    // draws a polygon
    var polygon = function (node, tfMatrix, colorMode, gradient, gradientMatrix, svgIdPrefix, attributeState) {
      var points = parsePointsString(node.getAttribute("points"));
      var lines = [{op: "m", c: multVecMatrix(points[0], tfMatrix)}];
      var i, angle;
      for (i = 1; i < points.length; i++) {
        var p = points[i];
        var to = multVecMatrix(p, tfMatrix);
        lines.push({op: "l", c: to});
      }
      lines.push({op: "h"});
      _pdf.path(lines, colorMode, gradient, gradientMatrix);
  
      var markerEnd = node.getAttribute("marker-end"),
          markerStart = node.getAttribute("marker-start"),
          markerMid = node.getAttribute("marker-mid");
  
      if (markerStart || markerMid || markerEnd) {
        var length = lines.length;
        var markers = new MarkerList();
        if (markerStart) {
          markerStart = svgIdPrefix.get() + iriReference.exec(markerStart)[1];
          angle = addVectors(getDirectionVector(lines[0].c, lines[1].c), getDirectionVector(lines[length - 2].c, lines[0].c));
          markers.addMarker(new Marker(markerStart, lines[0].c, Math.atan2(angle[1], angle[0])));
        }
  
        if (markerMid) {
          markerMid = svgIdPrefix.get() + iriReference.exec(markerMid)[1];
          var prevAngle = getDirectionVector(lines[0].c, lines[1].c), curAngle;
          for (i = 1; i < lines.length - 2; i++) {
            curAngle = getDirectionVector(lines[i].c, lines[i + 1].c);
            angle = addVectors(prevAngle, curAngle);
            markers.addMarker(new Marker(markerMid, lines[i].c, Math.atan2(angle[1], angle[0])));
            prevAngle = curAngle;
          }
  
          curAngle = getDirectionVector(lines[length - 2].c, lines[0].c);
          angle = addVectors(prevAngle, curAngle);
          markers.addMarker(new Marker(markerMid, lines[length - 2].c, Math.atan2(angle[1], angle[0])));
        }
  
        if (markerEnd) {
          markerEnd = svgIdPrefix.get() + iriReference.exec(markerEnd)[1];
          angle = addVectors(getDirectionVector(lines[0].c, lines[1].c), getDirectionVector(lines[length - 2].c, lines[0].c));
          markers.addMarker(new Marker(markerEnd, lines[0].c, Math.atan2(angle[1], angle[0])));
        }
  
        m pf(node.getAttribute("x2")) || (x1 + pf(node.getAttribute("width"))) || (pf(node.getAttribute("cx")) + pf(node.getAttribute("r"))) || 0;
        var y1 = pf(node.getAttribute("y1")) || pf(node.getAttribute("y")) || (pf(node.getAttribute("cy")) - pf(node.getAttribute("r"))) || 0;
        var y2 = pf(node.getAttribute("y2")) || (y1 + pf(node.getAttribute("height"))) || (pf(node.getAttribute("cy")) + pf(node.getAttribute("r"))) || 0;
        boundingBox = [
          Math.min(x1, x2),
          Math.min(y1, y2),
          Math.max(x1, x2) - Math.min(x1, x2),
          Math.max(y1, y2) - Math.min(y1, y2)
        ];
      }
  
      if (!nodeIs(node, "marker,svg,g")) {
        // add line-width
        var lineWidth = getAttribute(node, "stroke-width") || 1;
        var miterLimit = getAttribute(node, "stroke-miterlimit");
        // miterLength / lineWidth = 1 / sin(phi / 2)
        miterLimit && (lineWidth *= 0.5 / (Math.sin(Math.PI / 12)));
        return [
            boundingBox[0] - lineWidth,
            boundingBox[1] - lineWidth,
            boundingBox[2] + 2 * lineWidth,
            boundingBox[3] + 2 * lineWidth
        ];
      }
  
      return boundingBox;
    };
  
    // transforms a bounding box and returns a new rect that contains it
    var transformBBox = function (box, matrix) {
      var bl = multVecMatrix([box[0], box[1]], matrix);
      var br = multVecMatrix([box[0] + box[2], box[1]], matrix);
      var tl = multVecMatrix([box[0], box[1] + box[3]], matrix);
      var tr = multVecMatrix([box[0] + box[2], box[1] + box[3]], matrix);
  
      var bottom = Math.min(bl[1], br[1], tl[1], tr[1]);
      var left = Math.min(bl[0], br[0], tl[0], tr[0]);
      var top = Math.max(bl[1], br[1], tl[1], tr[1]);
      var right = Math.max(bl[0], br[0], tl[0], tr[0]);
  
      return [
        left,
        bottom,
        right - left,
        top - bottom
      ]
    };
  
    // draws a polygon
    var polygon = function (node, tfMatrix, colorMode, gradient, gradientMatrix, svgIdPrefix, attributeState) {
      var points = parsePointsString(node.getAttribute("points"));
      var lines = [{op: "m", c: multVecMatrix(points[0], tfMatrix)}];
      var i, angle;
      for (i = 1; i < points.length; i++) {
        var p = points[i];
        var to = multVecMatrix(p, tfMatrix);
        lines.push({op: "l", c: to});
      }
      lines.push({op: "h"});
      _pdf.path(lines, colorMode, gradient, gradientMatrix);
  
      var markerEnd = node.getAttribute("marker-end"),
          markerStart = node.getAttribute("marker-start"),
          markerMid = node.getAttribute("marker-mid");
  
      if (markerStart || markerMid || markerEnd) {
        var length = lines.length;
        var markers = new MarkerList();
        if (markerStart) {
          markerStart = svgIdPrefix.get() + iriReference.exec(markerStart)[1];
          angle = addVectors(getDirectionVector(lines[0].c, lines[1].c), getDirectionVector(lines[length - 2].c, lines[0].c));
          markers.addMarker(new Marker(markerStart, lines[0].c, Math.atan2(angle[1], angle[0])));
        }
  
        if (markerMid) {
          markerMid = svgIdPrefix.get() + iriReference.exec(markerMid)[1];
          var prevAngle = getDirectionVector(lines[0].c, lines[1].c), curAngle;
          for (i = 1; i < lines.length - 2; i++) {
            curAngle = getDirectionVector(lines[i].c, lines[i + 1].c);
            angle = addVectors(prevAngle, curAngle);
            markers.addMarker(new Marker(markerMid, lines[i].c, Math.atan2(angle[1], angle[0])));
            prevAngle = curAngle;
          }
  
          curAngle = getDirectionVector(lines[length - 2].c, lines[0].c);
          angle = addVectors(prevAngle, curAngle);
          markers.addMarker(new Marker(markerMid, lines[length - 2].c, Math.atan2(angle[1], angle[0])));
        }
  
        if (markerEnd) {
          markerEnd = svgIdPrefix.get() + iriReference.exec(markerEnd)[1];
          angle = addVectors(getDirectionVector(lines[0].c, lines[1].c), getDirectionVector(lines[length - 2].c, lines[0].c));
          markers.addMarker(new Marker(markerEnd, lines[0].c, Math.atan2(angle[1], angle[0])));
        }
  
        markers.draw(_pdf.unitMatrix, attributeState);
      }
    };
  
    // draws an image (converts it to jpeg first, as jsPDF doesn't support png or other formats)
    var image = function (node) {
      // convert image to jpeg
      var imageUrl = node.getAttribute("xlink:href") || node.getAttribute("href");
      var image = new Image();
      image.src = imageUrl;
  
      var canvas = document.createElement("canvas");
      var width = parseFloat(node.getAttribute("width")),
          height = parseFloat(node.getAttribute("height")),
          x = parseFloat(node.getAttribute("x") || 0),
          y = parseFloat(node.getAttribute("y") || 0);
      canvas.width = width;
      canvas.height = height;
      var context = canvas.getContext("2d");
      context.fillStyle = "#fff";
      context.fillRect(0, 0, width, height);
      context.drawImage(image, 0, 0, width, height);
  
      try {
        var jpegUrl = canvas.toDataURL("image/jpeg");
  
        _pdf.addImage(jpegUrl,
            "jpeg",
            x,
            y,
            width,
            height
        );
      } catch (e) {
        (typeof console === "object"
            && console.warn
            && console.warn('svg2pdfjs: Images with external resource link are not supported! ("' + imageUrl + '")'));
      }
    };
  
    // draws a path
    var path = function (node, tfMatrix, svgIdPrefix, colorMode, gradient, gradientMatrix, attributeState) {
      var list = getPathSegList(node);
      var markerEnd = node.getAttribute("marker-end"),
          markerStart = node.getAttribute("marker-start"),
          markerMid = node.getAttribute("marker-mid");
  
      markerEnd && (markerEnd = svgIdPrefix.get() + iriReference.exec(markerEnd)[1]);
      markerStart && (markerStart = svgIdPrefix.get() + iriReference.exec(markerStart)[1]);
      markerMid && (markerMid = svgIdPrefix.get() + iriReference.exec(markerMid)[1]);
  
      var getLinesFromPath = function (pathSegList, tfMatrix) {
        var x = 0, y = 0;
        var x0 = x, y0 = y;
        var prevX, prevY, newX, newY;
        var to, p, p2, p3;
        var lines = [];
        var markers = new MarkerList();
        var op;
        var prevAngle = [0, 0], curAngle;
  
        for (var i = 0; i < list.numberOfItems; i++) {
          var seg = list.getItem(i);
          var cmd = seg.pathSegTypeAsLetter;
          switch (cmd) {
            case "M":
              x0 = x;
              y0 = y;
              to = [seg.x, seg.y];
              op = "m";
              break;
            case "m":
              x0 = x;
              y0 = y;
              to = [seg.x + x, seg.y + y];
              op = "m";
              break;
            case "L":
              to = [seg.x, seg.y];
              op = "l";
              break;
            case "l":
              to = [seg.x + x, seg.y + y];
              op = "l";
              break;
            case "H":
              to = [seg.x, y];
              op = "l";
              newX = seg.x;
              newY = y;
              break;
            case "h":
              to = [seg.x + x, y];
              op = "l";
              newX = seg.x + x;
              newY = y;
              break;
            case "V":
              to = [x, seg.y];
              op = "l";
              newX = x;
              newY = seg.y;
              break;
            case "v":
              to = [x, seg.y + y];
              op = "l";
              newX = x;
              newY = seg.y + y;
              break;
            case "C":
              p2 = [seg.x1, seg.y1];
              p3 = [seg.x2, seg.y2];
              to = [seg.x, seg.y];
              break;
            case "c":
              p2 = [seg.x1 + x, seg.y1 + y];
              p3 = [seg.x2 + x, seg.y2 + y];
              to = [seg.x + x, seg.y + y];
              break;
            case "S":
              p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
              p3 = [seg.x2, seg.y2];
              to = [seg.x, seg.y];
              break;
            case "s":
              p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
              p3 = [seg.x2 + x, seg.y2 + y];
              to = [seg.x + x, seg.y + y];
              break;
            case "Q":
              p = [seg.x1, seg.y1];
              p2 = toCubic([x, y], p);
              p3 = toCubic([seg.x, seg.y], p);
              to = [seg.x, seg.y];
              break;
            case "q":
              p = [seg.x1 + x, seg.y1 + y];
              p2 = toCubic([x, y], p);
              p3 = toCubic([x + seg.x, y + seg.y], p);
              to = [seg.x + x, seg.y + y];
              break;
            case "T":
              p2 = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
              p2 = toCubic([x, y], p);
              p3 = toCubic([seg.x, seg.y], p);
              to = [seg.x, seg.y];
              break;
            case "t":
              p = getControlPointFromPrevious(i, [x, y], list, prevX, prevY);
              p2 = toCubic([x, y], p);
              p3 = toCubic([x + seg.x, y + seg.y], p);
              to = [seg.x + x, seg.y + y];
              break;
            // TODO: A,a
            case "Z":
            case "z":
              x = x0;
              y = y0;
              lines.push({op: "h"});
              break;
          }
  
          var hasStartMarker = markerStart
              && (i === 1
              || ("mM".indexOf(cmd) < 0 && "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0));
          var hasEndMarker = markerEnd
              && (i === list.numberOfItems - 1
              || ("mM".indexOf(cmd) < 0 && "mM".indexOf(list.getItem(i + 1).pathSegTypeAsLetter) >= 0));
          var hasMidMarker = markerMid
              && i > 0
              && !(i === 1 && "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0);
  
          if ("sScCqQtT".indexOf(cmd) >= 0) {
            hasStartMarker && markers.addMarker(new Marker(markerStart, [x, y], getAngle([x, y], p2)));
            hasEndMarker && markers.addMarker(new Marker(markerEnd, to, getAngle(p3, to)));
            if (hasMidMarker) {
              curAngle = getDirectionVector([x, y], p2);
              curAngle = "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0 ?
                  curAngle : normalize(addVectors(prevAngle, curAngle));
              markers.addMarker(new Marker(markerMid, [x, y], Math.atan2(curAngle[1], curAngle[0])));
            }
  
            prevAngle = getDirectionVector(p3, to);
  
            prevX = x;
            prevY = y;
            p2 = multVecMatrix(p2, tfMatrix);
            p3 = multVecMatrix(p3, tfMatrix);
            p = multVecMatrix(to, tfMatrix);
            lines.push({
              op: "c", c: [
                p2[0], p2[1],
                p3[0], p3[1],
                p[0], p[1]
              ]
            });
          } else if ("lLhHvVmM".indexOf(cmd) >= 0) {
            curAngle = getDirectionVector([x, y], to);
            hasStartMarker && markers.addMarker(new Marker(markerStart, [x, y], Math.atan2(curAngle[1], curAngle[0])));
            hasEndMarker && markers.addMarker(new Marker(markerEnd, to, Math.atan2(curAngle[1], curAngle[0])));
            if (hasMidMarker) {
              var angle = "mM".indexOf(cmd) >= 0 ?
                  prevAngle : "mM".indexOf(list.getItem(i - 1).pathSegTypeAsLetter) >= 0 ?
                  curAngle : normalize(addVectors(prevAngle, curAngle));
              markers.addMarker(new Marker(markerMid, [x, y], Math.atan2(angle[1], angle[0])));
            }
            prevAngle = curAngle;
  
            p = multVecMatrix(to, tfMatrix);
            lines.push({op: op, c: p});
          }
  
          if ("MLCSQT".indexOf(cmd) >= 0) {
            x = seg.x;
            y = seg.y;
          } else if ("mlcsqt".indexOf(cmd) >= 0) {
            x = seg.x + x;
            y = seg.y + y;
          } else if ("zZ".indexOf(cmd) < 0) {
            x = newX;
            y = newY;
          }
        }
  
        return {lines: lines, markers: markers};
      };
      var lines = getLinesFromPath(list, tfMatrix);
  
      if (lines.lines.length > 0) {
        _pdf.path(lines.lines, colorMode, gradient, gradientMatrix);
      }
  
      if (markerEnd || markerStart || markerMid) {
        lines.markers.draw(tfMatrix, attributeState);
      }
    };
  
    // draws the element referencefset = width / 2;
            break;
          case 'start':
            break;
        }
        return xOffset;
      };
  
      /**
       * Convert em, px and bare number attributes to pixel values
       */
      var toPixels = function (value, pdfFontSize) {
        var match;
  
        // em
        match = value && value.toString().match(/^([\-0-9.]+)em$/);
        if (match) {
          return parseFloat(match[1]) * pdfFontSize;
        }
  
        // pixels
        match = value && value.toString().match(/^([\-0-9.]+)(px|)$/);
        if (match) {
          return parseFloat(match[1]);
        }
        return 0;
      };
  
      // creates an svg element and append the text node to properly measure the text size
      var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      svg.appendChild(node);
      svg.setAttribute("visibility", "hidden");
      document.body.appendChild(svg);
  
      var box = node.getBBox();
      var x, y, xOffset = 0;
      var textAnchor = getAttribute(node, "text-anchor");
      if (textAnchor) {
        xOffset = getTextOffset(textAnchor, box.width);
      }
  
      var pdfFontSize = _pdf.getFontSize();
      var textX = toPixels(node.getAttribute('x'), pdfFontSize);
      var textY = toPixels(node.getAttribute('y'), pdfFontSize);
      var m = _pdf.matrixMult(new _pdf.Matrix(1, 0, 0, 1, textX, textY), tfMatrix);
  
      x = toPixels(node.getAttribute("dx"), pdfFontSize);
      y = toPixels(node.getAttribute("dy"), pdfFontSize);
  
      var visibility = getAttribute(node, "visibility") || attributeState.visibility;
      // when there are no tspans draw the text directly
      if (node.childElementCount === 0) {
        if (visibility === "visible") {
          _pdf.text(
              (x - xOffset),
              y,
              transformText(node, removeNewlinesAndTrim(node.textContent)),
              void 0,
              m
          );
        }
      } else {
        // otherwise loop over tspans and position each relative to the previous one
        forEachChild(node, function (i, tSpan) {
          if (!tSpan.textContent || nodeIs(tSpan, 'title,desc,metadata')) {
            return;
          }
          _pdf.saveGraphicsState();
          var tSpanColor = getAttribute(tSpan, "fill");
          setTextProperties(tSpan, tSpanColor && new RGBColor(tSpanColor));
          var extent = tSpan.getExtentOfChar(0);
          var tSpanVisibility = getAttribute(tSpan, "visibility") || visibility;
          if (tSpanVisibility === "visible") {
            _pdf.text(
                extent.x - textX,//x - xOffset,
                extent.y + extent.height * 0.7 - textY, // 0.7 roughly mimicks the text baseline
                transformText(node, removeNewlinesAndTrim(tSpan.textContent)),
                void 0,
                m
            );
          }
  
          _pdf.restoreGraphicsState();
        });
  
      }
  
      document.body.removeChild(svg);
      _pdf.restoreGraphicsState();
    };
  
    // As defs elements are allowed to appear after they are referenced, we search for them first
    var findAndRenderDefs = function (node, tfMatrix, defs, svgIdPrefix, withinDefs, attributeState) {
      forEachChild(node, function (i, child) {
        if (child.tagName.toLowerCase() === "defs") {
          renderNode(child, tfMatrix, defs, svgIdPrefix, withinDefs, attributeState);
          // prevent defs from being evaluated twice // TODO: make this better
          child.parentNode.removeChild(child);
        }
      });
    };
  
    // processes a svg node
    var svg = function (node, tfMatrix, defs, svgIdPrefix, withinDefs, attributeState) {
      // create a new prefix and clone the defs, as defs within the svg should not be visible outside
      var newSvgIdPrefix = svgIdPrefix.nextChild();
      var newDefs = cloneDefs(defs);
      findAndRenderDefs(node, tfMatrix, newDefs, newSvgIdPrefix, withinDefs, attributeState);
      renderChildren(node, tfMatrix, newDefs, newSvgIdPrefix, withinDefs, attributeState);
    };
  
    // renders all children of a node
    var renderChildren = function (node, tfMatrix, defs, svgIdPrefix, withinDefs, attributeState) {
      forEachChild(node, function (i, node) {
        renderNode(node, tfMatrix, defs, svgIdPrefix, withinDefs, attributeState);
      });
    };
  
    // adds a gradient to defs and the pdf document for later use, type is either "axial" or "radial"
    // opacity is only supported rudimentary by averaging over all stops
    // transforms are applied on use
    var putGradient = function (node, type, coords, defs, svgIdPrefix) {
      var colors = [];
      var opacitySum = 0;
      var hasOpacity = false;
      var gState;
      forEachChild(node, function (i, element) {
        // since opacity gradients are hard to realize, average the opacity over the control points
        if (element.tagName.toLowerCase() === "stop") {
          var color = new RGBColor(getAttribute(element, "stop-color"));
          colors.push({
            offset: parseFloat(element.getAttribute("offset")),
            color: [color.r, color.g, color.b]
          });
          var opacity = getAttribute(element, "stop-opacity");
          if (opacity && opacity != 1) {
            opacitySum += parseFloat(opacity);
            hasOpacity = true;
          }
        }
      });
  
      if (hasOpacity) {
        gState = new _pdf.GState({opacity: opacitySum / coords.length});
      }
  
      var pattern = new _pdf.ShadingPattern(type, coords, colors, gState);
      var id = svgIdPrefix.get() + node.getAttribute("id");
      _pdf.addShadingPattern(id, pattern);
      defs[id] = node;
    };
  
    var pattern = function (node, defs, svgIdPrefix, attributeState) {
      var id = svgIdPrefix.get() + node.getAttribute("id");
      defs[id] = node;
  
      // the transformations directly at the node are written to the pattern transformation matrix
      var bBox = getUntransformedBBox(node);
      var pattern = new _pdf.TilingPattern([bBox[0], bBox[1], bBox[0] + bBox[2], bBox[1] + bBox[3]], bBox[2], bBox[3],
          null, computeNodeTransform(node));
  
      _pdf.beginTilingPattern(pattern);
      // continue without transformation
      renderChildren(node, _pdf.unitMatrix, defs, svgIdPrefix, false, attributeState);
      _pdf.endTilingPattern(id, pattern);
    };
  
    function setTextProperties(node, fillRGB) {
      var fontFamily = getAttribute(node, "font-family");
      if (fontFamily) {
        _pdf.setFont(fontFamily);
      }
  
      if (fillRGB && fillRGB.ok) {
        _pdf.setTextColor(fillRGB.r, fillRGB.g, fillRGB.b);
      }
  
      var fontType;
      var fontWeight = getAttribute(node, "font-weight");
      if (fontWeight) {
        if (fontWeight === "bold") {
          fontType = "bold";
        }
      }
  
      var fontStyle = getAttribute(node, "font-style");
      if (fontStyle) {
        if (fontStyle === "italic") {
          fontType += "italic";
        }
      }
      _pdf.setFontType(fontType);
  
      var pdfFontSize = 16;
      var fontSize = getAttribute(node, "font-size");
      if (fontSize) {
        pdfFontSize = parseFloat(fontSize);
        _pdf.setFontSize(pdfFontSize);
      }
    }
  
  
    /**
     * Renders a svg node.
     * @param node The svg element
     * @param contextTransform The current transformation matrix
     * @param defs The defs map holding all svg nodes that can be referenced
     * @param svgIdPrefix The current id prefix
     * @param withinDefs True iff we are top-level within a defs node, so the target can be switched to an pdf form object
     * @param {AttributeState} attributeState Keeps track of parent attributes that are inherited automatically
     */
    var renderNode = function (node, contextTransform, defs, svgIdPrefix, withinDefs, attributeState) {
      attributeState = attributeState.clone();
  
      if (getAttribute(node, "display") === "none") {
        return;
      }
  
      var visibility = attributeState.visibility = getAttribute(node, "visibility") || attributeState.visibility;
      if (visibility === "hidden" && !nodeIs(node, "svg,g,marker,a,pattern,defs,text")) {
        return;
      }
  
      var tfMatrix,
          hasFillColor = false,
          fillRGB = null,
          fillMode = "inherit",
          strokeMode = "inherit",
          fillUrl = null,
          fillData = null,
          bBox;
  
      //
      // Decide about the render target and set the correct transformation
      //
  
      // if we are within a defs node, start a new pdf form object and draw this node and all children on that instead
      // of the top-level page
      var targetIsFormObject = withinDefs && !nodeIs(node, "lineargradient,radialgradient,pattern");
      if (targetIsFormObject) {
  
        // the transformations directly at the node are written to the pdf form object transformation matrix
        tfMatrix = computeNodeTransform(node);
        bBox = getUntransformedBBox(node);
  
        _pdf.beginFormObject(bBox[0], bBox[1], bBox[2], bBox[3], tfMatrix);
  
        // continue without transformation and set withinDefs to false to prevent child nodes from starting new form objects
        tfMatrix = _pdf.unitMatrix;
        withinDefs = false;
  
      } else {
        tfMatrix = _pdf.matrixMult(computeNodeTransform(node), contextTransform);
        _pdf.saveGraphicsState();
      }
  
      //
      // extract fill and stroke mode
      //
  
      // fill mode
      if (nodeIs(node, "g,path,rect,text,ellipse,line,circle,polygon")) {
        function setDefaultColor() {
          fillRGB = new RGBColor("rgb(0, 0, 0)");
          hasFillColor = true;
          fillMode = "F";
        }
  
        var fillColor = getAttribute(node, "fill");
        if (fillColor) {
          var url = iriReference.exec(fillColor);
          if (url) {
            // probably a gradient (or something unsupported)
            fillUrl = svgIdPrefix.get() + url[1];
            var fill = getFromDefs(fillUrl, defs);
            if (fill && nodeIs(fill, "lineargradient,radialgradient")) {
  
              // matrix to convert between gradient space and user space
              // for "userSpaceOnUse" this is the current transformation: tfMatrix
              // for "objectBoundingBox" or default, the gradient gets scaled and transformed to the bounding box
              var gradientUnitsMatrix = tfMatrix;
              if (!fill.hasAttribute("gradientUnits")
                  || fill.getAttribute("gradientUnits").toLowerCase() === "objectboundingbox") {
                bBox || (bBox = getUntransformedBBox(node));
                gradientUnitsMatrix = new _pdf.Matrix(bBox[2], 0, 0, bBox[3], bBox[0], bBox[1]);
  
                var nodeTransform = computeNodeTransform(node);
                gradientUnitsMatrix = _pdf.matrixMult(gradientUnitsMatrix, nodeTransform);
              }
  
              // matrix that is applied to the gradient before any other transformations
              var gradientTransform = parseTransform(fill.getAttribute("gradientTransform"));
  
              fillData = _pdf.matrixMult(gradientTransform, gradientUnitsMatrix);
  
              fillMode = "";
            } else if (fill && nodeIs(fill, "pattern")) {
              var fillBBox, y, width, height, x;
              fillData = {};
  
              var patternUnitsMatrix = _pdf.unitMatrix;
              if (!fill.hasAttribute("patternUnits")
                  || fill.getAttribute("patternUnits").toLowerCase() === "objectboundingbox") {
                bBox || (bBox = getUntransformedBBox(node));
                patternUnitsMatrix = new _pdf.Matrix(1, 0, 0, 1, bBox[0], bBox[1]);
  
                // TODO: slightly inaccurate (rounding errors? line width bBoxes?)
                fillBBox = getUntransformedBBox(fill);
                x = fillBBox[0] * bBox[0];
                y = fillBBox[1] * bBox[1];
                width = fillBBox[2] * bBox[2];
                height = fillBBox[3] * bBox[3];
                fillData.boundingBox = [x, y, x + width, y + height];
                fillData.xStep = width;
                fillData.yStep = height;
              }
  
              var patternContentUnitsMatrix = _pdf.unitMatrix;
              if (fill.hasAttribute("patternContentUnits")
                  && fill.getAttribute("patternContentUnits").toLowerCase() === "objectboundingbox") {
                bBox || (bBox = getUntransformedBBox(node));
                patternContentUnitsMatrix = new _pdf.Matrix(bBox[2], 0, 0, bBox[3], 0, 0);
  
                fillBBox = fillData.boundingBox || getUntransformedBBox(fill);
                x = fillBBox[0] / bBox[0];
                y = fillBBox[1] / bBox[1];
                width = fillBBox[2] / bBox[2];
                height = fillBBox[3] / bBox[3];
                fillData.boundingBox = [x, y, x + width, y + height];
                fillData.xStep = width;
                fillData.yStep = height;
              }
  
              fillData.matrix = _pdf.matrixMult(
                  _pdf.matrixMult(patternContentUnitsMatrix, patternUnitsMatrix), tfMatrix);
  
              fillMode = "F";
            } else {
              // unsupported fill argument -> fill black
              fillUrl = fill = null;
              setDefaultColor();
            }
          } else {
            // plain color
            fillRGB = parseColor(fillColor);
            if (fillRGB.ok) {
              hasFillColor = true;
              fillMode = "F";
            } else {
              fillMode = "";
            }
          }
        }
  
        // opacity is realized via a pdf graphics state
        var opacity = 1.0;
        var nodeOpacity = getAttribute(node, "opacity")
            || getAttribute(node, "fill-opacity")
            // this is a quickfix: pdf can't handle different opacity values for stroke and fill
            // we could split the primitive into two parts, however
            || getAttribute(node, "stroke-opacity");
        if (nodeOpacity) {
          opacity *= parseFloat(nodeOpacity);
        }
        if (fillRGB && typeof fillRGB.a === "number") {
          opacity *= fillRGB.a;
        }
        _pdf.setGState(new _pdf.GState({opacity: opacity}));
      }
  
      if (nodeIs(node, "g,path,rect,ellipse,line,circle,polygon")) {
        // text has no fill color, so don't apply it until here
        if (hasFillColor) {
          attributeState.fill = fillRGB;
          _pdf.setFillColor(fillRGB.r, fillRGB.g, fillRGB.b);
        }
  
        // stroke mode
        var strokeColor = getAttribute(node, "stroke");
        if (strokeColor) {
          var strokeWidth = getAttribute(node, "stroke-width");
          if (strokeWidth !== void 0 && strokeWidth !== "") {
            strokeWidth = Math.abs(parseFloat(strokeWidth));
            attributeState.strokeWidth = strokeWidth;
            _pdf.setLineWidth(strokeWidth);
          }
          var strokeRGB = new RGBColor(strokeColor);
          if (strokeRGB.ok) {
            attributeState.color = strokeRGB;
            _pdf.setDrawColor(strokeRGB.r, strokeRGB.g, strokeRGB.b);
            if (strokeWidth !== 0) {
              // pdf spec states: "A line width of 0 denotes the thinnest line that can be rendered at device resolution:
              // 1 device pixel wide". SVG, however, does not draw zero width lines.
              strokeMode = "D";
            } else {
              strokeMode = "";
            }
          }
          var lineCap = getAttribute(node, "stroke-linecap");
          if (lineCap) {
            _pdf.setLineCap(attributeState.strokeLinecap = lineCap);
          }
          var lineJoin = getAttribute(node, "stroke-linejoin");
          if (lineJoin) {
            _pdf.setLineJoin(attributeState.strokeLinejoin = lineJoin);
          }
          var dashArray = getAttribute(node, "stroke-dasharray");
          if (dashArray) {
            dashArray = parseFloats(dashArray);
            var dashOffset = parseInt(getAttribute(node, "stroke-dashoffset")) || 0;
            attributeState.strokeDasharray = dashArray;
            attributeState.strokeDashoffset = dashOffset;
            _pdf.setLineDashPattern(dashArray, dashOffset);
          }
          var miterLimit = getAttribute(node, "stroke-miterlimit");
          if (miterLimit !== void 0 && miterLimit !== "") {
            _pdf.setLineMiterLimit(attributeState.strokeMiterlimit = parseFloat(miterLimit));
          }
        }
      }
  
      // inherit fill and stroke mode if not specified at this node
      fillMode = attributeState.fillMode = fillMode === "inherit" ? attributeState.fillMode : fillMode;
      strokeMode = attributeState.strokeMode = strokeMode === "inherit" ? attributeState.strokeMode : strokeMode;
  
      var colorMode = fillMode + strokeMode;
  
      setTextProperties(node, fillRGB);
  
      // do the actual drawing
      switch (node.tagName.toLowerCase()) {
        case 'svg':
          svg(node, tfMatrix, defs, svgIdPrefix, withinDefs, attributeState);
          break;
        case 'g':
          findAndRenderDefs(node, tfMatrix, defs, svgIdPrefix, withinDefs, attributeState);
        case 'a':
        case "marker":
          renderChildren(node, tfMatrix, defs, svgIdPrefix, withinDefs, attributeState);
          break;
  
        case 'defs':
          renderChildren(node, tfMatrix, defs, svgIdPrefix, true, attributeState);
          break;
  
        case 'use':
          use(node, tfMatrix, svgIdPrefix);
          break;
  
        case 'line':
          line(node, tfMatrix, svgIdPrefix, attributeState);
          break;
  
        case 'rect':
          _pdf.setCurrentTransformationMatrix(tfMatrix);
          rect(node, colorMode, fillUrl, fillData);
          break;
  
        case 'ellipse':
          _pdf.setCurrentTransformationMatrix(tfMatrix);
          ellipse(node, colorMode, fillUrl, fillData);
          break;
  
        case 'circle':
          _pdf.setCurrentTransformationMatrix(tfMatrix);
          circle(node, colorMode, fillUrl, fillData);
          break;
        case 'text':
          text(node, tfMatrix, hasFillColor, fillRGB, attributeState);
          break;
  
        case 'path':
          path(node, tfMatrix, svgIdPrefix, colorMode, fillUrl, fillData, attributeState);
          break;
  
        case 'polygon':
          polygon(node, tfMatrix, colorMode, fillUrl, fillData, svgIdPrefix, attributeState);
          break;
  
        case 'image':
          _pdf.setCurrentTransformationMatrix(tfMatrix);
          image(node);
          break;
  
        case "lineargradient":
          putGradient(node, "axial", [
            node.getAttribute("x1"),
            node.getAttribute("y1"),
            node.getAttribute("x2"),
            node.getAttribute("y2")
          ], defs, svgIdPrefix);
          break;
  
        case "radialgradient":
          putGradient(node, "radial", [
            node.getAttribute("fx") || node.getAttribute("cx"),
            node.getAttribute("fy") || node.getAttribute("cy"),
            0,
            node.getAttribute("cx") || 0,
            node.getAttribute("cy") || 0,
            node.getAttribute("r") || 0
          ], defs, svgIdPrefix);
          break;
  
        case "pattern":
          pattern(node, defs, svgIdPrefix, attributeState);
          break;
      }
  
      // close either the formObject or the graphics context
      if (targetIsFormObject) {
        _pdf.endFormObject(svgIdPrefix.get() + node.getAttribute("id"));
      } else {
        _pdf.restoreGraphicsState();
      }
    };
  
    // the actual svgToPdf function (see above)
    var svg2pdf = function (element, pdf, options) {
      _pdf = pdf;
  
      var k = options.scale || 1.0,
          xOffset = options.xOffset || 0.0,
          yOffset = options.yOffset || 0.0;
  
      // set offsets and scale everything by k
      _pdf.saveGraphicsState();
      _pdf.setCurrentTransformationMatrix(new _pdf.Matrix(k, 0, 0, k, xOffset, yOffset));
  
      // set default values that differ from pdf defaults
      var attributeState = new AttributeState();
      _pdf.setLineWidth(attributeState.strokeWidth);
      var fill = attributeState.fill;
      _pdf.setFillColor(fill.r, fill.g, fill.b);
      _pdf.setFont(attributeState.fontFamily);
      _pdf.setFontSize(attributeState.fontSize);
  
      // start rendering
      renderNode(element.cloneNode(true), _pdf.unitMatrix, {}, new SvgPrefix(""), false, attributeState);
  
      _pdf.restoreGraphicsState();
  
      return _pdf;
    };
  
    if (typeof define === "function" && define.amd) {
      define(["./rgbcolor", "SvgPath"], function (rgbcolor, svgpath) {
        RGBColor = rgbcolor;
        SvgPath = svgpath;
        return svg2pdf;
      });
    } else if (typeof module !== "undefined" && module.exports) {
      RGBColor = require("./rgbcolor.js");
      SvgPath = require("SvgPath");
      module.exports = svg2pdf;
    } else {
      SvgPath = global.SvgPath;
      RGBColor = global.RGBColor;
      global.svg2pdf = svg2pdf;
      // for compatibility reasons
      global.svgElementToPdf = svg2pdf;
    }
    return svg2pdf;
  }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this));
  
  },{"./rgbcolor.js":8,"SvgPath":1}]},{},[9])(9)
  });
  //# sourceMappingURL=svg2pdf.js.map
  