text: /*
   * Lazy Line Painter
   * SVG Stroke animation.
   *
   * https://github.com/camoconnell/lazy-line-painter
   * http://www.camoconnell.com
   *
   * Licensed under the MIT license.
   *
   */
  
  (function ($, window, undefined) {
  
      "use strict";
  
      var dataKey = 'lazyLinePainter';
      var methods = {
  
          /*
           PUBLIC : SETUP LAZY LINE DATA
           */
          init: function (_options) {
  
              return this.each(function () {
  
                  var $this = $(this);
                  var data = $this.data(dataKey);
                  $this.addClass('lazy-line');
  
                  // If the plugin hasn't been initialized yet
                  if (!data) {
  
                      // Collect settings, define defaults
                      var options = $.extend({
                          'width': null,
                          'height': null,
                          'strokeWidth': 2,
                          'strokeColor': '#000',
                          'strokeOverColor': null,
                          'strokeCap': 'round',
                          'strokeJoin': 'round',
                          'strokeOpacity': 1,
                          'arrowEnd': 'none',
                          'strokeDash': null,
                          'onComplete': null,
                          'delay': null,
                          'overrideKey': null,
                          'drawSequential': true,
                          'speedMultiplier': 1
                      }, _options);
  
                      // Set up path information
                      // if overrideKey has been defined - use overrideKey as key within the svgData object.
                      // else - use the elements id as key within the svgData object.
                      var target = options.overrideKey ? options.overrideKey : $this.attr('id').replace('#', '');
                      var w = options.svgData[target].dimensions.width;
                      var h = options.svgData[target].dimensions.height;
  
                      // target stroke path
                      options.svgData = options.svgData[target].strokepath;
  
                      // Create svg element and set dimensions
                      if (options.width === null) {
                          options.width = w;
                      }
                      if (options.height === null) {
                          options.height = h;
                      }
                      var svg = getSVGElement({
                          viewBox: '0 0 ' + w + ' ' + h,
                          preserveAspectRatio: 'xMidYMid'
                      });
                      options.svg = $(svg);
                      $this.append(options.svg);
                      $this.data(dataKey, options);
                  }
              });
          },
  
          /*
           PUBLIC : PAINT LAZY LINE DATA
           */
          paint: function () {
              return this.each(function () {
                  var $this = $(this);
                  var data = $this.data(dataKey);
                  var init = function () {
                      // Set width / height of container element
                      $this.css({
                          'width': data.width,
                          'height': data.height
                      });
  
                      // Build array of path objects
                      data.paths = [];
                      data.longestDuration = 0;
                      data.playhead = 0;
  
                      // Loop paths
                      for (var i = 0; i < data.svgData.length; i++) {
  
                          var path = getPath(data, i);
                          var length = path.getTotalLength();
                          path.style.strokeDasharray = length + ' ' + length;
                          path.style.strokeDashoffset = length;
                          path.style.display = 'block';
                          path.getBoundingClientRect();
  
                          var duration = data.svgData[i].duration * data.speedMultiplier;
                          if (duration > data.longestDuration) {
                              data.longestDuration = duration;
                          }
  
                          data.paths.push({
                              'duration': duration,
                              'drawStartTime': data.playhead,
                              'path': path,
                              'length': length
                          });
                          data.playhead += duration;
                      }
  
                      data.totalDuration = (data.drawSequential) ? data.playhead : data.longestDuration;
                      data.rAF = requestAnimationFrame(function (timestamp) {
                          draw(timestamp, data);
                      });
                  };
  
                  // if delay isset
                  if (data.delay === null) {
                      init();
                  } else {
                      setTimeout(init, data.delay);
                  }
              });
          },
  
          /*
           TOGGLE PAUSE/RESUME ANIMATION
           */
          pauseResume: function () {
  
              return this.each(function () {
  
                  var data = $(this).data(dataKey);
  
                  if (!data.paused) {
                      data.paused = true;
                      cancelAnimationFrame(data.rAF);
                  } else {
                      data.paused = false;
                      // resume
                      requestAnimationFrame(function (timestamp) {
                          adjustStartTime(timestamp, data)
                      });
                  }
              });
          },
          /*
           ERASE LAZY LINE DATA
           */
          erase: function () {
  
              return this.each(function () {
                  var $this = $(this);
                  $this.removeData(dataKey);
                  $this.find('svg').empty();
  
              });
          },
  
          /*
           DESTROY LAZY LINE DATA & ELEMENT
           */
          destroy: function () {
  
              return this.each(function () {
  
                  var $this = $(this);
                  $this.removeData(dataKey);
                  $this.remove();
              });
          },
          /*
           STAMP LAZY LINE DATA
           */
          stamp: function () {
  
              return this.each(function () {
  
                  var $this = $(this),
                      d = $this.data(dataKey);
  
                  var init = function () {
  
                      // Set width / height of container element
                      $this.css({
                          'width': d.width,
                          'height': d.height
                      });
  
                      // Loop paths
                      //$.each(d.svgData, function (i, val) {
                      for (i = 0; i < d.svgData.length; i++) {
                          d.paper.path(d.svgData[i].path).attr(applyStyles(d, d.svgData[i]));
                      }
  
                  };
  
                  // if delay isset
                  if (d.delay === null)
                      init();
                  else
                      setTimeout(init, d.delay);
              });
          }
      };
  
      var adjustStartTime = function (timestamp, o) {
          o.startTime = timestamp - o.elapsed_time;
          requestAnimationFrame(function (timestamp) {
              draw(timestamp, o);
          });
      }
  
      var draw = function (timestamp, o) {
  
          if (o.startTime == null) {
              o.startTime = timestamp;
          }
          o.elapsed_time = timestamp - o.startTime;
  
          for (var i = 0; i < o.paths.length; i++) {
  
              var path_elapsed_time;
              if (o.drawSequential) {
                  path_elapsed_time = o.elapsed_time - o.paths[i].drawStartTime;
                  if (path_elapsed_time < 0) path_elapsed_time = 0;
              } else {
                  path_elapsed_time = o.elapsed_time;
              }
  
              // don't redraw paths that are finished or paths that aren't up yet
              if (path_elapsed_time < o.paths[i].duration && path_elapsed_time > 0) {
                  var frame_length = path_elapsed_time / o.paths[i].duration * o.paths[i].length;
                  o.paths[i].path.style.strokeDashoffset = o.paths[i].length - frame_length;
              } else if (path_elapsed_time > o.paths[i].duration) {
                  o.paths[i].path.style.strokeDashoffset = 0;
              }
          }
  
          // whether to continue
          if (o.elapsed_time < o.totalDuration) {
              o.rAF = requestAnimationFrame(function (timestamp) {
                  draw(timestamp, o);
              });
          } else {
              if (o.onComplete != null) o.onComplete();
          }
      }
  
      var applyStyles = function (data, value) {
  
          var styles = {
              "stroke": (!value.strokeColor) ? data.strokeColor : value.strokeColor,
              "fill-opacity": 0,
              "stroke-dasharray": (!value.strokeDash) ? data.strokeDash : value.strokeDash,
              "stroke-opacity": (!value.strokeOpacity) ? data.strokeOpacity : value.strokeOpacity,
              "stroke-width": (!value.strokeWidth) ? data.strokeWidth : value.strokeWidth,
              "stroke-linecap": (!value.strokeCap) ? data.strokeCap : value.strokeCap,
              "stroke-linejoin": (!value.strokeJoin) ? data.strokeJoin : value.strokeJoin
          };
  
          return styles;
      };
  
      /*
       PRIVATE : SET PATH DATA
       */
      var getPath = function (data, i) {
          var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
          var $path = $(path);
          data.svg.append($path);
          $path.attr(getAttributes(data, data.svgData[i]));
          return path;
      };
  
      /*
       PRIVATE : GET STYLE DATA
       */
      var getAttributes = function (data, value) {
          var attributes = {
              "d": value.path,
              "stroke": (!value.strokeColor) ? data.strokeColor : value.strokeColor,
              "fill-opacity": 0,
              "stroke-dasharray": (!value.strokeDash) ? data.strokeDash : value.strokeDash,
              "stroke-opacity": (!value.strokeOpacity) ? data.strokeOpacity : value.strokeOpacity,
              "stroke-width": (!value.strokeWidth) ? data.strokeWidth : value.strokeWidth,
              "stroke-linecap": (!value.strokeCap) ? data.strokeCap : value.strokeCap,
              "stroke-linejoin": (!value.strokeJoin) ? data.strokeJoin : value.strokeJoin,
              "arrow-end": (!value.arrowEnd) ? data.arrowEnd : value.arrowEnd,
              "markerWidth": "4",
              "markerHeight": "3",
              "orient": "auto"
          };
          return attributes;
      };
  
      /*
       PRIVATE : GET STYLE DATA
       */
      var getSVGElement = function (attr) {
          var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
          svg.setAttributeNS(null, 'viewBox', attr.viewBox);
          svg.setAttributeNS(null, 'preserveAspectRatio', attr.preserveAspectRatio);
          svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
          return svg;
      };
  
      $.fn.lazylinepainter = function (method) {
          if (methods[method]) {
              return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
          } else if (typeof method === 'object' || !method) {
              return methods.init.apply(this, arguments);
          } else {
              // error
          }
      };
  
  })(jQuery, window);