text: 'use strict';
  
  Object.defineProperty(exports, '__esModule', {
    value: true
  });
  
  var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
  
  var _ops = require('./ops');
  
  var average = function average(body1, body2) {
    var mass = body1.mass + body2.mass;
    var point = (0, _ops.times)(1 / mass, (0, _ops.plus)((0, _ops.times)(body1.mass, body1.point), (0, _ops.times)(body2.mass, body2.point)));
    return [point, mass];
  };
  
  var locate = function locate(_ref, quadrants) {
    var _ref2 = _slicedToArray(_ref, 2);
  
    var x = _ref2[0];
    var y = _ref2[1];
    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;
  
    try {
      for (var _iterator = quadrants[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
        var q = _step.value;
        var _q$box = q.box;
        var _top = _q$box.top;
        var bottom = _q$box.bottom;
        var left = _q$box.left;
        var right = _q$box.right;
  
        if (left <= x && x <= right && bottom <= y && y <= _top) {
          return q;
        }
      }
    } catch (err) {
      _didIteratorError = true;
      _iteratorError = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion && _iterator['return']) {
          _iterator['return']();
        }
      } finally {
        if (_didIteratorError) {
          throw _iteratorError;
        }
      }
    }
  };
  
  var makeQuadrant = function makeQuadrant(_ref3, _ref4) {
    var top = _ref3.top;
    var bottom = _ref3.bottom;
    var left = _ref3.left;
    var right = _ref3.right;
  
    var _ref42 = _slicedToArray(_ref4, 2);
  
    var a = _ref42[0];
    var b = _ref42[1];
  
    var halfwayV = (left + right) / 2;
    var halfwayH = (top + bottom) / 2;
  
    return {
      box: {
        top: b ? halfwayH : top,
        bottom: b ? bottom : halfwayH,
        left: a ? halfwayV : left,
        right: a ? right : halfwayV
      }
    };
  };
  
  var subdivide = function subdivide(_ref5) {
    var box = _ref5.box;
    return [makeQuadrant(box, [0, 0]), makeQuadrant(box, [1, 0]), makeQuadrant(box, [0, 1]), makeQuadrant(box, [1, 1])];
  };
  
  var addBody = function addBody(root, body) {
    if (root.body) {
      var oldBody = root.body;
      delete root.body;
      root.children = subdivide(root);
      addBody(root, oldBody);
      addBody(root, body);
    } else {
      if (root.children) {
        var child = locate(body.point, root.children);
  
        var _ref6 = root.point ? average(root, body) : [body.point, body.mass];
  
        var _ref62 = _slicedToArray(_ref6, 2);
  
        var p = _ref62[0];
        var m = _ref62[1];
  
        root.point = p;
        root.mass = m;
        addBody(child, body);
      } else {
        root.body = body;
      }
    }
  };
  
  var makeTree = function makeTree(_x, _x2) {
    var _again = true;
  
    _function: while (_again) {
      var bodies = _x,
          root = _x2;
      body = undefined;
      _again = false;
  
      if (bodies.length === 0) {
        return root;
      } else {
        var body = bodies.shift();
        addBody(root, body);
        _x = bodies;
        _x2 = root;
        _again = true;
        continue _function;
      }
    }
  };
  
  var makeBodies = function makeBodies(positions) {
    return (0, _ops.mapObject)(positions, function (id, position) {
      return { id: id, point: position, mass: 1 };
    });
  };
  
  var makeRoot = function makeRoot(width, height) {
    return {
      box: {
        top: height,
        bottom: 0,
        left: 0,
        right: width
      }
    };
  };
  
  var walkLeaves = function walkLeaves(tree, f) {
    if (tree.body) {
      f(tree);
    } else {
      if (tree.children) {
        var _iteratorNormalCompletion2 = true;
        var _didIteratorError2 = false;
        var _iteratorError2 = undefined;
  
        try {
          for (var _iterator2 = tree.children[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
            var child = _step2.value;
  
            walkLeaves(child, f);
          }
        } catch (err) {
          _didIteratorError2 = true;
          _iteratorError2 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion2 && _iterator2['return']) {
              _iterator2['return']();
            }
          } finally {
            if (_didIteratorError2) {
              throw _iteratorError2;
            }
          }
        }
      }
    }
  };
  
  var bodyForceOn = function bodyForceOn(b1, b2, repulsion) {
    var segment = (0, _ops.minus)(b1.point, b2.point);
    var d = (0, _ops.length)(segment);
    return (0, _ops.times)(repulsion * b1.mass * b2.mass / (d * d * d), segment);
  };
  
  var boxWidth = function boxWidth(_ref7) {
    var top = _ref7.top;
    var bottom = _ref7.bottom;
    var left = _ref7.left;
    var right = _ref7.right;
    return (0, _ops.length)([top - bottom, right - left]);
  };
  
  var forceOn = function forceOn(leaf, tree, repulsion, threshold) {
    if (tree === leaf) {
      return [0, 0];
    } else if (tree.body) {
      return bodyForceOn(leaf.body, tree.body, repulsion);
    } else if (tree.point) {
      var s = boxWidth(tree.box);
      var d = (0, _ops.length)((0, _ops.minus)(leaf.body.point, tree.point));
  
      if (s / d < threshold) {
        return bodyForceOn(leaf.body, tree, repulsion);
      } else return (0, _ops.sumVectors)(tree.children.map(function (c) {
        return forceOn(leaf, c, repulsion, threshold);
      }));
    } else return [0, 0];
  };
  
  var repulsiveForces = function repulsiveForces(tree, repulsion, threshold) {
    var forces = {};
    walkLeaves(tree, function (leaf) {
      forces[leaf.body.id] = forceOn(leaf, tree, repulsion, threshold);
    });
    return forces;
  };
  
  exports.tree = makeTree;
  exports.bodies = makeBodies;
  exports.root = makeRoot;
  exports.forces = repulsiveForces;
  exports['default'] = {
    tree: makeTree,
    bodies: makeBodies,
    root: makeRoot,
    forces: repulsiveForces
  };