pathReg = /(m[^(h|v|l)]*|[vhl][^(v|h|l|z)]*)/gmi;
ns = 'http://www.w3.org/2000/svg';
clone = function(a) {
      var copy;
      if (a instanceof Array) {
        copy = [];
        for (var i = 0, len = a.length; i < len; i++) {
          copy[i] = clone(a[i]);
        }
        return copy;
      }
      return a;
    }
createPath = function (p){ // createPath
      var c = document.createElementNS(ns,'path'), d = typeof p === 'object' ? p.getAttribute('d') : p; 
      c.setAttribute('d',d); return c;
    }
getSegments = function(s,e,r){ // getSegments returns an array of points based on a sample size morphPrecision
      var s1 = [], e1 = [], le1 = s.getTotalLength(), le2 = e.getTotalLength(), ml = Math.max(le1,le2),
        d = r, ar = ml / r, j = 0, sl = ar*r; // sl = sample length

      while ( (j += r) < sl ) { // populate the points arrays based on morphPrecision as sample size
        s1.push( [s.getPointAtLength(j).x, s.getPointAtLength(j).y]);
        e1.push( [e.getPointAtLength(j).x, e.getPointAtLength(j).y]);
      }
      return [s1,e1];
    }
getClosestPoint = function(p,t,s){
      var x, y, a = [], l = s.length, dx, nx, pr;
      for (i=0; i<l; i++){
        x = Math.abs(s[i][0] - t.x);
        y = Math.abs(s[i][1] - t.y);
        a.push( Math.sqrt( x * x + y * y ) );
      }
      dx = a.indexOf(Math.min.apply(null,a));
      pr = !!s[dx-1] ? dx-1 : l-1;
      nx = !!s[dx+1] ? dx+1 : 0;
      return Math.abs(s[pr][0] - t.x) < p && Math.abs(s[pr][1] - t.y) < p ? s[pr]
      : Math.abs(s[nx][0] - t.x) < p && Math.abs(s[nx][1] - t.y) < p ? s[nx] 
      : Math.abs(s[dx][0] - t.x) < p && Math.abs(s[dx][1] - t.y) < p ? s[dx] 
      : [t.x,t.y];
    }
getBestIndex = function(s,e){ // getBestIndex for shape rotation
      var s1 = clone(s), e1 = clone(e), d = [], i, l = e.length, t, ax, ay;
      for (i=0; i<l; i++){
        t = e1.splice(i,l-i); e1 = t.concat(e1);
        ax = Math.abs(s1[i][0] - e1[i][0]);
        ay = Math.abs(s1[i][1] - e1[i][1]);
        d.push( Math.sqrt( ax * ax + ay * ay ) );
        e1 = []; e1 = clone(e); t = null;
      }
      return d.indexOf(Math.min.apply(null,d));
    }
pathToAbsolute = function(p) {
      var np = p.match(pathReg), wp = [], l = np.length, s, c, r, x = 0, y = 0;
      for (var i = 0; i<l; i++){
        np[i] = np[i]; c = np[i][0]; r = new RegExp(c+'[^\\d|\\-]*','i'); 
        np[i] = np[i].replace(/(^|[^,])\s*-/g, '$1,-').replace(/(\s+\,|\s|\,)/g,',').replace(r,'').split(',');
        np[i][0] = parseFloat(np[i][0]);
        np[i][1] = parseFloat(np[i][1]);
        if (i === 0) { x+=np[i][0]; y +=np[i][1]; }
        else {
          x = np[i-1][0]; 
          y = np[i-1][1]; 
          if (/l/i.test(c)) {
            np[i][0] = c === 'l' ? np[i][0] + x : np[i][0];
            np[i][1] = c === 'l' ? np[i][1] + y : np[i][1];  
          } else if (/h/i.test(c)) {
            np[i][0] = c === 'h' ? np[i][0] + x : np[i][0];
            np[i][1] = y;  
          } else if (/v/i.test(c)) {
            np[i][0] = x;
            np[i][1] = c === 'v' ? np[i][0] + y : np[i][0];
          }
        }
      }
      return np;
    }
pathCross = function(s,e){ // pathCross
      var s1, e1, arr, arL, sm, lg, smp, lgp, nsm = [], sml, cl = [], len, tl, cs,
          isPolygon = !/[CSQTA]/i.test(s) && !/[CSQTA]/i.test(e);

      if (!isPolygon) {
        s = createPath(s); e = createPath(e);  
        arr = getSegments(s,e,parseInt('1')); 
        s1 = arr[0]; e1 = arr[1]; arL = e1.length;
      } else {
        s = pathToAbsolute(s); e = pathToAbsolute(e);

        if ( s.length !== e.length ){
          arL = Math.max(s.length,e.length);
          if ( arL === e.length) { sm = s; lg = e; } else { sm = e; lg = s; }
          sml = sm.length;

          smp = createPath('M'+sm.join('L')+'z'); len = smp.getTotalLength() / arL;
          for (var i=0; i<arL; i++){
            tl = smp.getPointAtLength(len*i);
            cs = getClosestPoint(len,tl,sm);
            nsm.push( [ cs[0], cs[1] ] );
          }

          if (arL === e.length) { e1 = lg; s1 = nsm; } else { s1 = lg; e1 = nsm; }
        } else {
          s1 = s; e1 = e;
        }
      }

      // determine index for best/minimum distance between points
      return getBestIndex(s1,e1);
    };
getOnePath = function(p){ return p.split(/z/i).shift() + 'z'; }