text: /* *
   *
   *  (c) 2016 Highsoft AS
   *  Author: Øystein Moseng
   *
   *  License: www.highcharts.com/license
   *
   *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
   *
   * */
  'use strict';
  import U from '../Core/Utilities.js';
  
  var extend = U.extend, pick = U.pick;
  var min = Math.min, max = Math.max, abs = Math.abs;
  
  /**
   * Get index of last obstacle before xMin. Employs a type of binary search, and
   * thus requires that obstacles are sorted by xMin value.
   *
   * @private
   * @function findLastObstacleBefore
   *
   * @param {Array<object>} obstacles
   *        Array of obstacles to search in.
   *
   * @param {number} xMin
   *        The xMin threshold.
   *
   * @param {number} [startIx]
   *        Starting index to search from. Must be within array range.
   *
   * @return {number}
   *         The index of the last obstacle element before xMin.
   */
  function findLastObstacleBefore(obstacles, xMin, startIx) {
      var left = startIx || 0, // left limit
          right = obstacles.length - 1, // right limit
          min = xMin - 0.0000001, // Make sure we include all obstacles at xMin
          cursor, cmp;
      while (left <= right) {
          cursor = (right + left) >> 1;
          cmp = min - obstacles[cursor].xMin;
          if (cmp > 0) {
              left = cursor + 1;
          } else if (cmp < 0) {
              right = cursor - 1;
          } else {
              return cursor;
          }
      }
      return left > 0 ? left - 1 : 0;
  }
  
  /**
   * Test if a point lays within an obstacle.
   *
   * @private
   * @function pointWithinObstacle
   *
   * @param {object} obstacle
   *        Obstacle to test.
   *
   * @param {Highcharts.Point} point
   *        Point with x/y props.
   *
   * @return {boolean}
   *         Whether point is within the obstacle or not.
   */
  function pointWithinObstacle(obstacle, point) {
      return (point.x <= obstacle.xMax &&
          point.x >= obstacle.xMin &&
          point.y <= obstacle.yMax &&
          point.y >= obstacle.yMin);
  }
  
  /**
   * Find the index of an obstacle that wraps around a point.
   * Returns -1 if not found.
   *
   * @private
   * @function findObstacleFromPoint
   *
   * @param {Array<object>} obstacles
   *        Obstacles to test.
   *
   * @param {Highcharts.Point} point
   *        Point with x/y props.
   *
   * @return {number}
   *         Ix of the obstacle in the array, or -1 if not found.
   */
  function findObstacleFromPoint(obstacles, point) {
      var i = findLastObstacleBefore(obstacles, point.x + 1) + 1;
      while (i--) {
          if (obstacles[i].xMax >= point.x &&
              // optimization using lazy evaluation
              pointWithinObstacle(obstacles[i], point)) {
              return i;
          }
      }
      return -1;
  }
  
  /**
   * Get SVG path array from array of line segments.
   *
   * @private
   * @function pathFromSegments
   *
   * @param {Array<object>} segments
   *        The segments to build the path from.
   *
   * @return {Highcharts.SVGPathArray}
   *         SVG path array as accepted by the SVG Renderer.
   */
  function pathFromSegments(segments) {
      var path = [];
      if (segments.length) {
          path.push(['M', segments[0].start.x, segments[0].start.y]);
          for (var i = 0; i < segments.length; ++i) {
              path.push(['L', segments[i].end.x, segments[i].end.y]);
          }
      }
      return path;
  }
  
  /**
   * Limits obstacle max/mins in all directions to bounds. Modifies input
   * obstacle.
   *
   * @private
   * @function limitObstacleToBounds
   *
   * @param {object} obstacle
   *        Obstacle to limit.
   *
   * @param {object} bounds
   *        Bounds to use as limit.
   *
   * @return {void}
   */
  function limitObstacleToBounds(obstacle, bounds) {
      obstacle.yMin = max(obstacle.yMin, bounds.yMin);
      obstacle.yMax = min(obstacle.yMax, bounds.yMax);
      obstacle.xMin = max(obstacle.xMin, bounds.xMin);
      obstacle.xMax = min(obstacle.xMax, bounds.xMax);
  }
  
  /**
   * Get an SVG path from a starting coordinate to an ending coordinate.
   * Draws a straight line.
   *
   * @function Highcharts.Pathfinder.algorithms.straight
   *
   * @param {Highcharts.PositionObject} start
   *        Starting coordinate, object with x/y props.
   *
   * @param {Highcharts.PositionObject} end
   *        Ending coordinate, object with x/y props.
   *
   * @return {object}
   *         An object with the SVG path in Array form as accepted by the SVG
   *         renderer, as well as an array of new obstacles making up this
   *         path.
   */
  function straight(start, end) {
      return {
          path: [
              ['M', start.x, start.y],
              ['L', end.x, end.y]
          ],
          obstacles: [{start: start, end: end}]
      };
  }
  
  /**
   * Find a path from a starting coordinate to an ending coordinate, using
   * right angles only, and taking only starting/ending obstacle into
   * consideration.
   *
   * @function Highcharts.Pathfinder.algorithms.simpleConnect
   *
   * @param {Highcharts.PositionObject} start
   *        Starting coordinate, object with x/y props.
   *
   * @param {Highcharts.PositionObject} end
   *        Ending coordinate, object with x/y props.
   *
   * @param {object} options
   *        Options for the algorithm:
   *        - chartObstacles: Array of chart obstacles to avoid
   *        - startDirectionX: Optional. True if starting in the X direction.
   *          If not provided, the algorithm starts in the direction that is
   *          the furthest between start/end.
   *
   * @return {object}
   *         An object with the SVG path in Array form as accepted by the SVG
   *         renderer, as well as an array of new obstacles making up this
   *         path.
   */
  var simpleConnect = extend(function (start, end, options) {
      var segments = [], endSegment, dir = pick(options.startDirectionX, abs(end.x - start.x) > abs(end.y - start.y)) ? 'x' : 'y', chartObstacles = options.chartObstacles,
          startObstacleIx = findObstacleFromPoint(chartObstacles, start), endObstacleIx = findObstacleFromPoint(chartObstacles, end), startObstacle, endObstacle, prevWaypoint,
          waypoint, waypoint2, useMax, endPoint;
  
      // eslint-disable-next-line valid-jsdoc
      /**
       * Return a clone of a point with a property set from a target object,
       * optionally with an offset
       * @private
       */
      function copyFromPoint(from, fromKey, to, toKey, offset) {
          var point = {
              x: from.x,
              y: from.y
          };
          point[fromKey] = to[toKey || fromKey] + (offset || 0);
          return point;
      }
  
      // eslint-disable-next-line valid-jsdoc
      /**
       * Return waypoint outside obstacle.
       * @private
       */
      function getMeOut(obstacle, point, direction) {
          var useMax = abs(point[direction] - obstacle[direction + 'Min']) >
              abs(point[direction] - obstacle[direction + 'Max']);
          return copyFromPoint(point, direction, obstacle, direction + (useMax ? 'Max' : 'Min'), useMax ? 1 : -1);
      }
  
      // Pull out end point
      if (endObstacleIx > -1) {
          endObstacle = chartObstacles[endObstacleIx];
          waypoint = getMeOut(endObstacle, end, dir);
          endSegment = {
              start: waypoint,
              end: end
          };
          endPoint = waypoint;
      } else {
          endPoint = end;
      }
      // If an obstacle envelops the start point, add a segment to get out,
      // and around it.
      if (startObstacleIx > -1) {
          startObstacle = chartObstacles[startObstacleIx];
          waypoint = getMeOut(startObstacle, start, dir);
          segments.push({
              start: start,
              end: waypoint
          });
          // If we are going back again, switch direction to get around start
          // obstacle.
          if (
              // Going towards max from start:
              waypoint[dir] >= start[dir] ===
              // Going towards min to end:
              waypoint[dir] >= endPoint[dir]) {
              dir = dir === 'y' ? 'x' : 'y';
              useMax = start[dir] < end[dir];
              segments.push({
                  start: waypoint,
                  end: copyFromPoint(waypoint, dir, startObstacle, dir + (useMax ? 'Max' : 'Min'), useMax ? 1 : -1)
              });
              // Switch direction again
              dir = dir === 'y' ? 'x' : 'y';
          }
      }
      // We are around the start obstacle. Go towards the end in one
      // direction.
      prevWaypoint = segments.length ?
          segments[segments.length - 1].end :
          start;
      waypoint = copyFromPoint(prevWaypoint, dir, endPoint);
      segments.push({
          start: prevWaypoint,
          end: waypoint
      });
      // Final run to end point in the other direction
      dir = dir === 'y' ? 'x' : 'y';
      waypoint2 = copyFromPoint(waypoint, dir, endPoint);
      segments.push({
          start: waypoint,
          end: waypoint2
      });
      // Finally add the endSegment
      segments.push(endSegment);
      return {
          path: pathFromSegments(segments),
          obstacles: segments
      };
  }, {
      requiresObstacles: true
  });
  /**
   * Find a path from a starting coordinate to an ending coordinate, taking
   * obstacles into consideration. Might not always find the optimal path,
   * but is fast, and usually good enough.
   *
   * @function Highcharts.Pathfinder.algorithms.fastAvoid
   *
   * @param {Highcharts.PositionObject} start
   *        Starting coordinate, object with x/y props.
   *
   * @param {Highcharts.PositionObject} end
   *        Ending coordinate, object with x/y props.
   *
   * @param {object} options
   *        Options for the algorithm.
   *        - chartObstacles:  Array of chart obstacles to avoid
   *        - lineObstacles:   Array of line obstacles to jump over
   *        - obstacleMetrics: Object with metrics of chartObstacles cached
   *        - hardBounds:      Hard boundaries to not cross
   *        - obstacleOptions: Options for the obstacles, including margin
   *        - startDirectionX: Optional. True if starting in the X direction.
   *                           If not provided, the algorithm starts in the
   *                           direction that is the furthest between
   *                           start/end.
   *
   * @return {object}
   *         An object with the SVG path in Array form as accepted by the SVG
   *         renderer, as well as an array of new obstacles making up this
   *         path.
   */
  var fastAvoid = extend(function (start, end, options) {
      /*
          Algorithm rules/description
          - Find initial direction
          - Determine soft/hard max for each direction.
          - Move along initial direction until obstacle.
          - Change direction.
          - If hitting obstacle, first try to change length of previous line
              before changing direction again.
  
          Soft min/max x = start/destination x +/- widest obstacle + margin
          Soft min/max y = start/destination y +/- tallest obstacle + margin
  
          @todo:
              - Make retrospective, try changing prev segment to reduce
                  corners
              - Fix logic for breaking out of end-points - not always picking
                  the best direction currently
              - When going around the end obstacle we should not always go the
                  shortest route, rather pick the one closer to the end point
      */
      var dirIsX = pick(options.startDirectionX, abs(end.x - start.x) > abs(end.y - start.y)), dir = dirIsX ? 'x' : 'y', segments, useMax, extractedEndPoint, endSegments = [],
          forceObstacleBreak = false, // Used in clearPathTo to keep track of
          // when to force break through an obstacle.
          // Boundaries to stay within. If beyond soft boundary, prefer to
          // change direction ASAP. If at hard max, always change immediately.
          metrics = options.obstacleMetrics, softMinX = min(start.x, end.x) - metrics.maxWidth - 10, softMaxX = max(start.x, end.x) + metrics.maxWidth + 10,
          softMinY = min(start.y, end.y) - metrics.maxHeight - 10, softMaxY = max(start.y, end.y) + metrics.maxHeight + 10,
          // Obstacles
          chartObstacles = options.chartObstacles, startObstacleIx = findLastObstacleBefore(chartObstacles, softMinX),
          endObstacleIx = findLastObstacleBefore(chartObstacles, softMaxX);
  
      // eslint-disable-next-line valid-jsdoc
      /**
       * How far can you go between two points before hitting an obstacle?
       * Does not work for diagonal lines (because it doesn't have to).
       * @private
       */
      function pivotPoint(fromPoint, toPoint, directionIsX) {
          var firstPoint, lastPoint, highestPoint, lowestPoint, i, searchDirection = fromPoint.x < toPoint.x ? 1 : -1;
          if (fromPoint.x < toPoint.x) {
              firstPoint = fromPoint;
              lastPoint = toPoint;
          } else {
              firstPoint = toPoint;
              lastPoint = fromPoint;
          }
          if (fromPoint.y < toPoint.y) {
              lowestPoint = fromPoint;
              highestPoint = toPoint;
          } else {
              lowestPoint = toPoint;
              highestPoint = fromPoint;
          }
          // Go through obstacle range in reverse if toPoint is before
          // fromPoint in the X-dimension.
          i = searchDirection < 0 ?
              // Searching backwards, start at last obstacle before last point
              min(findLastObstacleBefore(chartObstacles, lastPoint.x), chartObstacles.length - 1) :
              // Forwards. Since we're not sorted by xMax, we have to look
              // at all obstacles.
              0;
          // Go through obstacles in this X range
          while (chartObstacles[i] && (searchDirection > 0 && chartObstacles[i].xMin <= lastPoint.x ||
              searchDirection < 0 && chartObstacles[i].xMax >= firstPoint.x)) {
              // If this obstacle is between from and to points in a straight
              // line, pivot at the intersection.
              if (chartObstacles[i].xMin <= lastPoint.x &&
                  chartObstacles[i].xMax >= firstPoint.x &&
                  chartObstacles[i].yMin <= highestPoint.y &&
                  chartObstacles[i].yMax >= lowestPoint.y) {
                  if (directionIsX) {
                      return {
                          y: fromPoint.y,
                          x: fromPoint.x < toPoint.x ?
                              chartObstacles[i].xMin - 1 :
                              chartObstacles[i].xMax + 1,
                          obstacle: chartObstacles[i]
                      };
                  }
                  // else ...
                  return {
                      x: fromPoint.x,
                      y: fromPoint.y < toPoint.y ?
                          chartObstacles[i].yMin - 1 :
                          chartObstacles[i].yMax + 1,
                      obstacle: chartObstacles[i]
                  };
              }
              i += searchDirection;
          }
          return toPoint;
      }
  
      /**
       * Decide in which direction to dodge or get out of an obstacle.
       * Considers desired direction, which way is shortest, soft and hard
       * bounds.
       *
       * (? Returns a string, either xMin, xMax, yMin or yMax.)
       *
       * @private
       * @function
       *
       * @param {object} obstacle
       *        Obstacle to dodge/escape.
       *
       * @param {object} fromPoint
       *        Point with x/y props that's dodging/escaping.
       *
       * @param {object} toPoint
       *        Goal point.
       *
       * @param {boolean} dirIsX
       *        Dodge in X dimension.
       *
       * @param {object} bounds
       *        Hard and soft boundaries.
       *
       * @return {boolean}
       *         Use max or not.
       */
      function getDodgeDirection(obstacle, fromPoint, toPoint, dirIsX, bounds) {
          var softBounds = bounds.soft, hardBounds = bounds.hard, dir = dirIsX ? 'x' : 'y', toPointMax = {x: fromPoint.x, y: fromPoint.y},
              toPointMin = {x: fromPoint.x, y: fromPoint.y}, minPivot, maxPivot, maxOutOfSoftBounds = obstacle[dir + 'Max'] >=
              softBounds[dir + 'Max'], minOutOfSoftBounds = obstacle[dir + 'Min'] <=
              softBounds[dir + 'Min'], maxOutOfHardBounds = obstacle[dir + 'Max'] >=
              hardBounds[dir + 'Max'], minOutOfHardBounds = obstacle[dir + 'Min'] <=
              hardBounds[dir + 'Min'],
              // Find out if we should prefer one direction over the other if
              // we can choose freely
              minDistance = abs(obstacle[dir + 'Min'] - fromPoint[dir]), maxDistance = abs(obstacle[dir + 'Max'] - fromPoint[dir]),
              // If it's a small difference, pick the one leading towards dest
              // point. Otherwise pick the shortest distance
              useMax = abs(minDistance - maxDistance) < 10 ?
                  fromPoint[dir] < toPoint[dir] :
                  maxDistance < minDistance;
          // Check if we hit any obstacles trying to go around in either
          // direction.
          toPointMin[dir] = obstacle[dir + 'Min'];
          toPointMax[dir] = obstacle[dir + 'Max'];
          minPivot = pivotPoint(fromPoint, toPointMin, dirIsX)[dir] !==
              toPointMin[dir];
          maxPivot = pivotPoint(fromPoint, toPointMax, dirIsX)[dir] !==
              toPointMax[dir];
          useMax = minPivot ?
              (maxPivot ? useMax : true) :
              (maxPivot ? false : useMax);
          // useMax now contains our preferred choice, bounds not taken into
          // account. If both or neither direction is out of bounds we want to
          // use this.
          // Deal with soft bounds
          useMax = minOutOfSoftBounds ?
              (maxOutOfSoftBounds ? useMax : true) : // Out on min
              (maxOutOfSoftBounds ? false : useMax); // Not out on min
          // Deal with hard bounds
          useMax = minOutOfHardBounds ?
              (maxOutOfHardBounds ? useMax : true) : // Out on min
              (maxOutOfHardBounds ? false : useMax); // Not out on min
          return useMax;
      }
  
      // eslint-disable-next-line valid-jsdoc
      /**
       * Find a clear path between point.
       * @private
       */
      function clearPathTo(fromPoint, toPoint, dirIsX) {
          // Don't waste time if we've hit goal
          if (fromPoint.x === toPoint.x && fromPoint.y === toPoint.y) {
              return [];
          }
          var dir = dirIsX ? 'x' : 'y', pivot, segments, waypoint, waypointUseMax, envelopingObstacle, secondEnvelopingObstacle, envelopWaypoint,
              obstacleMargin = options.obstacleOptions.margin, bounds = {
                  soft: {
                      xMin: softMinX,
                      xMax: softMaxX,
                      yMin: softMinY,
                      yMax: softMaxY
                  },
                  hard: options.hardBounds
              };
          // If fromPoint is inside an obstacle we have a problem. Break out
          // by just going to the outside of this obstacle. We prefer to go to
          // the nearest edge in the chosen direction.
          envelopingObstacle =
              findObstacleFromPoint(chartObstacles, fromPoint);
          if (envelopingObstacle > -1) {
              envelopingObstacle = chartObstacles[envelopingObstacle];
              waypointUseMax = getDodgeDirection(envelopingObstacle, fromPoint, toPoint, dirIsX, bounds);
              // Cut obstacle to hard bounds to make sure we stay within
              limitObstacleToBounds(envelopingObstacle, options.hardBounds);
              envelopWaypoint = dirIsX ? {
                  y: fromPoint.y,
                  x: envelopingObstacle[waypointUseMax ? 'xMax' : 'xMin'] +
                      (waypointUseMax ? 1 : -1)
              } : {
                  x: fromPoint.x,
                  y: envelopingObstacle[waypointUseMax ? 'yMax' : 'yMin'] +
                      (waypointUseMax ? 1 : -1)
              };
              // If we crashed into another obstacle doing this, we put the
              // waypoint between them instead
              secondEnvelopingObstacle = findObstacleFromPoint(chartObstacles, envelopWaypoint);
              if (secondEnvelopingObstacle > -1) {
                  secondEnvelopingObstacle = chartObstacles[secondEnvelopingObstacle];
                  // Cut obstacle to hard bounds
                  limitObstacleToBounds(secondEnvelopingObstacle, options.hardBounds);
                  // Modify waypoint to lay between obstacles
                  envelopWaypoint[dir] = waypointUseMax ? max(envelopingObstacle[dir + 'Max'] - obstacleMargin + 1, (secondEnvelopingObstacle[dir + 'Min'] +
                      envelopingObstacle[dir + 'Max']) / 2) :
                      min((envelopingObstacle[dir + 'Min'] + obstacleMargin - 1), ((secondEnvelopingObstacle[dir + 'Max'] +
                          envelopingObstacle[dir + 'Min']) / 2));
                  // We are not going anywhere. If this happens for the first
                  // time, do nothing. Otherwise, try to go to the extreme of
                  // the obstacle pair in the current direction.
                  if (fromPoint.x === envelopWaypoint.x &&
                      fromPoint.y === envelopWaypoint.y) {
                      if (forceObstacleBreak) {
                          envelopWaypoint[dir] = waypointUseMax ?
                              max(envelopingObstacle[dir + 'Max'], secondEnvelopingObstacle[dir + 'Max']) + 1 :
                              min(envelopingObstacle[dir + 'Min'], secondEnvelopingObstacle[dir + 'Min']) - 1;
                      }
                      // Toggle on if off, and the opposite
                      forceObstacleBreak = !forceObstacleBreak;
                  } else {
                      // This point is not identical to previous.
                      // Clear break trigger.
                      forceObstacleBreak = false;
                  }
              }
              segments = [{
                  start: fromPoint,
                  end: envelopWaypoint
              }];
          } else { // If not enveloping, use standard pivot calculation
              pivot = pivotPoint(fromPoint, {
                  x: dirIsX ? toPoint.x : fromPoint.x,
                  y: dirIsX ? fromPoint.y : toPoint.y
              }, dirIsX);
              segments = [{
                  start: fromPoint,
                  end: {
                      x: pivot.x,
                      y: pivot.y
                  }
              }];
              // Pivot before goal, use a waypoint to dodge obstacle
              if (pivot[dirIsX ? 'x' : 'y'] !== toPoint[dirIsX ? 'x' : 'y']) {
                  // Find direction of waypoint
                  waypointUseMax = getDodgeDirection(pivot.obstacle, pivot, toPoint, !dirIsX, bounds);
                  // Cut waypoint to hard bounds
                  limitObstacleToBounds(pivot.obstacle, options.hardBounds);
                  waypoint = {
                      x: dirIsX ?
                          pivot.x :
                          pivot.obstacle[waypointUseMax ? 'xMax' : 'xMin'] +
                          (waypointUseMax ? 1 : -1),
                      y: dirIsX ?
                          pivot.obstacle[waypointUseMax ? 'yMax' : 'yMin'] +
                          (waypointUseMax ? 1 : -1) :
                          pivot.y
                  };
                  // We're changing direction here, store that to make sure we
                  // also change direction when adding the last segment array
                  // after handling waypoint.
                  dirIsX = !dirIsX;
                  segments = segments.concat(clearPathTo({
                      x: pivot.x,
                      y: pivot.y
                  }, waypoint, dirIsX));
              }
          }
          // Get segments for the other direction too
          // Recursion is our friend
          segments = segments.concat(clearPathTo(segments[segments.length - 1].end, toPoint, !dirIsX));
          return segments;
      }
  
      // eslint-disable-next-line valid-jsdoc
      /**
       * Extract point to outside of obstacle in whichever direction is
       * closest. Returns new point outside obstacle.
       * @private
       */
      function extractFromObstacle(obstacle, point, goalPoint) {
          var dirIsX = min(obstacle.xMax - point.x, point.x - obstacle.xMin) <
              min(obstacle.yMax - point.y, point.y - obstacle.yMin), bounds = {
              soft: options.hardBounds,
              hard: options.hardBounds
          }, useMax = getDodgeDirection(obstacle, point, goalPoint, dirIsX, bounds);
          return dirIsX ? {
              y: point.y,
              x: obstacle[useMax ? 'xMax' : 'xMin'] + (useMax ? 1 : -1)
          } : {
              x: point.x,
              y: obstacle[useMax ? 'yMax' : 'yMin'] + (useMax ? 1 : -1)
          };
      }
  
      // Cut the obstacle array to soft bounds for optimization in large
      // datasets.
      chartObstacles =
          chartObstacles.slice(startObstacleIx, endObstacleIx + 1);
      // If an obstacle envelops the end point, move it out of there and add
      // a little segment to where it was.
      if ((endObstacleIx = findObstacleFromPoint(chartObstacles, end)) > -1) {
          extractedEndPoint = extractFromObstacle(chartObstacles[endObstacleIx], end, start);
          endSegments.push({
              end: end,
              start: extractedEndPoint
          });
          end = extractedEndPoint;
      }
      // If it's still inside one or more obstacles, get out of there by
      // force-moving towards the start point.
      while ((endObstacleIx = findObstacleFromPoint(chartObstacles, end)) > -1) {
          useMax = end[dir] - start[dir] < 0;
          extractedEndPoint = {
              x: end.x,
              y: end.y
          };
          extractedEndPoint[dir] = chartObstacles[endObstacleIx][useMax ? dir + 'Max' : dir + 'Min'] + (useMax ? 1 : -1);
          endSegments.push({
              end: end,
              start: extractedEndPoint
          });
          end = extractedEndPoint;
      }
      // Find the path
      segments = clearPathTo(start, end, dirIsX);
      // Add the end-point segments
      segments = segments.concat(endSegments.reverse());
      return {
          path: pathFromSegments(segments),
          obstacles: segments
      };
  }, {
      requiresObstacles: true
  });
  // Define the available pathfinding algorithms.
  // Algorithms take up to 3 arguments: starting point, ending point, and an
  // options object.
  var algorithms = {
      fastAvoid: fastAvoid,
      straight: straight,
      simpleConnect: simpleConnect
  };
  export default algorithms;
  