text: // https://github.com/topojson/topojson-server Version 3.0.0. Copyright 2017 Mike Bostock.
  (function (global, factory) {
  	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  	typeof define === 'function' && define.amd ? define(['exports'], factory) :
  	(factory((global.topojson = global.topojson || {})));
  }(this, (function (exports) { 'use strict';
  
  // Computes the bounding box of the specified hash of GeoJSON objects.
  var bounds = function(objects) {
    var x0 = Infinity,
        y0 = Infinity,
        x1 = -Infinity,
        y1 = -Infinity;
  
    function boundGeometry(geometry) {
      if (geometry != null && boundGeometryType.hasOwnProperty(geometry.type)) boundGeometryType[geometry.type](geometry);
    }
  
    var boundGeometryType = {
      GeometryCollection: function(o) { o.geometries.forEach(boundGeometry); },
      Point: function(o) { boundPoint(o.coordinates); },
      MultiPoint: function(o) { o.coordinates.forEach(boundPoint); },
      LineString: function(o) { boundLine(o.arcs); },
      MultiLineString: function(o) { o.arcs.forEach(boundLine); },
      Polygon: function(o) { o.arcs.forEach(boundLine); },
      MultiPolygon: function(o) { o.arcs.forEach(boundMultiLine); }
    };
  
    function boundPoint(coordinates) {
      var x = coordinates[0],
          y = coordinates[1];
      if (x < x0) x0 = x;
      if (x > x1) x1 = x;
      if (y < y0) y0 = y;
      if (y > y1) y1 = y;
    }
  
    function boundLine(coordinates) {
      coordinates.forEach(boundPoint);
    }
  
    function boundMultiLine(coordinates) {
      coordinates.forEach(boundLine);
    }
  
    for (var key in objects) {
      boundGeometry(objects[key]);
    }
  
    return x1 >= x0 && y1 >= y0 ? [x0, y0, x1, y1] : undefined;
  };
  
  var hashset = function(size, hash, equal, type, empty) {
    if (arguments.length === 3) {
      type = Array;
      empty = null;
    }
  
    var store = new type(size = 1 << Math.max(4, Math.ceil(Math.log(size) / Math.LN2))),
        mask = size - 1;
  
    for (var i = 0; i < size; ++i) {
      store[i] = empty;
    }
  
    function add(value) {
      var index = hash(value) & mask,
          match = store[index],
          collisions = 0;
      while (match != empty) {
        if (equal(match, value)) return true;
        if (++collisions >= size) throw new Error("full hashset");
        match = store[index = (index + 1) & mask];
      }
      store[index] = value;
      return true;
    }
  
    function has(value) {
      var index = hash(value) & mask,
          match = store[index],
          collisions = 0;
      while (match != empty) {
        if (equal(match, value)) return true;
        if (++collisions >= size) break;
        match = store[index = (index + 1) & mask];
      }
      return false;
    }
  
    function values() {
      var values = [];
      for (var i = 0, n = store.length; i < n; ++i) {
        var match = store[i];
        if (match != empty) values.push(match);
      }
      return values;
    }
  
    return {
      add: add,
      has: has,
      values: values
    };
  };
  
  var hashmap = function(size, hash, equal, keyType, keyEmpty, valueType) {
    if (arguments.length === 3) {
      keyType = valueType = Array;
      keyEmpty = null;
    }
  
    var keystore = new keyType(size = 1 << Math.max(4, Math.ceil(Math.log(size) / Math.LN2))),
        valstore = new valueType(size),
        mask = size - 1;
  
    for (var i = 0; i < size; ++i) {
      keystore[i] = keyEmpty;
    }
  
    function set(key, value) {
      var index = hash(key) & mask,
          matchKey = keystore[index],
          collisions = 0;
      while (matchKey != keyEmpty) {
        if (equal(matchKey, key)) return valstore[index] = value;
        if (++collisions >= size) throw new Error("full hashmap");
        matchKey = keystore[index = (index + 1) & mask];
      }
      keystore[index] = key;
      valstore[index] = value;
      return value;
    }
  
    function maybeSet(key, value) {
      var index = hash(key) & mask,
          matchKey = keystore[index],
          collisions = 0;
      while (matchKey != keyEmpty) {
        if (equal(matchKey, key)) return valstore[index];
        if (++collisions >= size) throw new Error("full hashmap");
        matchKey = keystore[index = (index + 1) & mask];
      }
      keystore[index] = key;
      valstore[index] = value;
      return value;
    }
  
    function get(key, missingValue) {
      var index = hash(key) & mask,
          matchKey = keystore[index],
          collisions = 0;
      while (matchKey != keyEmpty) {
        if (equal(matchKey, key)) return valstore[index];
        if (++collisions >= size) break;
        matchKey = keystore[index = (index + 1) & mask];
      }
      return missingValue;
    }
  
    function keys() {
      var keys = [];
      for (var i = 0, n = keystore.length; i < n; ++i) {
        var matchKey = keystore[i];
        if (matchKey != keyEmpty) keys.push(matchKey);
      }
      return keys;
    }
  
    return {
      set: set,
      maybeSet: maybeSet, // set if unset
      get: get,
      keys: keys
    };
  };
  
  var equalPoint = function(pointA, pointB) {
    return pointA[0] === pointB[0] && pointA[1] === pointB[1];
  };
  
  // TODO if quantized, use simpler Int32 hashing?
  
  var buffer = new ArrayBuffer(16);
  var floats = new Float64Array(buffer);
  var uints = new Uint32Array(buffer);
  
  var hashPoint = function(point) {
    floats[0] = point[0];
    floats[1] = point[1];
    var hash = uints[0] ^ uints[1];
    hash = hash << 5 ^ hash >> 7 ^ uints[2] ^ uints[3];
    return hash & 0x7fffffff;
  };
  
  // Given an extracted (pre-)topology, identifies all of the junctions. These are
  // the points at which arcs (lines or rings) will need to be cut so that each
  // arc is represented uniquely.
  //
  // A junction is a point where at least one arc deviates from another arc going
  // through the same point. For example, consider the point B. If there is a arc
  // through ABC and another arc through CBA, then B is not a junction because in
  // both cases the adjacent point pairs are {A,C}. However, if there is an
  // additional arc ABD, then {A,D} != {A,C}, and thus B becomes a junction.
  //
  // For a closed ring ABCA, the first point A’s adjacent points are the second
  // and last point {B,C}. For a line, the first and last point are always
  // considered junctions, even if the line is closed; this ensures that a closed
  // line is never rotated.
  var join = function(topology) {
    var coordinates = topology.coordinates,
        lines = topology.lines,
        rings = topology.rings,
        indexes = index(),
        visitedByIndex = new Int32Array(coordinates.length),
        leftByIndex = new Int32Array(coordinates.length),
        rightByIndex = new Int32Array(coordinates.length),
        junctionByIndex = new Int8Array(coordinates.length),
        junctionCount = 0, // upper bound on number of junctions
        i, n,
        previousIndex,
        currentIndex,
        nextIndex;
  
    for (i = 0, n = coordinates.length; i < n; ++i) {
      visitedByIndex[i] = leftByIndex[i] = rightByIndex[i] = -1;
    }
  
    for (i = 0, n = lines.length; i < n; ++i) {
      var line = lines[i],
          lineStart = line[0],
          lineEnd = line[1];
      currentIndex = indexes[lineStart];
      nextIndex = indexes[++lineStart];
      ++junctionCount, junctionByIndex[currentIndex] = 1; // start
      while (++lineStart <= lineEnd) {
        sequence(i, previousIndex = currentIndex, currentIndex = nextIndex, nextIndex = indexes[lineStart]);
      }
      ++junctionCount, junctionByIndex[nextIndex] = 1; // end
    }
  
    for (i = 0, n = coordinates.length; i < n; ++i) {
      visitedByIndex[i] = -1;
    }
  
    for (i = 0, n = rings.length; i < n; ++i) {
      var ring = rings[i],
          ringStart = ring[0] + 1,
          ringEnd = ring[1];
      previousIndex = indexes[ringEnd - 1];
      currentIndex = indexes[ringStart - 1];
      nextIndex = indexes[ringStart];
      sequence(i, previousIndex, currentIndex, nextIndex);
      while (++ringStart <= ringEnd) {
        sequence(i, previousIndex = currentIndex, currentIndex = nextIndex, nextIndex = indexes[ringStart]);
      }
    }
  
    function sequence(i, previousIndex, currentIndex, nextIndex) {
      if (visitedByIndex[currentIndex] === i) return; // ignore self-intersection
      visitedByIndex[currentIndex] = i;
      var leftIndex = leftByIndex[currentIndex];
      if (leftIndex >= 0) {
        var rightIndex = rightByIndex[currentIndex];
        if ((leftIndex !== previousIndex || rightIndex !== nextIndex)
          && (leftIndex !== nextIndex || rightIndex !== previousIndex)) {
          ++junctionCount, junctionByIndex[currentIndex] = 1;
        }
      } else {
        leftByIndex[currentIndex] = previousIndex;
        rightByIndex[currentIndex] = nextIndex;
      }
    }
  
    function index() {
      var indexByPoint = hashmap(coordinates.length * 1.4, hashIndex, equalIndex, Int32Array, -1, Int32Array),
          indexes = new Int32Array(coordinates.length);
  
      for (var i = 0, n = coordinates.length; i < n; ++i) {
        indexes[i] = indexByPoint.maybeSet(i, i);
      }
  
      return indexes;
    }
  
    function hashIndex(i) {
      return hashPoint(coordinates[i]);
    }
  
    function equalIndex(i, j) {
      return equalPoint(coordinates[i], coordinates[j]);
    }
  
    visitedByIndex = leftByIndex = rightByIndex = null;
  
    var junctionByPoint = hashset(junctionCount * 1.4, hashPoint, equalPoint), j;
  
    // Convert back to a standard hashset by point for caller convenience.
    for (i = 0, n = coordinates.length; i < n; ++i) {
      if (junctionByIndex[j = indexes[i]]) {
        junctionByPoint.add(coordinates[j]);
      }
    }
  
    return junctionByPoint;
  };
  
  // Given an extracted (pre-)topology, cuts (or rotates) arcs so that all shared
  // point sequences are identified. The topology can then be subsequently deduped
  // to remove exact duplicate arcs.
  var cut = function(topology) {
    var junctions = join(topology),
        coordinates = topology.coordinates,
        lines = topology.lines,
        rings = topology.rings,
        next,
        i, n;
  
    for (i = 0, n = lines.length; i < n; ++i) {
      var line = lines[i],
          lineMid = line[0],
          lineEnd = line[1];
      while (++lineMid < lineEnd) {
        if (junctions.has(coordinates[lineMid])) {
          next = {0: lineMid, 1: line[1]};
          line[1] = lineMid;
          line = line.next = next;
        }
      }
    }
  
    for (i = 0, n = rings.length; i < n; ++i) {
      var ring = rings[i],
          ringStart = ring[0],
          ringMid = ringStart,
          ringEnd = ring[1],
          ringFixed = junctions.has(coordinates[ringStart]);
      while (++ringMid < ringEnd) {
        if (junctions.has(coordinates[ringMid])) {
          if (ringFixed) {
            next = {0: ringMid, 1: ring[1]};
            ring[1] = ringMid;
            ring = ring.next = next;
          } else { // For the first junction, we can rotate rather than cut.
            rotateArray(coordinates, ringStart, ringEnd, ringEnd - ringMid);
            coordinates[ringEnd] = coordinates[ringStart];
            ringFixed = true;
            ringMid = ringStart; // restart; we may have skipped junctions
          }
        }
      }
    }
  
    return topology;
  };
  
  function rotateArray(array, start, end, offset) {
    reverse(array, start, end);
    reverse(array, start, start + offset);
    reverse(array, start + offset, end);
  }
  
  function reverse(array, start, end) {
    for (var mid = start + ((end-- - start) >> 1), t; start < mid; ++start, --end) {
      t = array[start], array[start] = array[end], array[end] = t;
    }
  }
  
  // Given a cut topology, combines duplicate arcs.
  var dedup = function(topology) {
    var coordinates = topology.coordinates,
        lines = topology.lines, line,
        rings = topology.rings, ring,
        arcCount = lines.length + rings.length,
        i, n;
  
    delete topology.lines;
    delete topology.rings;
  
    // Count the number of (non-unique) arcs to initialize the hashmap safely.
    for (i = 0, n = lines.length; i < n; ++i) {
      line = lines[i]; while (line = line.next) ++arcCount;
    }
    for (i = 0, n = rings.length; i < n; ++i) {
      ring = rings[i]; while (ring = ring.next) ++arcCount;
    }
  
    var arcsByEnd = hashmap(arcCount * 2 * 1.4, hashPoint, equalPoint),
        arcs = topology.arcs = [];
  
    for (i = 0, n = lines.length; i < n; ++i) {
      line = lines[i];
      do {
        dedupLine(line);
      } while (line = line.next);
    }
  
    for (i = 0, n = rings.length; i < n; ++i) {
      ring = rings[i];
      if (ring.next) { // arc is no longer closed
        do {
          dedupLine(ring);
        } while (ring = ring.next);
      } else {
        dedupRing(ring);
      }
    }
  
    function dedupLine(arc) {
      var startPoint,
          endPoint,
          startArcs, startArc,
          endArcs, endArc,
          i, n;
  
      // Does this arc match an existing arc in order?
      if (startArcs = arcsByEnd.get(startPoint = coordinates[arc[0]])) {
        for (i = 0, n = startArcs.length; i < n; ++i) {
          startArc = startArcs[i];
          if (equalLine(startArc, arc)) {
            arc[0] = startArc[0];
            arc[1] = startArc[1];
            return;
          }
        }
      }
  
      // Does this arc match an existing arc in reverse order?
      if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[1]])) {
        for (i = 0, n = endArcs.length; i < n; ++i) {
          endArc = endArcs[i];
          if (reverseEqualLine(endArc, arc)) {
            arc[1] = endArc[0];
            arc[0] = endArc[1];
            return;
          }
        }
      }
  
      if (startArcs) startArcs.push(arc); else arcsByEnd.set(startPoint, [arc]);
      if (endArcs) endArcs.push(arc); else arcsByEnd.set(endPoint, [arc]);
      arcs.push(arc);
    }
  
    function dedupRing(arc) {
      var endPoint,
          endArcs,
          endArc,
          i, n;
  
      // Does this arc match an existing line in order, or reverse order?
      // Rings are closed, so their start point and end point is the same.
      if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[0]])) {
        for (i = 0, n = endArcs.length; i < n; ++i) {
          endArc = endArcs[i];
          if (equalRing(endArc, arc)) {
            arc[0] = endArc[0];
            arc[1] = endArc[1];
            return;
          }
          if (reverseEqualRing(endArc, arc)) {
            arc[0] = endArc[1];
            arc[1] = endArc[0];
            return;
          }
        }
      }
  
      // Otherwise, does this arc match an existing ring in order, or reverse order?
      if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[0] + findMinimumOffset(arc)])) {
        for (i = 0, n = endArcs.length; i < n; ++i) {
          endArc = endArcs[i];
          if (equalRing(endArc, arc)) {
            arc[0] = endArc[0];
            arc[1] = endArc[1];
            return;
          }
          if (reverseEqualRing(endArc, arc)) {
            arc[0] = endArc[1];
            arc[1] = endArc[0];
            return;
          }
        }
      }
  
      if (endArcs) endArcs.push(arc); else arcsByEnd.set(endPoint, [arc]);
      arcs.push(arc);
    }
  
    function equalLine(arcA, arcB) {
      var ia = arcA[0], ib = arcB[0],
          ja = arcA[1], jb = arcB[1];
      if (ia - ja !== ib - jb) return false;
      for (; ia <= ja; ++ia, ++ib) if (!equalPoint(coordinates[ia], coordinates[ib])) return false;
      return true;
    }
  
    function reverseEqualLine(arcA, arcB) {
      var ia = arcA[0], ib = arcB[0],
          ja = arcA[1], jb = arcB[1];
      if (ia - ja !== ib - jb) return false;
      for (; ia <= ja; ++ia, --jb) if (!equalPoint(coordinates[ia], coordinates[jb])) return false;
      return true;
    }
  
    function equalRing(arcA, arcB) {
      var ia = arcA[0], ib = arcB[0],
          ja = arcA[1], jb = arcB[1],
          n = ja - ia;
      if (n !== jb - ib) return false;
      var ka = findMinimumOffset(arcA),
          kb = findMinimumOffset(arcB);
      for (var i = 0; i < n; ++i) {
        if (!equalPoint(coordinates[ia + (i + ka) % n], coordinates[ib + (i + kb) % n])) return false;
      }
      return true;
    }
  
    function reverseEqualRing(arcA, arcB) {
      var ia = arcA[0], ib = arcB[0],
          ja = arcA[1], jb = arcB[1],
          n = ja - ia;
      if (n !== jb - ib) return false;
      var ka = findMinimumOffset(arcA),
          kb = n - findMinimumOffset(arcB);
      for (var i = 0; i < n; ++i) {
        if (!equalPoint(coordinates[ia + (i + ka) % n], coordinates[jb - (i + kb) % n])) return false;
      }
      return true;
    }
  
    // Rings are rotated to a consistent, but arbitrary, start point.
    // This is necessary to detect when a ring and a rotated copy are dupes.
    function findMinimumOffset(arc) {
      var start = arc[0],
          end = arc[1],
          mid = start,
          minimum = mid,
          minimumPoint = coordinates[mid];
      while (++mid < end) {
        var point = coordinates[mid];
        if (point[0] < minimumPoint[0] || point[0] === minimumPoint[0] && point[1] < minimumPoint[1]) {
          minimum = mid;
          minimumPoint = point;
        }
      }
      return minimum - start;
    }
  
    return topology;
  };
  
  // Given an array of arcs in absolute (but already quantized!) coordinates,
  // converts to fixed-point delta encoding.
  // This is a destructive operation that modifies the given arcs!
  var delta = function(arcs) {
    var i = -1,
        n = arcs.length;
  
    while (++i < n) {
      var arc = arcs[i],
          j = 0,
          k = 1,
          m = arc.length,
          point = arc[0],
          x0 = point[0],
          y0 = point[1],
          x1,
          y1;
  
      while (++j < m) {
        point = arc[j], x1 = point[0], y1 = point[1];
        if (x1 !== x0 || y1 !== y0) arc[k++] = [x1 - x0, y1 - y0], x0 = x1, y0 = y1;
      }
  
      if (k === 1) arc[k++] = [0, 0]; // Each arc must be an array of two or more positions.
  
      arc.length = k;
    }
  
    return arcs;
  };
  
  // Extracts the lines and rings from the specified hash of geometry objects.
  //
  // Returns an object with three properties:
  //
  // * coordinates - shared buffer of [x, y] coordinates
  // * lines - lines extracted from the hash, of the form [start, end]
  // * rings - rings extracted from the hash, of the form [start, end]
  //
  // For each ring or line, start and end represent inclusive indexes into the
  // coordinates buffer. For rings (and closed lines), coordinates[start] equals
  // coordinates[end].
  //
  // For each line or polygon geometry in the input hash, including nested
  // geometries as in geometry collections, the `coordinates` array is replaced
  // with an equivalent `arcs` array that, for each line (for line string
  // geometries) or ring (for polygon geometries), points to one of the above
  // lines or rings.
  var extract = function(objects) {
    var index = -1,
        lines = [],
        rings = [],
        coordinates = [];
  
    function extractGeometry(geometry) {
      if (geometry && extractGeometryType.hasOwnProperty(geometry.type)) extractGeometryType[geometry.type](geometry);
    }
  
    var extractGeometryType = {
      GeometryCollection: function(o) { o.geometries.forEach(extractGeometry); },
      LineString: function(o) { o.arcs = extractLine(o.arcs); },
      MultiLineString: function(o) { o.arcs = o.arcs.map(extractLine); },
      Polygon: function(o) { o.arcs = o.arcs.map(extractRing); },
      MultiPolygon: function(o) { o.arcs = o.arcs.map(extractMultiRing); }
    };
  
    function extractLine(line) {
      for (var i = 0, n = line.length; i < n; ++i) coordinates[++index] = line[i];
      var arc = {0: index - n + 1, 1: index};
      lines.push(arc);
      return arc;
    }
  
    function extractRing(ring) {
      for (var i = 0, n = ring.length; i < n; ++i) coordinates[++index] = ring[i];
      var arc = {0: index - n + 1, 1: index};
      rings.push(arc);
      return arc;
    }
  
    function extractMultiRing(rings) {
      return rings.map(extractRing);
    }
  
    for (var key in objects) {
      extractGeometry(objects[key]);
    }
  
    return {
      type: "Topology",
      coordinates: coordinates,
      lines: lines,
      rings: rings,
      objects: objects
    };
  };
  
  // Given a hash of GeoJSON objects, returns a hash of GeoJSON geometry objects.
  // Any null input geometry objects are represented as {type: null} in the output.
  // Any feature.{id,properties,bbox} are transferred to the output geometry object.
  // Each output geometry object is a shallow copy of the input (e.g., properties, coordinates)!
  var geometry = function(inputs) {
    var outputs = {}, key;
    for (key in inputs) outputs[key] = geomifyObject(inputs[key]);
    return outputs;
  };
  
  function geomifyObject(input) {
    return input == null ? {type: null}
        : (input.type === "FeatureCollection" ? geomifyFeatureCollection
        : input.type === "Feature" ? geomifyFeature
        : geomifyGeometry)(input);
  }
  
  function geomifyFeatureCollection(input) {
    var output = {type: "GeometryCollection", geometries: input.features.map(geomifyFeature)};
    if (input.bbox != null) output.bbox = input.bbox;
    return output;
  }
  
  function geomifyFeature(input) {
    var output = geomifyGeometry(input.geometry), key; // eslint-disable-line no-unused-vars
    if (input.id != null) output.id = input.id;
    if (input.bbox != null) output.bbox = input.bbox;
    for (key in input.properties) { output.properties = input.properties; break; }
    return output;
  }
  
  function geomifyGeometry(input) {
    if (input == null) return {type: null};
    var output = input.type === "GeometryCollection" ? {type: "GeometryCollection", geometries: input.geometries.map(geomifyGeometry)}
        : input.type === "Point" || input.type === "MultiPoint" ? {type: input.type, coordinates: input.coordinates}
        : {type: input.type, arcs: input.coordinates}; // TODO Check for unknown types?
    if (input.bbox != null) output.bbox = input.bbox;
    return output;
  }
  
  var prequantize = function(objects, bbox, n) {
    var x0 = bbox[0],
        y0 = bbox[1],
        x1 = bbox[2],
        y1 = bbox[3],
        kx = x1 - x0 ? (n - 1) / (x1 - x0) : 1,
        ky = y1 - y0 ? (n - 1) / (y1 - y0) : 1;
  
    function quantizePoint(input) {
      return [Math.round((input[0] - x0) * kx), Math.round((input[1] - y0) * ky)];
    }
  
    function quantizePoints(input, m) {
      var i = -1,
          j = 0,
          n = input.length,
          output = new Array(n), // pessimistic
          pi,
          px,
          py,
          x,
          y;
  
      while (++i < n) {
        pi = input[i];
        x = Math.round((pi[0] - x0) * kx);
        y = Math.round((pi[1] - y0) * ky);
        if (x !== px || y !== py) output[j++] = [px = x, py = y]; // non-coincident points
      }
  
      output.length = j;
      while (j < m) j = output.push([output[0][0], output[0][1]]);
      return output;
    }
  
    function quantizeLine(input) {
      return quantizePoints(input, 2);
    }
  
    function quantizeRing(input) {
      return quantizePoints(input, 4);
    }
  
    function quantizePolygon(input) {
      return input.map(quantizeRing);
    }
  
    function quantizeGeometry(o) {
      if (o != null && quantizeGeometryType.hasOwnProperty(o.type)) quantizeGeometryType[o.type](o);
    }
  
    var quantizeGeometryType = {
      GeometryCollection: function(o) { o.geometries.forEach(quantizeGeometry); },
      Point: function(o) { o.coordinates = quantizePoint(o.coordinates); },
      MultiPoint: function(o) { o.coordinates = o.coordinates.map(quantizePoint); },
      LineString: function(o) { o.arcs = quantizeLine(o.arcs); },
      MultiLineString: function(o) { o.arcs = o.arcs.map(quantizeLine); },
      Polygon: function(o) { o.arcs = quantizePolygon(o.arcs); },
      MultiPolygon: function(o) { o.arcs = o.arcs.map(quantizePolygon); }
    };
  
    for (var key in objects) {
      quantizeGeometry(objects[key]);
    }
  
    return {
      scale: [1 / kx, 1 / ky],
      translate: [x0, y0]
    };
  };
  
  // Constructs the TopoJSON Topology for the specified hash of features.
  // Each object in the specified hash must be a GeoJSON object,
  // meaning FeatureCollection, a Feature or a geometry object.
  var topology = function(objects, quantization) {
    var bbox = bounds(objects = geometry(objects)),
        transform = quantization > 0 && bbox && prequantize(objects, bbox, quantization),
        topology = dedup(cut(extract(objects))),
        coordinates = topology.coordinates,
        indexByArc = hashmap(topology.arcs.length * 1.4, hashArc, equalArc);
  
    objects = topology.objects; // for garbage collection
    topology.bbox = bbox;
    topology.arcs = topology.arcs.map(function(arc, i) {
      indexByArc.set(arc, i);
      return coordinates.slice(arc[0], arc[1] + 1);
    });
  
    delete topology.coordinates;
    coordinates = null;
  
    function indexGeometry(geometry$$1) {
      if (geometry$$1 && indexGeometryType.hasOwnProperty(geometry$$1.type)) indexGeometryType[geometry$$1.type](geometry$$1);
    }
  
    var indexGeometryType = {
      GeometryCollection: function(o) { o.geometries.forEach(indexGeometry); },
      LineString: function(o) { o.arcs = indexArcs(o.arcs); },
      MultiLineString: function(o) { o.arcs = o.arcs.map(indexArcs); },
      Polygon: function(o) { o.arcs = o.arcs.map(indexArcs); },
      MultiPolygon: function(o) { o.arcs = o.arcs.map(indexMultiArcs); }
    };
  
    function indexArcs(arc) {
      var indexes = [];
      do {
        var index = indexByArc.get(arc);
        indexes.push(arc[0] < arc[1] ? index : ~index);
      } while (arc = arc.next);
      return indexes;
    }
  
    function indexMultiArcs(arcs) {
      return arcs.map(indexArcs);
    }
  
    for (var key in objects) {
      indexGeometry(objects[key]);
    }
  
    if (transform) {
      topology.transform = transform;
      topology.arcs = delta(topology.arcs);
    }
  
    return topology;
  };
  
  function hashArc(arc) {
    var i = arc[0], j = arc[1], t;
    if (j < i) t = i, i = j, j = t;
    return i + 31 * j;
  }
  
  function equalArc(arcA, arcB) {
    var ia = arcA[0], ja = arcA[1],
        ib = arcB[0], jb = arcB[1], t;
    if (ja < ia) t = ia, ia = ja, ja = t;
    if (jb < ib) t = ib, ib = jb, jb = t;
    return ia === ib && ja === jb;
  }
  
  exports.topology = topology;
  
  Object.defineProperty(exports, '__esModule', { value: true });
  
  })));
  