imported latest release of markercluster from google
authorThierry Parmentelat <thierry.parmentelat@inria.fr>
Tue, 17 Sep 2013 09:42:44 +0000 (11:42 +0200)
committerThierry Parmentelat <thierry.parmentelat@inria.fr>
Tue, 17 Sep 2013 09:42:44 +0000 (11:42 +0200)
Makefile
plugins/googlemaps/static/js/markerclusterer.js [deleted file]
plugins/googlemaps/static/js/markerclusterer_compiled.js [deleted file]
plugins/googlemaps/static/js/markerclusterer_packed.js [deleted file]
third-party/markerclusterer/markerclusterer-2.0.16.js [new file with mode: 0644]
third-party/markerclusterer/markerclusterer-2.0.16.js.url [new file with mode: 0644]
third-party/markerclusterer/markerclusterer-2.0.16_packed.js [new file with mode: 0644]
third-party/markerclusterer/markerclusterer-2.0.16_packed.js.url [new file with mode: 0644]
third-party/markerclusterer/markerclusterer.js [new symlink]
third-party/markerclusterer/markerclusterer_packed.js [new symlink]

index 235336b..d011fe4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -95,7 +95,9 @@ THIRD-PARTY-RESOURCES += $(shell ls third-party/codemirror-3.15/lib/codemirror.c
 THIRD-PARTY-RESOURCES += $(shell ls third-party/codemirror-3.15/mode/sql/sql.js)
 # Mustache.js
 THIRD-PARTY-RESOURCES += $(shell ls third-party/mustache/mustache.js)
-
+# markerclustererplus for the googlemap plugin
+THIRD-PARTY-RESOURCES += $(shell ls third-party/markerclusterer/markerclusterer.js)
+THIRD-PARTY-RESOURCES += $(shell ls third-party/markerclusterer/markerclusterer_packed.js)
 
 thirdparty-js:
        @find $(THIRD-PARTY-RESOURCES) -name '*.js'
diff --git a/plugins/googlemaps/static/js/markerclusterer.js b/plugins/googlemaps/static/js/markerclusterer.js
deleted file mode 100644 (file)
index 8ac6d8f..0000000
+++ /dev/null
@@ -1,1137 +0,0 @@
-// ==ClosureCompiler==
-// @compilation_level ADVANCED_OPTIMIZATIONS
-// @externs_url http://closure-compiler.googlecode.com/svn/trunk/contrib/externs/maps/google_maps_api_v3.js
-// ==/ClosureCompiler==
-
-/**
- * @name MarkerClusterer for Google Maps v3
- * @version version 1.0
- * @author Luke Mahe
- * @fileoverview
- * The library creates and manages per-zoom-level clusters for large amounts of
- * markers.
- * <br/>
- * This is a v3 implementation of the
- * <a href="http://gmaps-utility-library-dev.googlecode.com/svn/tags/markerclusterer/"
- * >v2 MarkerClusterer</a>.
- */
-
-/**
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-/**
- * A Marker Clusterer that clusters markers.
- *
- * @param {google.maps.Map} map The Google map to attach to.
- * @param {Array.<google.maps.Marker>} opt_markers Optional markers to add to
- *   the cluster.
- * @param {Object} opt_options support the following options:
- *     'gridSize': (number) The grid size of a cluster in pixels.
- *     'maxZoom': (number) The maximum zoom level that a marker can be part of a
- *                cluster.
- *     'zoomOnClick': (boolean) Whether the default behaviour of clicking on a
- *                    cluster is to zoom into it.
- *     'averageCenter': (boolean) Wether the center of each cluster should be
- *                      the average of all markers in the cluster.
- *     'styles': (object) An object that has style properties:
- *       'url': (string) The image url.
- *       'height': (number) The image height.
- *       'width': (number) The image width.
- *       'anchor': (Array) The anchor position of the label text.
- *       'textColor': (string) The text color.
- *       'textSize': (number) The text size.
- * @constructor
- * @extends google.maps.OverlayView
- */
-function MarkerClusterer(map, opt_markers, opt_options) {
-  // MarkerClusterer implements google.maps.OverlayView interface. We use the
-  // extend function to extend MarkerClusterer with google.maps.OverlayView
-  // because it might not always be available when the code is defined so we
-  // look for it at the last possible moment. If it doesn't exist now then
-  // there is no point going ahead :)
-  this.extend(MarkerClusterer, google.maps.OverlayView);
-  this.map_ = map;
-
-  /**
-   * @type {Array.<google.maps.Marker>}
-   * @private
-   */
-  this.markers_ = [];
-
-  /**
-   *  @type {Array.<Cluster>}
-   */
-  this.clusters_ = [];
-
-  this.sizes = [53, 56, 66, 78, 90];
-
-  /**
-   * @private
-   */
-  this.styles_ = [];
-
-  /**
-   * @type {boolean}
-   * @private
-   */
-  this.ready_ = false;
-
-  var options = opt_options || {};
-
-  /**
-   * @type {number}
-   * @private
-   */
-  this.gridSize_ = options['gridSize'] || 60;
-
-  /**
-   * @type {?number}
-   * @private
-   */
-  this.maxZoom_ = options['maxZoom'] || null;
-
-  this.styles_ = options['styles'] || [];
-
-  /**
-   * @type {string}
-   * @private
-   */
-  this.imagePath_ = options['imagePath'] ||
-      this.MARKER_CLUSTER_IMAGE_PATH_;
-
-  /**
-   * @type {string}
-   * @private
-   */
-  this.imageExtension_ = options['imageExtension'] ||
-      this.MARKER_CLUSTER_IMAGE_EXTENSION_;
-
-  /**
-   * @type {boolean}
-   * @private
-   */
-  this.zoomOnClick_ = true;
-
-  if (options['zoomOnClick'] != undefined) {
-    this.zoomOnClick_ = options['zoomOnClick'];
-  }
-
-  /**
-   * @type {boolean}
-   * @private
-   */
-  this.averageCenter_ = false;
-
-  if (options['averageCenter'] != undefined) {
-    this.averageCenter_ = options['averageCenter'];
-  }
-
-  this.setupStyles_();
-
-  this.setMap(map);
-
-  /**
-   * @type {number}
-   * @private
-   */
-  this.prevZoom_ = this.map_.getZoom();
-
-  // Add the map event listeners
-  var that = this;
-  google.maps.event.addListener(this.map_, 'zoom_changed', function() {
-    var maxZoom = that.map_.mapTypes[that.map_.getMapTypeId()].maxZoom;
-    var zoom = that.map_.getZoom();
-    if (zoom < 0 || zoom > maxZoom) {
-      return;
-    }
-
-    if (that.prevZoom_ != zoom) {
-      that.prevZoom_ = that.map_.getZoom();
-      that.resetViewport();
-    }
-  });
-
-  google.maps.event.addListener(this.map_, 'idle', function() {
-    that.redraw();
-  });
-
-  // Finally, add the markers
-  if (opt_markers && opt_markers.length) {
-    this.addMarkers(opt_markers, false);
-  }
-}
-
-
-/**
- * The marker cluster image path.
- *
- * @type {string}
- * @private
- */
-MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_PATH_ =
-    'http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/' +
-    'images/m';
-
-
-/**
- * The marker cluster image path.
- *
- * @type {string}
- * @private
- */
-MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_EXTENSION_ = 'png';
-
-
-/**
- * Extends a objects prototype by anothers.
- *
- * @param {Object} obj1 The object to be extended.
- * @param {Object} obj2 The object to extend with.
- * @return {Object} The new extended object.
- * @ignore
- */
-MarkerClusterer.prototype.extend = function(obj1, obj2) {
-  return (function(object) {
-    for (property in object.prototype) {
-      this.prototype[property] = object.prototype[property];
-    }
-    return this;
-  }).apply(obj1, [obj2]);
-};
-
-
-/**
- * Implementaion of the interface method.
- * @ignore
- */
-MarkerClusterer.prototype.onAdd = function() {
-  this.setReady_(true);
-};
-
-
-/**
- * Implementation of the interface.
- * @ignore
- */
-MarkerClusterer.prototype.draw = function() {};
-
-
-/**
- * Sets up the styles object.
- *
- * @private
- */
-MarkerClusterer.prototype.setupStyles_ = function() {
-  if (this.styles_.length) {
-    return;
-  }
-
-  for (var i = 0, size; size = this.sizes[i]; i++) {
-    this.styles_.push({
-      url: this.imagePath_ + (i + 1) + '.' + this.imageExtension_,
-      height: size,
-      width: size
-    });
-  }
-};
-
-
-/**
- *  Sets the styles.
- *
- *  @param {Object} styles The style to set.
- */
-MarkerClusterer.prototype.setStyles = function(styles) {
-  this.styles_ = styles;
-};
-
-
-/**
- *  Gets the styles.
- *
- *  @return {Object} The styles object.
- */
-MarkerClusterer.prototype.getStyles = function() {
-  return this.styles_;
-};
-
-
-/**
- * Whether zoom on click is set.
- *
- * @return {boolean} True if zoomOnClick_ is set.
- */
-MarkerClusterer.prototype.isZoomOnClick = function() {
-  return this.zoomOnClick_;
-};
-
-/**
- * Whether average center is set.
- *
- * @return {boolean} True if averageCenter_ is set.
- */
-MarkerClusterer.prototype.isAverageCenter = function() {
-  return this.averageCenter_;
-};
-
-
-/**
- *  Returns the array of markers in the clusterer.
- *
- *  @return {Array.<google.maps.Marker>} The markers.
- */
-MarkerClusterer.prototype.getMarkers = function() {
-  return this.markers_;
-};
-
-
-/**
- *  Returns the array of markers in the clusterer.
- *
- *  @return {Array.<google.maps.Marker>} The number of markers.
- */
-MarkerClusterer.prototype.getTotalMarkers = function() {
-  return this.markers_;
-};
-
-
-/**
- *  Sets the max zoom for the clusterer.
- *
- *  @param {number} maxZoom The max zoom level.
- */
-MarkerClusterer.prototype.setMaxZoom = function(maxZoom) {
-  this.maxZoom_ = maxZoom;
-};
-
-
-/**
- *  Gets the max zoom for the clusterer.
- *
- *  @return {number} The max zoom level.
- */
-MarkerClusterer.prototype.getMaxZoom = function() {
-  return this.maxZoom_ || this.map_.mapTypes[this.map_.getMapTypeId()].maxZoom;
-};
-
-
-/**
- *  The function for calculating the cluster icon image.
- *
- *  @param {Array.<google.maps.Marker>} markers The markers in the clusterer.
- *  @param {number} numStyles The number of styles available.
- *  @return {Object} A object properties: 'text' (string) and 'index' (number).
- *  @private
- */
-MarkerClusterer.prototype.calculator_ = function(markers, numStyles) {
-  var index = 0;
-  var count = markers.length;
-  var dv = count;
-  while (dv !== 0) {
-    dv = parseInt(dv / 10, 10);
-    index++;
-  }
-
-  index = Math.min(index, numStyles);
-  return {
-    text: count,
-    index: index
-  };
-};
-
-
-/**
- * Set the calculator function.
- *
- * @param {function(Array, number)} calculator The function to set as the
- *     calculator. The function should return a object properties:
- *     'text' (string) and 'index' (number).
- *
- */
-MarkerClusterer.prototype.setCalculator = function(calculator) {
-  this.calculator_ = calculator;
-};
-
-
-/**
- * Get the calculator function.
- *
- * @return {function(Array, number)} the calculator function.
- */
-MarkerClusterer.prototype.getCalculator = function() {
-  return this.calculator_;
-};
-
-
-/**
- * Add an array of markers to the clusterer.
- *
- * @param {Array.<google.maps.Marker>} markers The markers to add.
- * @param {boolean} opt_nodraw Whether to redraw the clusters.
- */
-MarkerClusterer.prototype.addMarkers = function(markers, opt_nodraw) {
-  for (var i = 0, marker; marker = markers[i]; i++) {
-    this.pushMarkerTo_(marker);
-  }
-  if (!opt_nodraw) {
-    this.redraw();
-  }
-};
-
-
-/**
- * Pushes a marker to the clusterer.
- *
- * @param {google.maps.Marker} marker The marker to add.
- * @private
- */
-MarkerClusterer.prototype.pushMarkerTo_ = function(marker) {
-  marker.setVisible(false);
-  marker.setMap(null);
-  marker.isAdded = false;
-  if (marker['draggable']) {
-    // If the marker is draggable add a listener so we update the clusters on
-    // the drag end.
-    var that = this;
-    google.maps.event.addListener(marker, 'dragend', function() {
-      marker.isAdded = false;
-      that.resetViewport();
-      that.redraw();
-    });
-  }
-  this.markers_.push(marker);
-};
-
-
-/**
- * Adds a marker to the clusterer and redraws if needed.
- *
- * @param {google.maps.Marker} marker The marker to add.
- * @param {boolean} opt_nodraw Whether to redraw the clusters.
- */
-MarkerClusterer.prototype.addMarker = function(marker, opt_nodraw) {
-  this.pushMarkerTo_(marker);
-  if (!opt_nodraw) {
-    this.redraw();
-  }
-};
-
-
-/**
- * Remove a marker from the cluster.
- *
- * @param {google.maps.Marker} marker The marker to remove.
- * @return {boolean} True if the marker was removed.
- */
-MarkerClusterer.prototype.removeMarker = function(marker) {
-  var index = -1;
-  if (this.markers_.indexOf) {
-    index = this.markers_.indexOf(marker);
-  } else {
-    for (var i = 0, m; m = this.markers_[i]; i++) {
-      if (m == marker) {
-        index = i;
-        continue;
-      }
-    }
-  }
-
-  if (index == -1) {
-    // Marker is not in our list of markers.
-    return false;
-  }
-
-  this.markers_.splice(index, 1);
-  marker.setVisible(false);
-  marker.setMap(null);
-
-  this.resetViewport();
-  this.redraw();
-  return true;
-};
-
-
-/**
- * Sets the clusterer's ready state.
- *
- * @param {boolean} ready The state.
- * @private
- */
-MarkerClusterer.prototype.setReady_ = function(ready) {
-  if (!this.ready_) {
-    this.ready_ = ready;
-    this.createClusters_();
-  }
-};
-
-
-/**
- * Returns the number of clusters in the clusterer.
- *
- * @return {number} The number of clusters.
- */
-MarkerClusterer.prototype.getTotalClusters = function() {
-  return this.clusters_.length;
-};
-
-
-/**
- * Returns the google map that the clusterer is associated with.
- *
- * @return {google.maps.Map} The map.
- */
-MarkerClusterer.prototype.getMap = function() {
-  return this.map_;
-};
-
-
-/**
- * Sets the google map that the clusterer is associated with.
- *
- * @param {google.maps.Map} map The map.
- */
-MarkerClusterer.prototype.setMap = function(map) {
-  this.map_ = map;
-};
-
-
-/**
- * Returns the size of the grid.
- *
- * @return {number} The grid size.
- */
-MarkerClusterer.prototype.getGridSize = function() {
-  return this.gridSize_;
-};
-
-
-/**
- * Returns the size of the grid.
- *
- * @param {number} size The grid size.
- */
-MarkerClusterer.prototype.setGridSize = function(size) {
-  this.gridSize_ = size;
-};
-
-
-/**
- * Extends a bounds object by the grid size.
- *
- * @param {google.maps.LatLngBounds} bounds The bounds to extend.
- * @return {google.maps.LatLngBounds} The extended bounds.
- */
-MarkerClusterer.prototype.getExtendedBounds = function(bounds) {
-  var projection = this.getProjection();
-
-  // Turn the bounds into latlng.
-  var tr = new google.maps.LatLng(bounds.getNorthEast().lat(),
-      bounds.getNorthEast().lng());
-  var bl = new google.maps.LatLng(bounds.getSouthWest().lat(),
-      bounds.getSouthWest().lng());
-
-  // Convert the points to pixels and the extend out by the grid size.
-  var trPix = projection.fromLatLngToDivPixel(tr);
-  trPix.x += this.gridSize_;
-  trPix.y -= this.gridSize_;
-
-  var blPix = projection.fromLatLngToDivPixel(bl);
-  blPix.x -= this.gridSize_;
-  blPix.y += this.gridSize_;
-
-  // Convert the pixel points back to LatLng
-  var ne = projection.fromDivPixelToLatLng(trPix);
-  var sw = projection.fromDivPixelToLatLng(blPix);
-
-  // Extend the bounds to contain the new bounds.
-  bounds.extend(ne);
-  bounds.extend(sw);
-
-  return bounds;
-};
-
-
-/**
- * Determins if a marker is contained in a bounds.
- *
- * @param {google.maps.Marker} marker The marker to check.
- * @param {google.maps.LatLngBounds} bounds The bounds to check against.
- * @return {boolean} True if the marker is in the bounds.
- * @private
- */
-MarkerClusterer.prototype.isMarkerInBounds_ = function(marker, bounds) {
-  return bounds.contains(marker.getPosition());
-};
-
-
-/**
- * Clears all clusters and markers from the clusterer.
- */
-MarkerClusterer.prototype.clearMarkers = function() {
-  this.resetViewport();
-
-  // Set the markers a empty array.
-  this.markers_ = [];
-};
-
-
-/**
- * Clears all existing clusters and recreates them.
- */
-MarkerClusterer.prototype.resetViewport = function() {
-  // Remove all the clusters
-  for (var i = 0, cluster; cluster = this.clusters_[i]; i++) {
-    cluster.remove();
-  }
-
-  // Reset the markers to not be added and to be invisible.
-  for (var i = 0, marker; marker = this.markers_[i]; i++) {
-    marker.isAdded = false;
-    marker.setMap(null);
-    marker.setVisible(false);
-  }
-
-  this.clusters_ = [];
-};
-
-
-/**
- * Redraws the clusters.
- */
-MarkerClusterer.prototype.redraw = function() {
-  this.createClusters_();
-};
-
-
-/**
- * Creates the clusters.
- *
- * @private
- */
-MarkerClusterer.prototype.createClusters_ = function() {
-  if (!this.ready_) {
-    return;
-  }
-
-  // Get our current map view bounds.
-  // Create a new bounds object so we don't affect the map.
-  var mapBounds = new google.maps.LatLngBounds(this.map_.getBounds().getSouthWest(),
-      this.map_.getBounds().getNorthEast());
-  var bounds = this.getExtendedBounds(mapBounds);
-
-  for (var i = 0, marker; marker = this.markers_[i]; i++) {
-    var added = false;
-    if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) {
-      for (var j = 0, cluster; cluster = this.clusters_[j]; j++) {
-        if (!added && cluster.getCenter() &&
-            cluster.isMarkerInClusterBounds(marker)) {
-          added = true;
-          cluster.addMarker(marker);
-          break;
-        }
-      }
-
-      if (!added) {
-        // Create a new cluster.
-        var cluster = new Cluster(this);
-        cluster.addMarker(marker);
-        this.clusters_.push(cluster);
-      }
-    }
-  }
-};
-
-
-/**
- * A cluster that contains markers.
- *
- * @param {MarkerClusterer} markerClusterer The markerclusterer that this
- *     cluster is associated with.
- * @constructor
- * @ignore
- */
-function Cluster(markerClusterer) {
-  this.markerClusterer_ = markerClusterer;
-  this.map_ = markerClusterer.getMap();
-  this.gridSize_ = markerClusterer.getGridSize();
-  this.averageCenter_ = markerClusterer.isAverageCenter();
-  this.center_ = null;
-  this.markers_ = [];
-  this.bounds_ = null;
-  this.clusterIcon_ = new ClusterIcon(this, markerClusterer.getStyles(),
-      markerClusterer.getGridSize());
-}
-
-/**
- * Determins if a marker is already added to the cluster.
- *
- * @param {google.maps.Marker} marker The marker to check.
- * @return {boolean} True if the marker is already added.
- */
-Cluster.prototype.isMarkerAlreadyAdded = function(marker) {
-  if (this.markers_.indexOf) {
-    return this.markers_.indexOf(marker) != -1;
-  } else {
-    for (var i = 0, m; m = this.markers_[i]; i++) {
-      if (m == marker) {
-        return true;
-      }
-    }
-  }
-  return false;
-};
-
-
-/**
- * Add a marker the cluster.
- *
- * @param {google.maps.Marker} marker The marker to add.
- * @return {boolean} True if the marker was added.
- */
-Cluster.prototype.addMarker = function(marker) {
-  if (this.isMarkerAlreadyAdded(marker)) {
-    return false;
-  }
-
-  if (!this.center_) {
-    this.center_ = marker.getPosition();
-    this.calculateBounds_();
-  } else {
-    if (this.averageCenter_) {
-      var lat = (this.center_.lat() + marker.getPosition().lat()) / 2;
-      var lng = (this.center_.lng() + marker.getPosition().lng()) / 2;
-      this.center_ = new google.maps.LatLng(lat, lng);
-      this.calculateBounds_();
-    }
-  }
-
-
-  if (this.markers_.length == 0) {
-    // Only 1 marker in this cluster so show the marker.
-    marker.setMap(this.map_);
-    marker.setVisible(true);
-  } else if (this.markers_.length == 1) {
-    // Hide the 1 marker that was showing.
-    this.markers_[0].setMap(null);
-    this.markers_[0].setVisible(false);
-  }
-
-  marker.isAdded = true;
-  this.markers_.push(marker);
-
-  this.updateIcon();
-  return true;
-};
-
-
-/**
- * Returns the marker clusterer that the cluster is associated with.
- *
- * @return {MarkerClusterer} The associated marker clusterer.
- */
-Cluster.prototype.getMarkerClusterer = function() {
-  return this.markerClusterer_;
-};
-
-
-/**
- * Returns the bounds of the cluster.
- *
- * @return {google.maps.LatLngBounds} the cluster bounds.
- */
-Cluster.prototype.getBounds = function() {
-  this.calculateBounds_();
-  return this.bounds_;
-};
-
-
-/**
- * Removes the cluster
- */
-Cluster.prototype.remove = function() {
-  this.clusterIcon_.remove();
-  this.markers_.length = 0;
-  delete this.markers_;
-};
-
-
-/**
- * Returns the center of the cluster.
- *
- * @return {number} The cluster center.
- */
-Cluster.prototype.getSize = function() {
-  return this.markers_.length;
-};
-
-
-/**
- * Returns the center of the cluster.
- *
- * @return {Array.<google.maps.Marker>} The cluster center.
- */
-Cluster.prototype.getMarkers = function() {
-  return this.markers_;
-};
-
-
-/**
- * Returns the center of the cluster.
- *
- * @return {google.maps.LatLng} The cluster center.
- */
-Cluster.prototype.getCenter = function() {
-  return this.center_;
-};
-
-
-/**
- * Calculated the bounds of the cluster with the grid.
- *
- * @private
- */
-Cluster.prototype.calculateBounds_ = function() {
-  var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
-  this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds);
-};
-
-
-/**
- * Determines if a marker lies in the clusters bounds.
- *
- * @param {google.maps.Marker} marker The marker to check.
- * @return {boolean} True if the marker lies in the bounds.
- */
-Cluster.prototype.isMarkerInClusterBounds = function(marker) {
-  return this.bounds_.contains(marker.getPosition());
-};
-
-
-/**
- * Returns the map that the cluster is associated with.
- *
- * @return {google.maps.Map} The map.
- */
-Cluster.prototype.getMap = function() {
-  return this.map_;
-};
-
-
-/**
- * Updates the cluster icon
- */
-Cluster.prototype.updateIcon = function() {
-  var zoom = this.map_.getZoom();
-  var mz = this.markerClusterer_.getMaxZoom();
-
-  if (zoom > mz) {
-    // The zoom is greater than our max zoom so show all the markers in cluster.
-    for (var i = 0, marker; marker = this.markers_[i]; i++) {
-      marker.setMap(this.map_);
-      marker.setVisible(true);
-    }
-    return;
-  }
-
-  if (this.markers_.length < 2) {
-    // We have 0 or 1 markers so hide the icon.
-    this.clusterIcon_.hide();
-    return;
-  }
-
-  var numStyles = this.markerClusterer_.getStyles().length;
-  var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles);
-  this.clusterIcon_.setCenter(this.center_);
-  this.clusterIcon_.setSums(sums);
-  this.clusterIcon_.show();
-};
-
-
-/**
- * A cluster icon
- *
- * @param {Cluster} cluster The cluster to be associated with.
- * @param {Object} styles An object that has style properties:
- *     'url': (string) The image url.
- *     'height': (number) The image height.
- *     'width': (number) The image width.
- *     'anchor': (Array) The anchor position of the label text.
- *     'textColor': (string) The text color.
- *     'textSize': (number) The text size.
- * @param {number} opt_padding Optional padding to apply to the cluster icon.
- * @constructor
- * @extends google.maps.OverlayView
- * @ignore
- */
-function ClusterIcon(cluster, styles, opt_padding) {
-  cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView);
-
-  this.styles_ = styles;
-  this.padding_ = opt_padding || 0;
-  this.cluster_ = cluster;
-  this.center_ = null;
-  this.map_ = cluster.getMap();
-  this.div_ = null;
-  this.sums_ = null;
-  this.visible_ = false;
-
-  this.setMap(this.map_);
-}
-
-
-/**
- * Triggers the clusterclick event and zoom's if the option is set.
- */
-ClusterIcon.prototype.triggerClusterClick = function() {
-  var markerClusterer = this.cluster_.getMarkerClusterer();
-
-  // Trigger the clusterclick event.
-  google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_);
-
-  if (markerClusterer.isZoomOnClick()) {
-    // Center the map on this cluster.
-    this.map_.panTo(this.cluster_.getCenter());
-
-    // Zoom into the cluster.
-    this.map_.fitBounds(this.cluster_.getBounds());
-  }
-};
-
-
-/**
- * Adding the cluster icon to the dom.
- * @ignore
- */
-ClusterIcon.prototype.onAdd = function() {
-  this.div_ = document.createElement('DIV');
-  if (this.visible_) {
-    var pos = this.getPosFromLatLng_(this.center_);
-    this.div_.style.cssText = this.createCss(pos);
-    this.div_.innerHTML = this.sums_.text;
-  }
-
-  var panes = this.getPanes();
-  panes.overlayImage.appendChild(this.div_);
-
-  var that = this;
-  google.maps.event.addDomListener(this.div_, 'click', function() {
-    that.triggerClusterClick();
-  });
-};
-
-
-/**
- * Returns the position to place the div dending on the latlng.
- *
- * @param {google.maps.LatLng} latlng The position in latlng.
- * @return {google.maps.Point} The position in pixels.
- * @private
- */
-ClusterIcon.prototype.getPosFromLatLng_ = function(latlng) {
-  var pos = this.getProjection().fromLatLngToDivPixel(latlng);
-  pos.x -= parseInt(this.width_ / 2, 10);
-  pos.y -= parseInt(this.height_ / 2, 10);
-  return pos;
-};
-
-
-/**
- * Draw the icon.
- * @ignore
- */
-ClusterIcon.prototype.draw = function() {
-  if (this.visible_) {
-    var pos = this.getPosFromLatLng_(this.center_);
-    this.div_.style.top = pos.y + 'px';
-    this.div_.style.left = pos.x + 'px';
-  }
-};
-
-
-/**
- * Hide the icon.
- */
-ClusterIcon.prototype.hide = function() {
-  if (this.div_) {
-    this.div_.style.display = 'none';
-  }
-  this.visible_ = false;
-};
-
-
-/**
- * Position and show the icon.
- */
-ClusterIcon.prototype.show = function() {
-  if (this.div_) {
-    var pos = this.getPosFromLatLng_(this.center_);
-    this.div_.style.cssText = this.createCss(pos);
-    this.div_.style.display = '';
-  }
-  this.visible_ = true;
-};
-
-
-/**
- * Remove the icon from the map
- */
-ClusterIcon.prototype.remove = function() {
-  this.setMap(null);
-};
-
-
-/**
- * Implementation of the onRemove interface.
- * @ignore
- */
-ClusterIcon.prototype.onRemove = function() {
-  if (this.div_ && this.div_.parentNode) {
-    this.hide();
-    this.div_.parentNode.removeChild(this.div_);
-    this.div_ = null;
-  }
-};
-
-
-/**
- * Set the sums of the icon.
- *
- * @param {Object} sums The sums containing:
- *   'text': (string) The text to display in the icon.
- *   'index': (number) The style index of the icon.
- */
-ClusterIcon.prototype.setSums = function(sums) {
-  this.sums_ = sums;
-  this.text_ = sums.text;
-  this.index_ = sums.index;
-  if (this.div_) {
-    this.div_.innerHTML = sums.text;
-  }
-
-  this.useStyle();
-};
-
-
-/**
- * Sets the icon to the the styles.
- */
-ClusterIcon.prototype.useStyle = function() {
-  var index = Math.max(0, this.sums_.index - 1);
-  index = Math.min(this.styles_.length - 1, index);
-  var style = this.styles_[index];
-  this.url_ = style['url'];
-  this.height_ = style['height'];
-  this.width_ = style['width'];
-  this.textColor_ = style['textColor'];
-  this.anchor = style['anchor'];
-  this.textSize_ = style['textSize'];
-};
-
-
-/**
- * Sets the center of the icon.
- *
- * @param {google.maps.LatLng} center The latlng to set as the center.
- */
-ClusterIcon.prototype.setCenter = function(center) {
-  this.center_ = center;
-};
-
-
-/**
- * Create the css text based on the position of the icon.
- *
- * @param {google.maps.Point} pos The position.
- * @return {string} The css style text.
- */
-ClusterIcon.prototype.createCss = function(pos) {
-  var style = [];
-  if (document.all) {
-    style.push('filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(' +
-        'sizingMethod=scale,src="' + this.url_ + '");');
-  } else {
-    style.push('background:url(' + this.url_ + ');');
-  }
-
-  if (typeof this.anchor_ === 'object') {
-    if (typeof this.anchor_[0] === 'number' && this.anchor_[0] > 0 &&
-        this.anchor_[0] < this.height_) {
-      style.push('height:' + (this.height_ - this.anchor_[0]) +
-          'px; padding-top:' + this.anchor_[0] + 'px;');
-    } else {
-      style.push('height:' + this.height_ + 'px; line-height:' + this.height_ +
-          'px;');
-    }
-    if (typeof this.anchor_[1] === 'number' && this.anchor_[1] > 0 &&
-        this.anchor_[1] < this.width_) {
-      style.push('width:' + (this.width_ - this.anchor_[1]) +
-          'px; padding-left:' + this.anchor_[1] + 'px;');
-    } else {
-      style.push('width:' + this.width_ + 'px; text-align:center;');
-    }
-  } else {
-    style.push('height:' + this.height_ + 'px; line-height:' +
-        this.height_ + 'px; width:' + this.width_ + 'px; text-align:center;');
-  }
-
-  var txtColor = this.textColor_ ? this.textColor_ : 'black';
-  var txtSize = this.textSize_ ? this.textSize_ : 11;
-
-  style.push('cursor:pointer; top:' + pos.y + 'px; left:' +
-      pos.x + 'px; color:' + txtColor + '; position:absolute; font-size:' +
-      txtSize + 'px; font-family:Arial,sans-serif; font-weight:bold');
-  return style.join('');
-};
-
-
-// Export Symbols for Closure
-// If you are not going to compile with closure then you can remove the
-// code below.
-window['MarkerClusterer'] = MarkerClusterer;
-MarkerClusterer.prototype['addMarker'] = MarkerClusterer.prototype.addMarker;
-MarkerClusterer.prototype['addMarkers'] = MarkerClusterer.prototype.addMarkers;
-MarkerClusterer.prototype['clearMarkers'] =
-    MarkerClusterer.prototype.clearMarkers;
-MarkerClusterer.prototype['getCalculator'] =
-    MarkerClusterer.prototype.getCalculator;
-MarkerClusterer.prototype['getGridSize'] =
-    MarkerClusterer.prototype.getGridSize;
-MarkerClusterer.prototype['getMap'] = MarkerClusterer.prototype.getMap;
-MarkerClusterer.prototype['getMarkers'] = MarkerClusterer.prototype.getMarkers;
-MarkerClusterer.prototype['getMaxZoom'] = MarkerClusterer.prototype.getMaxZoom;
-MarkerClusterer.prototype['getStyles'] = MarkerClusterer.prototype.getStyles;
-MarkerClusterer.prototype['getTotalClusters'] =
-    MarkerClusterer.prototype.getTotalClusters;
-MarkerClusterer.prototype['getTotalMarkers'] =
-    MarkerClusterer.prototype.getTotalMarkers;
-MarkerClusterer.prototype['redraw'] = MarkerClusterer.prototype.redraw;
-MarkerClusterer.prototype['removeMarker'] =
-    MarkerClusterer.prototype.removeMarker;
-MarkerClusterer.prototype['resetViewport'] =
-    MarkerClusterer.prototype.resetViewport;
-MarkerClusterer.prototype['setCalculator'] =
-    MarkerClusterer.prototype.setCalculator;
-MarkerClusterer.prototype['setGridSize'] =
-    MarkerClusterer.prototype.setGridSize;
-MarkerClusterer.prototype['onAdd'] = MarkerClusterer.prototype.onAdd;
-MarkerClusterer.prototype['draw'] = MarkerClusterer.prototype.draw;
-
-Cluster.prototype['getCenter'] = Cluster.prototype.getCenter;
-Cluster.prototype['getSize'] = Cluster.prototype.getSize;
-Cluster.prototype['getMarkers'] = Cluster.prototype.getMarkers;
-
-ClusterIcon.prototype['onAdd'] = ClusterIcon.prototype.onAdd;
-ClusterIcon.prototype['draw'] = ClusterIcon.prototype.draw;
-ClusterIcon.prototype['onRemove'] = ClusterIcon.prototype.onRemove;
diff --git a/plugins/googlemaps/static/js/markerclusterer_compiled.js b/plugins/googlemaps/static/js/markerclusterer_compiled.js
deleted file mode 100644 (file)
index ad74d1b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-function d(a){return function(b){this[a]=b}}function e(a){return function(){return this[a]}}var h; function i(a,b,c){this.extend(i,google.maps.OverlayView);this.b=a;this.a=[];this.l=[];this.Y=[53,56,66,78,90];this.h=[];this.z=false;c=c||{};this.f=c.gridSize||60;this.U=c.maxZoom||null;this.h=c.styles||[];this.T=c.imagePath||this.M;this.S=c.imageExtension||this.L;this.K=true;if(c.zoomOnClick!=undefined)this.K=c.zoomOnClick;this.p=false;if(c.averageCenter!=undefined)this.p=c.averageCenter;j(this);this.setMap(a);this.G=this.b.getZoom();var f=this;google.maps.event.addListener(this.b,"zoom_changed", function(){var g=f.b.mapTypes[f.b.getMapTypeId()].maxZoom,l=f.b.getZoom();if(!(l<0||l>g))if(f.G!=l){f.G=f.b.getZoom();f.m()}});google.maps.event.addListener(this.b,"idle",function(){f.j()});b&&b.length&&this.B(b,false)}h=i.prototype;h.M="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/images/m";h.L="png";h.extend=function(a,b){return function(c){for(property in c.prototype)this.prototype[property]=c.prototype[property];return this}.apply(a,[b])}; h.onAdd=function(){if(!this.z){this.z=true;m(this)}};h.R=function(){};h.draw=function(){};function j(a){if(!a.h.length)for(var b=0,c;c=a.Y[b];b++)a.h.push({url:a.T+(b+1)+"."+a.S,height:c,width:c})}h.w=e("h");h.v=e("a");h.Q=e("a");h.F=function(){return this.U||this.b.mapTypes[this.b.getMapTypeId()].maxZoom};h.C=function(a,b){for(var c=0,f=a.length,g=f;g!==0;){g=parseInt(g/10,10);c++}c=Math.min(c,b);return{text:f,index:c}};h.W=d("C");h.D=e("C"); h.B=function(a,b){for(var c=0,f;f=a[c];c++)n(this,f);b||this.j()};function n(a,b){b.setVisible(false);b.setMap(null);b.r=false;b.draggable&&google.maps.event.addListener(b,"dragend",function(){b.r=false;a.m();a.j()});a.a.push(b)}h.o=function(a,b){n(this,a);b||this.j()};h.V=function(a){var b=-1;if(this.a.indexOf)b=this.a.indexOf(a);else for(var c=0,f;f=this.a[c];c++)if(f==a)b=c;if(b==-1)return false;this.a.splice(b,1);a.setVisible(false);a.setMap(null);this.m();this.j();return true};h.P=function(){return this.l.length}; h.getMap=e("b");h.setMap=d("b");h.u=e("f");h.X=d("f");function o(a,b){var c=a.getProjection(),f=new google.maps.LatLng(b.getNorthEast().lat(),b.getNorthEast().lng()),g=new google.maps.LatLng(b.getSouthWest().lat(),b.getSouthWest().lng());f=c.fromLatLngToDivPixel(f);f.x+=a.f;f.y-=a.f;g=c.fromLatLngToDivPixel(g);g.x-=a.f;g.y+=a.f;f=c.fromDivPixelToLatLng(f);c=c.fromDivPixelToLatLng(g);b.extend(f);b.extend(c);return b}h.N=function(){this.m();this.a=[]}; h.m=function(){for(var a=0,b;b=this.l[a];a++)b.remove();for(a=0;b=this.a[a];a++){b.r=false;b.setMap(null);b.setVisible(false)}this.l=[]};h.j=function(){m(this)};function m(a){if(a.z)for(var b=o(a,new google.maps.LatLngBounds(a.b.getBounds().getSouthWest(),a.b.getBounds().getNorthEast())),c=0,f;f=a.a[c];c++){var g=false;if(!f.r&&b.contains(f.getPosition())){for(var l=0,k;k=a.l[l];l++)if(!g&&k.getCenter()&&k.t.contains(f.getPosition())){g=true;k.o(f);break}if(!g){k=new p(a);k.o(f);a.l.push(k)}}}} function p(a){this.i=a;this.b=a.getMap();this.f=a.u();this.p=a.p;this.d=null;this.a=[];this.t=null;this.k=new q(this,a.w(),a.u())}h=p.prototype; h.o=function(a){var b;a:if(this.a.indexOf)b=this.a.indexOf(a)!=-1;else{b=0;for(var c;c=this.a[b];b++)if(c==a){b=true;break a}b=false}if(b)return false;if(this.d){if(this.p){b=(this.d.lat()+a.getPosition().lat())/2;c=(this.d.lng()+a.getPosition().lng())/2;this.d=new google.maps.LatLng(b,c);r(this)}}else{this.d=a.getPosition();r(this)}if(this.a.length==0){a.setMap(this.b);a.setVisible(true)}else if(this.a.length==1){this.a[0].setMap(null);this.a[0].setVisible(false)}a.r=true;this.a.push(a);if(this.b.getZoom()> this.i.F())for(a=0;b=this.a[a];a++){b.setMap(this.b);b.setVisible(true)}else if(this.a.length<2)s(this.k);else{a=this.i.w().length;b=this.i.D()(this.a,a);this.k.setCenter(this.d);a=this.k;a.A=b;a.aa=b.text;a.Z=b.index;if(a.c)a.c.innerHTML=b.text;b=Math.max(0,a.A.index-1);b=Math.min(a.h.length-1,b);b=a.h[b];a.J=b.url;a.g=b.height;a.n=b.width;a.H=b.textColor;a.anchor=b.anchor;a.I=b.textSize;this.k.show()}return true};h.getBounds=function(){r(this);return this.t}; h.remove=function(){this.k.remove();this.a.length=0;delete this.a};h.O=function(){return this.a.length};h.v=e("a");h.getCenter=e("d");function r(a){a.t=o(a.i,new google.maps.LatLngBounds(a.d,a.d))}h.getMap=e("b");function q(a,b,c){a.i.extend(q,google.maps.OverlayView);this.h=b;this.$=c||0;this.q=a;this.d=null;this.b=a.getMap();this.A=this.c=null;this.s=false;this.setMap(this.b)}h=q.prototype; h.onAdd=function(){this.c=document.createElement("DIV");if(this.s){this.c.style.cssText=t(this,u(this,this.d));this.c.innerHTML=this.A.text}this.getPanes().overlayImage.appendChild(this.c);var a=this;google.maps.event.addDomListener(this.c,"click",function(){var b=a.q.i;google.maps.event.trigger(b,"clusterclick",a.q);if(b.K){a.b.panTo(a.q.getCenter());a.b.fitBounds(a.q.getBounds())}})}; function u(a,b){var c=a.getProjection().fromLatLngToDivPixel(b);c.x-=parseInt(a.n/2,10);c.y-=parseInt(a.g/2,10);return c}h.draw=function(){if(this.s){var a=u(this,this.d);this.c.style.top=a.y+"px";this.c.style.left=a.x+"px"}};function s(a){if(a.c)a.c.style.display="none";a.s=false}h.show=function(){if(this.c){this.c.style.cssText=t(this,u(this,this.d));this.c.style.display=""}this.s=true};h.remove=function(){this.setMap(null)}; h.onRemove=function(){if(this.c&&this.c.parentNode){s(this);this.c.parentNode.removeChild(this.c);this.c=null}};h.setCenter=d("d"); function t(a,b){var c=[];document.all?c.push('filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale,src="'+a.J+'");'):c.push("background:url("+a.J+");");if(typeof a.e==="object"){typeof a.e[0]==="number"&&a.e[0]>0&&a.e[0]<a.g?c.push("height:"+(a.g-a.e[0])+"px; padding-top:"+a.e[0]+"px;"):c.push("height:"+a.g+"px; line-height:"+a.g+"px;");typeof a.e[1]==="number"&&a.e[1]>0&&a.e[1]<a.n?c.push("width:"+(a.n-a.e[1])+"px; padding-left:"+a.e[1]+"px;"):c.push("width:"+a.n+"px; text-align:center;")}else c.push("height:"+ a.g+"px; line-height:"+a.g+"px; width:"+a.n+"px; text-align:center;");c.push("cursor:pointer; top:"+b.y+"px; left:"+b.x+"px; color:"+(a.H?a.H:"black")+"; position:absolute; font-size:"+(a.I?a.I:11)+"px; font-family:Arial,sans-serif; font-weight:bold");return c.join("")}window.MarkerClusterer=i;i.prototype.addMarker=i.prototype.o;i.prototype.addMarkers=i.prototype.B;i.prototype.clearMarkers=i.prototype.N;i.prototype.getCalculator=i.prototype.D;i.prototype.getGridSize=i.prototype.u; i.prototype.getMap=i.prototype.getMap;i.prototype.getMarkers=i.prototype.v;i.prototype.getMaxZoom=i.prototype.F;i.prototype.getStyles=i.prototype.w;i.prototype.getTotalClusters=i.prototype.P;i.prototype.getTotalMarkers=i.prototype.Q;i.prototype.redraw=i.prototype.j;i.prototype.removeMarker=i.prototype.V;i.prototype.resetViewport=i.prototype.m;i.prototype.setCalculator=i.prototype.W;i.prototype.setGridSize=i.prototype.X;i.prototype.onAdd=i.prototype.onAdd;i.prototype.draw=i.prototype.draw; i.prototype.idle=i.prototype.R;p.prototype.getCenter=p.prototype.getCenter;p.prototype.getSize=p.prototype.O;p.prototype.getMarkers=p.prototype.v;q.prototype.onAdd=q.prototype.onAdd;q.prototype.draw=q.prototype.draw;q.prototype.onRemove=q.prototype.onRemove;
diff --git a/plugins/googlemaps/static/js/markerclusterer_packed.js b/plugins/googlemaps/static/js/markerclusterer_packed.js
deleted file mode 100644 (file)
index cbcac71..0000000
+++ /dev/null
@@ -1 +0,0 @@
-eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('6 5(c,d,e){3.Z(5,u.v.23);3.l=c;3.k=[];3.N=[];3.24=[2H,2I,2J,2K,2L];3.F=[];3.1d=r;7 f=e||{};3.G=f[\'2M\']||2N;3.1s=f[\'1t\']||w;3.F=f[\'2O\']||[];3.25=f[\'2P\']||3.26;3.27=f[\'2Q\']||3.28;3.1u=C;8(f[\'29\']!=2a){3.1u=f[\'29\']}3.12=r;8(f[\'2b\']!=2a){3.12=f[\'2b\']}3.2c();3.D(c);3.1v=3.l.1e();7 g=3;u.v.13.1w(3.l,\'2R\',6(){7 a=g.l.2d[g.l.2e()].1t;7 b=g.l.1e();8(b<0||b>a){9}8(g.1v!=b){g.1v=g.l.1e();g.K()}});u.v.13.1w(3.l,\'1f\',6(){g.H()});8(d&&d.A){3.1g(d,r)}}5.4.26=\'2S://u-v-2T-2U-2V.2W.2X/2Y/2Z/30/\'+\'31/m\';5.4.28=\'32\';5.4.Z=6(b,c){9(6(a){E(1x 33 a.4){3.4[1x]=a.4[1x]}9 3}).34(b,[c])};5.4.O=6(){3.2f(C)};5.4.1f=6(){};5.4.P=6(){};5.4.2c=6(){8(3.F.A){9}E(7 i=0,14;14=3.24[i];i++){3.F.z({1y:3.25+(i+1)+\'.\'+3.27,L:14,15:14})}};5.4.35=6(a){3.F=a};5.4.16=6(){9 3.F};5.4.2g=6(){9 3.1u};5.4.2h=6(){9 3.12};5.4.Q=6(){9 3.k};5.4.1z=6(){9 3.k};5.4.36=6(a){3.1s=a};5.4.1h=6(){9 3.1s||3.l.2d[3.l.2e()].1t};5.4.1A=6(a,b){7 c=0;7 d=a.A;7 e=d;37(e!==0){e=1B(e/10,10);c++}c=1C.2i(c,b);9{R:d,1D:c}};5.4.1E=6(a){3.1A=a};5.4.1i=6(){9 3.1A};5.4.1g=6(a,b){E(7 i=0,q;q=a[i];i++){3.1F(q)}8(!b){3.H()}};5.4.1F=6(a){a.S(r);a.D(w);a.17=r;8(a[\'38\']){7 b=3;u.v.13.1w(a,\'39\',6(){a.17=r;b.K();b.H()})}3.k.z(a)};5.4.T=6(a,b){3.1F(a);8(!b){3.H()}};5.4.1G=6(a){7 b=-1;8(3.k.1j){b=3.k.1j(a)}I{E(7 i=0,m;m=3.k[i];i++){8(m==a){b=i;3a}}}8(b==-1){9 r}3.k.3b(b,1);a.S(r);a.D(w);3.K();3.H();9 C};5.4.2f=6(a){8(!3.1d){3.1d=a;3.1H()}};5.4.1I=6(){9 3.N.A};5.4.U=6(){9 3.l};5.4.D=6(a){3.l=a};5.4.18=6(){9 3.G};5.4.1J=6(a){3.G=a};5.4.1K=6(a){7 b=3.2j();7 c=M u.v.1L(a.1M().1k(),a.1M().1l());7 d=M u.v.1L(a.1N().1k(),a.1N().1l());7 e=b.1O(c);e.x+=3.G;e.y-=3.G;7 f=b.1O(d);f.x-=3.G;f.y+=3.G;7 g=b.2k(e);7 h=b.2k(f);a.Z(g);a.Z(h);9 a};5.4.2l=6(a,b){9 b.2m(a.19())};5.4.1P=6(){3.K();3.k=[]};5.4.K=6(){E(7 i=0,1Q;1Q=3.N[i];i++){1Q.1m()}E(7 i=0,q;q=3.k[i];i++){q.17=r;q.D(w);q.S(r)}3.N=[]};5.4.H=6(){3.1H()};5.4.1H=6(){8(!3.1d){9}7 a=M u.v.2n(3.l.1n().1N(),3.l.1n().1M());7 b=3.1K(a);E(7 i=0,q;q=3.k[i];i++){7 c=r;8(!q.17&&3.2l(q,b)){E(7 j=0,d;d=3.N[j];j++){8(!c&&d.1a()&&d.2o(q)){c=C;d.T(q);3c}}8(!c){7 d=M o(3);d.T(q);3.N.z(d)}}}};6 o(a){3.V=a;3.l=a.U();3.G=a.18();3.12=a.2h();3.s=w;3.k=[];3.1o=w;3.W=M n(3,a.16(),a.18())}o.4.2p=6(a){8(3.k.1j){9 3.k.1j(a)!=-1}I{E(7 i=0,m;m=3.k[i];i++){8(m==a){9 C}}}9 r};o.4.T=6(a){8(3.2p(a)){9 r}8(!3.s){3.s=a.19();3.1p()}I{8(3.12){7 b=(3.s.1k()+a.19().1k())/2;7 c=(3.s.1l()+a.19().1l())/2;3.s=M u.v.1L(b,c);3.1p()}}8(3.k.A==0){a.D(3.l);a.S(C)}I 8(3.k.A==1){3.k[0].D(w);3.k[0].S(r)}a.17=C;3.k.z(a);3.2q();9 C};o.4.1R=6(){9 3.V};o.4.1n=6(){3.1p();9 3.1o};o.4.1m=6(){3.W.1m();3.k.A=0;3d 3.k};o.4.1S=6(){9 3.k.A};o.4.Q=6(){9 3.k};o.4.1a=6(){9 3.s};o.4.1p=6(){7 a=M u.v.2n(3.s,3.s);3.1o=3.V.1K(a)};o.4.2o=6(a){9 3.1o.2m(a.19())};o.4.U=6(){9 3.l};o.4.2q=6(){7 a=3.l.1e();7 b=3.V.1h();8(a>b){E(7 i=0,q;q=3.k[i];i++){q.D(3.l);q.S(C)}9}8(3.k.A<2){3.W.1T();9}7 c=3.V.16().A;7 d=3.V.1i()(3.k,c);3.W.2r(3.s);3.W.2s(d);3.W.2t()};6 n(a,b,c){a.1R().Z(n,u.v.23);3.F=b;3.3e=c||0;3.1b=a;3.s=w;3.l=a.U();3.p=w;3.1q=w;3.1c=r;3.D(3.l)}n.4.2u=6(){7 a=3.1b.1R();u.v.13.3f(a,\'3g\',3.1b);8(a.2g()){3.l.3h(3.1b.1a());3.l.3i(3.1b.1n())}};n.4.O=6(){3.p=2v.3j(\'3k\');8(3.1c){7 a=3.1r(3.s);3.p.X.2w=3.1U(a);3.p.2x=3.1q.R}7 b=3.3l();b.3m.3n(3.p);7 c=3;u.v.13.3o(3.p,\'3p\',6(){c.2u()})};n.4.1r=6(a){7 b=3.2j().1O(a);b.x-=1B(3.Y/2,10);b.y-=1B(3.J/2,10);9 b};n.4.P=6(){8(3.1c){7 a=3.1r(3.s);3.p.X.1V=a.y+\'t\';3.p.X.1W=a.x+\'t\'}};n.4.1T=6(){8(3.p){3.p.X.2y=\'3q\'}3.1c=r};n.4.2t=6(){8(3.p){7 a=3.1r(3.s);3.p.X.2w=3.1U(a);3.p.X.2y=\'\'}3.1c=C};n.4.1m=6(){3.D(w)};n.4.1X=6(){8(3.p&&3.p.2z){3.1T();3.p.2z.3r(3.p);3.p=w}};n.4.2s=6(a){3.1q=a;3.3s=a.R;3.3t=a.1D;8(3.p){3.p.2x=a.R}3.2A()};n.4.2A=6(){7 a=1C.3u(0,3.1q.1D-1);a=1C.2i(3.F.A-1,a);7 b=3.F[a];3.1Y=b[\'1y\'];3.J=b[\'L\'];3.Y=b[\'15\'];3.1Z=b[\'3v\'];3.2B=b[\'2B\'];3.20=b[\'3w\']};n.4.2r=6(a){3.s=a};n.4.1U=6(a){7 b=[];8(2v.3x){b.z(\'3y:3z:3A.3B.3C(\'+\'3D=3E,3F="\'+3.1Y+\'");\')}I{b.z(\'3G:1y(\'+3.1Y+\');\')}8(21 3.B===\'3H\'){8(21 3.B[0]===\'2C\'&&3.B[0]>0&&3.B[0]<3.J){b.z(\'L:\'+(3.J-3.B[0])+\'t; 2D-1V:\'+3.B[0]+\'t;\')}I{b.z(\'L:\'+3.J+\'t; 2E-L:\'+3.J+\'t;\')}8(21 3.B[1]===\'2C\'&&3.B[1]>0&&3.B[1]<3.Y){b.z(\'15:\'+(3.Y-3.B[1])+\'t; 2D-1W:\'+3.B[1]+\'t;\')}I{b.z(\'15:\'+3.Y+\'t; R-2F:2G;\')}}I{b.z(\'L:\'+3.J+\'t; 2E-L:\'+3.J+\'t; 15:\'+3.Y+\'t; R-2F:2G;\')}7 c=3.1Z?3.1Z:\'3I\';7 d=3.20?3.20:11;b.z(\'3J:3K; 1V:\'+a.y+\'t; 1W:\'+a.x+\'t; 3L:\'+c+\'; 3M:3N; 22-14:\'+d+\'t; 22-3O:3P,3Q-3R; 22-3S:3T\');9 b.3U(\'\')};3V[\'5\']=5;5.4[\'T\']=5.4.T;5.4[\'1g\']=5.4.1g;5.4[\'1P\']=5.4.1P;5.4[\'1i\']=5.4.1i;5.4[\'18\']=5.4.18;5.4[\'U\']=5.4.U;5.4[\'Q\']=5.4.Q;5.4[\'1h\']=5.4.1h;5.4[\'16\']=5.4.16;5.4[\'1I\']=5.4.1I;5.4[\'1z\']=5.4.1z;5.4[\'H\']=5.4.H;5.4[\'1G\']=5.4.1G;5.4[\'K\']=5.4.K;5.4[\'1E\']=5.4.1E;5.4[\'1J\']=5.4.1J;5.4[\'O\']=5.4.O;5.4[\'P\']=5.4.P;5.4[\'1f\']=5.4.1f;o.4[\'1a\']=o.4.1a;o.4[\'1S\']=o.4.1S;o.4[\'Q\']=o.4.Q;n.4[\'O\']=n.4.O;n.4[\'P\']=n.4.P;n.4[\'1X\']=n.4.1X;',62,244,'|||this|prototype|MarkerClusterer|function|var|if|return|||||||||||markers_|map_||ClusterIcon|Cluster|div_|marker|false|center_|px|google|maps|null|||push|length|anchor_|true|setMap|for|styles_|gridSize_|redraw|else|height_|resetViewport|height|new|clusters_|onAdd|draw|getMarkers|text|setVisible|addMarker|getMap|markerClusterer_|clusterIcon_|style|width_|extend|||averageCenter_|event|size|width|getStyles|isAdded|getGridSize|getPosition|getCenter|cluster_|visible_|ready_|getZoom|idle|addMarkers|getMaxZoom|getCalculator|indexOf|lat|lng|remove|getBounds|bounds_|calculateBounds_|sums_|getPosFromLatLng_|maxZoom_|maxZoom|zoomOnClick_|prevZoom_|addListener|property|url|getTotalMarkers|calculator_|parseInt|Math|index|setCalculator|pushMarkerTo_|removeMarker|createClusters_|getTotalClusters|setGridSize|getExtendedBounds|LatLng|getNorthEast|getSouthWest|fromLatLngToDivPixel|clearMarkers|cluster|getMarkerClusterer|getSize|hide|createCss|top|left|onRemove|url_|textColor_|textSize_|typeof|font|OverlayView|sizes|imagePath_|MARKER_CLUSTER_IMAGE_PATH_|imageExtension_|MARKER_CLUSTER_IMAGE_EXTENSION_|zoomOnClick|undefined|averageCenter|setupStyles_|mapTypes|getMapTypeId|setReady_|isZoomOnClick|isAverageCenter|min|getProjection|fromDivPixelToLatLng|isMarkerInBounds_|contains|LatLngBounds|isMarkerInClusterBounds|isMarkerAlreadyAdded|updateIcon|setCenter|setSums|show|triggerClusterClick|document|cssText|innerHTML|display|parentNode|useStyle|anchor|number|padding|line|align|center|53|56|66|78|90|gridSize|60|styles|imagePath|imageExtension|zoom_changed|http|utility|library|v3|googlecode|com|svn|trunk|markerclusterer|images|png|in|apply|setStyles|setMaxZoom|while|draggable|dragend|continue|splice|break|delete|padding_|trigger|clusterclick|panTo|fitBounds|createElement|DIV|getPanes|overlayImage|appendChild|addDomListener|click|none|removeChild|text_|index_|max|textColor|textSize|all|filter|progid|DXImageTransform|Microsoft|AlphaImageLoader|sizingMethod|scale|src|background|object|black|cursor|pointer|color|position|absolute|family|Arial|sans|serif|weight|bold|join|window'.split('|'),0,{}))
diff --git a/third-party/markerclusterer/markerclusterer-2.0.16.js b/third-party/markerclusterer/markerclusterer-2.0.16.js
new file mode 100644 (file)
index 0000000..cb89261
--- /dev/null
@@ -0,0 +1,1644 @@
+/*jslint browser: true, confusion: true, sloppy: true, vars: true, nomen: false, plusplus: false, indent: 2 */
+/*global window,google */
+
+/**
+ * @name MarkerClustererPlus for Google Maps V3
+ * @version 2.0.16 [October 18, 2012]
+ * @author Gary Little
+ * @fileoverview
+ * The library creates and manages per-zoom-level clusters for large amounts of markers.
+ * <p>
+ * This is an enhanced V3 implementation of the
+ * <a href="http://gmaps-utility-library-dev.googlecode.com/svn/tags/markerclusterer/"
+ * >V2 MarkerClusterer</a> by Xiaoxi Wu. It is based on the
+ * <a href="http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerclusterer/"
+ * >V3 MarkerClusterer</a> port by Luke Mahe. MarkerClustererPlus was created by Gary Little.
+ * <p>
+ * v2.0 release: MarkerClustererPlus v2.0 is backward compatible with MarkerClusterer v1.0. It
+ *  adds support for the <code>ignoreHidden</code>, <code>title</code>, <code>printable</code>,
+ *  <code>batchSizeIE</code>, and <code>calculator</code> properties as well as support for
+ *  four more events. It also allows greater control over the styling of the text that appears
+ *  on the cluster marker. The documentation has been significantly improved and the overall
+ *  code has been simplified and polished. Very large numbers of markers can now be managed
+ *  without causing Javascript timeout errors on Internet Explorer. Note that the name of the
+ *  <code>clusterclick</code> event has been deprecated. The new name is <code>click</code>,
+ *  so please change your application code now.
+ */
+
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * @name ClusterIconStyle
+ * @class This class represents the object for values in the <code>styles</code> array passed
+ *  to the {@link MarkerClusterer} constructor. The element in this array that is used to
+ *  style the cluster icon is determined by calling the <code>calculator</code> function.
+ *
+ * @property {string} url The URL of the cluster icon image file. Required.
+ * @property {number} height The height (in pixels) of the cluster icon. Required.
+ * @property {number} width The width (in pixels) of the cluster icon. Required.
+ * @property {Array} [anchor] The anchor position (in pixels) of the label text to be shown on
+ *  the cluster icon, relative to the top left corner of the icon.
+ *  The format is <code>[yoffset, xoffset]</code>. The <code>yoffset</code> must be positive
+ *  and less than <code>height</code> and the <code>xoffset</code> must be positive and less
+ *  than <code>width</code>. The default is to anchor the label text so that it is centered
+ *  on the icon.
+ * @property {Array} [anchorIcon] The anchor position (in pixels) of the cluster icon. This is the
+ *  spot on the cluster icon that is to be aligned with the cluster position. The format is
+ *  <code>[yoffset, xoffset]</code> where <code>yoffset</code> increases as you go down and
+ *  <code>xoffset</code> increases to the right. The default anchor position is the center of the
+ *  cluster icon.
+ * @property {string} [textColor="black"] The color of the label text shown on the
+ *  cluster icon.
+ * @property {number} [textSize=11] The size (in pixels) of the label text shown on the
+ *  cluster icon.
+ * @property {number} [textDecoration="none"] The value of the CSS <code>text-decoration</code>
+ *  property for the label text shown on the cluster icon.
+ * @property {number} [fontWeight="bold"] The value of the CSS <code>font-weight</code>
+ *  property for the label text shown on the cluster icon.
+ * @property {number} [fontStyle="normal"] The value of the CSS <code>font-style</code>
+ *  property for the label text shown on the cluster icon.
+ * @property {number} [fontFamily="Arial,sans-serif"] The value of the CSS <code>font-family</code>
+ *  property for the label text shown on the cluster icon.
+ * @property {string} [backgroundPosition="0 0"] The position of the cluster icon image
+ *  within the image defined by <code>url</code>. The format is <code>"xpos ypos"</code>
+ *  (the same format as for the CSS <code>background-position</code> property). You must set
+ *  this property appropriately when the image defined by <code>url</code> represents a sprite
+ *  containing multiple images.
+ */
+/**
+ * @name ClusterIconInfo
+ * @class This class is an object containing general information about a cluster icon. This is
+ *  the object that a <code>calculator</code> function returns.
+ *
+ * @property {string} text The text of the label to be shown on the cluster icon.
+ * @property {number} index The index plus 1 of the element in the <code>styles</code>
+ *  array to be used to style the cluster icon.
+ * @property {string} title The tooltip to display when the mouse moves over the cluster icon.
+ *  If this value is <code>undefined</code> or <code>""</code>, <code>title</code> is set to the
+ *  value of the <code>title</code> property passed to the MarkerClusterer.
+ */
+/**
+ * A cluster icon.
+ *
+ * @constructor
+ * @extends google.maps.OverlayView
+ * @param {Cluster} cluster The cluster with which the icon is to be associated.
+ * @param {Array} [styles] An array of {@link ClusterIconStyle} defining the cluster icons
+ *  to use for various cluster sizes.
+ * @private
+ */
+function ClusterIcon(cluster, styles) {
+  cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView);
+
+  this.cluster_ = cluster;
+  this.className_ = cluster.getMarkerClusterer().getClusterClass();
+  this.styles_ = styles;
+  this.center_ = null;
+  this.div_ = null;
+  this.sums_ = null;
+  this.visible_ = false;
+
+  this.setMap(cluster.getMap()); // Note: this causes onAdd to be called
+}
+
+
+/**
+ * Adds the icon to the DOM.
+ */
+ClusterIcon.prototype.onAdd = function () {
+  var cClusterIcon = this;
+  var cMouseDownInCluster;
+  var cDraggingMapByCluster;
+
+  this.div_ = document.createElement("div");
+  this.div_.className = this.className_;
+  if (this.visible_) {
+    this.show();
+  }
+
+  this.getPanes().overlayMouseTarget.appendChild(this.div_);
+
+  // Fix for Issue 157
+  this.boundsChangedListener_ = google.maps.event.addListener(this.getMap(), "bounds_changed", function () {
+    cDraggingMapByCluster = cMouseDownInCluster;
+  });
+
+  google.maps.event.addDomListener(this.div_, "mousedown", function () {
+    cMouseDownInCluster = true;
+    cDraggingMapByCluster = false;
+  });
+
+  google.maps.event.addDomListener(this.div_, "click", function (e) {
+    cMouseDownInCluster = false;
+    if (!cDraggingMapByCluster) {
+      var theBounds;
+      var mz;
+      var mc = cClusterIcon.cluster_.getMarkerClusterer();
+      /**
+       * This event is fired when a cluster marker is clicked.
+       * @name MarkerClusterer#click
+       * @param {Cluster} c The cluster that was clicked.
+       * @event
+       */
+      google.maps.event.trigger(mc, "click", cClusterIcon.cluster_);
+      google.maps.event.trigger(mc, "clusterclick", cClusterIcon.cluster_); // deprecated name
+
+      // The default click handler follows. Disable it by setting
+      // the zoomOnClick property to false.
+      if (mc.getZoomOnClick()) {
+        // Zoom into the cluster.
+        mz = mc.getMaxZoom();
+        theBounds = cClusterIcon.cluster_.getBounds();
+        mc.getMap().fitBounds(theBounds);
+        // There is a fix for Issue 170 here:
+        setTimeout(function () {
+          mc.getMap().fitBounds(theBounds);
+          // Don't zoom beyond the max zoom level
+          if (mz !== null && (mc.getMap().getZoom() > mz)) {
+            mc.getMap().setZoom(mz + 1);
+          }
+        }, 100);
+      }
+
+      // Prevent event propagation to the map:
+      e.cancelBubble = true;
+      if (e.stopPropagation) {
+        e.stopPropagation();
+      }
+    }
+  });
+
+  google.maps.event.addDomListener(this.div_, "mouseover", function () {
+    var mc = cClusterIcon.cluster_.getMarkerClusterer();
+    /**
+     * This event is fired when the mouse moves over a cluster marker.
+     * @name MarkerClusterer#mouseover
+     * @param {Cluster} c The cluster that the mouse moved over.
+     * @event
+     */
+    google.maps.event.trigger(mc, "mouseover", cClusterIcon.cluster_);
+  });
+
+  google.maps.event.addDomListener(this.div_, "mouseout", function () {
+    var mc = cClusterIcon.cluster_.getMarkerClusterer();
+    /**
+     * This event is fired when the mouse moves out of a cluster marker.
+     * @name MarkerClusterer#mouseout
+     * @param {Cluster} c The cluster that the mouse moved out of.
+     * @event
+     */
+    google.maps.event.trigger(mc, "mouseout", cClusterIcon.cluster_);
+  });
+};
+
+
+/**
+ * Removes the icon from the DOM.
+ */
+ClusterIcon.prototype.onRemove = function () {
+  if (this.div_ && this.div_.parentNode) {
+    this.hide();
+    google.maps.event.removeListener(this.boundsChangedListener_);
+    google.maps.event.clearInstanceListeners(this.div_);
+    this.div_.parentNode.removeChild(this.div_);
+    this.div_ = null;
+  }
+};
+
+
+/**
+ * Draws the icon.
+ */
+ClusterIcon.prototype.draw = function () {
+  if (this.visible_) {
+    var pos = this.getPosFromLatLng_(this.center_);
+    this.div_.style.top = pos.y + "px";
+    this.div_.style.left = pos.x + "px";
+  }
+};
+
+
+/**
+ * Hides the icon.
+ */
+ClusterIcon.prototype.hide = function () {
+  if (this.div_) {
+    this.div_.style.display = "none";
+  }
+  this.visible_ = false;
+};
+
+
+/**
+ * Positions and shows the icon.
+ */
+ClusterIcon.prototype.show = function () {
+  if (this.div_) {
+    var pos = this.getPosFromLatLng_(this.center_);
+    this.div_.style.cssText = this.createCss(pos);
+    if (this.cluster_.printable_) {
+      // (Would like to use "width: inherit;" below, but doesn't work with MSIE)
+      this.div_.innerHTML = "<img src='" + this.url_ + "'><div style='position: absolute; top: 0px; left: 0px; width: " + this.width_ + "px;'>" + this.sums_.text + "</div>";
+    } else {
+      this.div_.innerHTML = this.sums_.text;
+    }
+    if (typeof this.sums_.title === "undefined" || this.sums_.title === "") {
+      this.div_.title = this.cluster_.getMarkerClusterer().getTitle();
+    } else {
+      this.div_.title = this.sums_.title;
+    }
+    this.div_.style.display = "";
+  }
+  this.visible_ = true;
+};
+
+
+/**
+ * Sets the icon styles to the appropriate element in the styles array.
+ *
+ * @param {ClusterIconInfo} sums The icon label text and styles index.
+ */
+ClusterIcon.prototype.useStyle = function (sums) {
+  this.sums_ = sums;
+  var index = Math.max(0, sums.index - 1);
+  index = Math.min(this.styles_.length - 1, index);
+  var style = this.styles_[index];
+  this.url_ = style.url;
+  this.height_ = style.height;
+  this.width_ = style.width;
+  this.anchor_ = style.anchor;
+  this.anchorIcon_ = style.anchorIcon || [parseInt(this.height_ / 2, 10), parseInt(this.width_ / 2, 10)];
+  this.textColor_ = style.textColor || "black";
+  this.textSize_ = style.textSize || 11;
+  this.textDecoration_ = style.textDecoration || "none";
+  this.fontWeight_ = style.fontWeight || "bold";
+  this.fontStyle_ = style.fontStyle || "normal";
+  this.fontFamily_ = style.fontFamily || "Arial,sans-serif";
+  this.backgroundPosition_ = style.backgroundPosition || "0 0";
+};
+
+
+/**
+ * Sets the position at which to center the icon.
+ *
+ * @param {google.maps.LatLng} center The latlng to set as the center.
+ */
+ClusterIcon.prototype.setCenter = function (center) {
+  this.center_ = center;
+};
+
+
+/**
+ * Creates the cssText style parameter based on the position of the icon.
+ *
+ * @param {google.maps.Point} pos The position of the icon.
+ * @return {string} The CSS style text.
+ */
+ClusterIcon.prototype.createCss = function (pos) {
+  var style = [];
+  if (!this.cluster_.printable_) {
+    style.push('background-image:url(' + this.url_ + ');');
+    style.push('background-position:' + this.backgroundPosition_ + ';');
+  }
+
+  if (typeof this.anchor_ === 'object') {
+    if (typeof this.anchor_[0] === 'number' && this.anchor_[0] > 0 &&
+        this.anchor_[0] < this.height_) {
+      style.push('height:' + (this.height_ - this.anchor_[0]) +
+          'px; padding-top:' + this.anchor_[0] + 'px;');
+    } else {
+      style.push('height:' + this.height_ + 'px; line-height:' + this.height_ +
+          'px;');
+    }
+    if (typeof this.anchor_[1] === 'number' && this.anchor_[1] > 0 &&
+        this.anchor_[1] < this.width_) {
+      style.push('width:' + (this.width_ - this.anchor_[1]) +
+          'px; padding-left:' + this.anchor_[1] + 'px;');
+    } else {
+      style.push('width:' + this.width_ + 'px; text-align:center;');
+    }
+  } else {
+    style.push('height:' + this.height_ + 'px; line-height:' +
+        this.height_ + 'px; width:' + this.width_ + 'px; text-align:center;');
+  }
+
+  style.push('cursor:pointer; top:' + pos.y + 'px; left:' +
+      pos.x + 'px; color:' + this.textColor_ + '; position:absolute; font-size:' +
+      this.textSize_ + 'px; font-family:' + this.fontFamily_ + '; font-weight:' +
+      this.fontWeight_ + '; font-style:' + this.fontStyle_ + '; text-decoration:' +
+      this.textDecoration_ + ';');
+
+  return style.join("");
+};
+
+
+/**
+ * Returns the position at which to place the DIV depending on the latlng.
+ *
+ * @param {google.maps.LatLng} latlng The position in latlng.
+ * @return {google.maps.Point} The position in pixels.
+ */
+ClusterIcon.prototype.getPosFromLatLng_ = function (latlng) {
+  var pos = this.getProjection().fromLatLngToDivPixel(latlng);
+  pos.x -= this.anchorIcon_[1];
+  pos.y -= this.anchorIcon_[0];
+  return pos;
+};
+
+
+/**
+ * Creates a single cluster that manages a group of proximate markers.
+ *  Used internally, do not call this constructor directly.
+ * @constructor
+ * @param {MarkerClusterer} mc The <code>MarkerClusterer</code> object with which this
+ *  cluster is associated.
+ */
+function Cluster(mc) {
+  this.markerClusterer_ = mc;
+  this.map_ = mc.getMap();
+  this.gridSize_ = mc.getGridSize();
+  this.minClusterSize_ = mc.getMinimumClusterSize();
+  this.averageCenter_ = mc.getAverageCenter();
+  this.printable_ = mc.getPrintable();
+  this.markers_ = [];
+  this.center_ = null;
+  this.bounds_ = null;
+  this.clusterIcon_ = new ClusterIcon(this, mc.getStyles());
+}
+
+
+/**
+ * Returns the number of markers managed by the cluster. You can call this from
+ * a <code>click</code>, <code>mouseover</code>, or <code>mouseout</code> event handler
+ * for the <code>MarkerClusterer</code> object.
+ *
+ * @return {number} The number of markers in the cluster.
+ */
+Cluster.prototype.getSize = function () {
+  return this.markers_.length;
+};
+
+
+/**
+ * Returns the array of markers managed by the cluster. You can call this from
+ * a <code>click</code>, <code>mouseover</code>, or <code>mouseout</code> event handler
+ * for the <code>MarkerClusterer</code> object.
+ *
+ * @return {Array} The array of markers in the cluster.
+ */
+Cluster.prototype.getMarkers = function () {
+  return this.markers_;
+};
+
+
+/**
+ * Returns the center of the cluster. You can call this from
+ * a <code>click</code>, <code>mouseover</code>, or <code>mouseout</code> event handler
+ * for the <code>MarkerClusterer</code> object.
+ *
+ * @return {google.maps.LatLng} The center of the cluster.
+ */
+Cluster.prototype.getCenter = function () {
+  return this.center_;
+};
+
+
+/**
+ * Returns the map with which the cluster is associated.
+ *
+ * @return {google.maps.Map} The map.
+ * @ignore
+ */
+Cluster.prototype.getMap = function () {
+  return this.map_;
+};
+
+
+/**
+ * Returns the <code>MarkerClusterer</code> object with which the cluster is associated.
+ *
+ * @return {MarkerClusterer} The associated marker clusterer.
+ * @ignore
+ */
+Cluster.prototype.getMarkerClusterer = function () {
+  return this.markerClusterer_;
+};
+
+
+/**
+ * Returns the bounds of the cluster.
+ *
+ * @return {google.maps.LatLngBounds} the cluster bounds.
+ * @ignore
+ */
+Cluster.prototype.getBounds = function () {
+  var i;
+  var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
+  var markers = this.getMarkers();
+  for (i = 0; i < markers.length; i++) {
+    bounds.extend(markers[i].getPosition());
+  }
+  return bounds;
+};
+
+
+/**
+ * Removes the cluster from the map.
+ *
+ * @ignore
+ */
+Cluster.prototype.remove = function () {
+  this.clusterIcon_.setMap(null);
+  this.markers_ = [];
+  delete this.markers_;
+};
+
+
+/**
+ * Adds a marker to the cluster.
+ *
+ * @param {google.maps.Marker} marker The marker to be added.
+ * @return {boolean} True if the marker was added.
+ * @ignore
+ */
+Cluster.prototype.addMarker = function (marker) {
+  var i;
+  var mCount;
+  var mz;
+
+  if (this.isMarkerAlreadyAdded_(marker)) {
+    return false;
+  }
+
+  if (!this.center_) {
+    this.center_ = marker.getPosition();
+    this.calculateBounds_();
+  } else {
+    if (this.averageCenter_) {
+      var l = this.markers_.length + 1;
+      var lat = (this.center_.lat() * (l - 1) + marker.getPosition().lat()) / l;
+      var lng = (this.center_.lng() * (l - 1) + marker.getPosition().lng()) / l;
+      this.center_ = new google.maps.LatLng(lat, lng);
+      this.calculateBounds_();
+    }
+  }
+
+  marker.isAdded = true;
+  this.markers_.push(marker);
+
+  mCount = this.markers_.length;
+  mz = this.markerClusterer_.getMaxZoom();
+  if (mz !== null && this.map_.getZoom() > mz) {
+    // Zoomed in past max zoom, so show the marker.
+    if (marker.getMap() !== this.map_) {
+      marker.setMap(this.map_);
+    }
+  } else if (mCount < this.minClusterSize_) {
+    // Min cluster size not reached so show the marker.
+    if (marker.getMap() !== this.map_) {
+      marker.setMap(this.map_);
+    }
+  } else if (mCount === this.minClusterSize_) {
+    // Hide the markers that were showing.
+    for (i = 0; i < mCount; i++) {
+      this.markers_[i].setMap(null);
+    }
+  } else {
+    marker.setMap(null);
+  }
+
+  this.updateIcon_();
+  return true;
+};
+
+
+/**
+ * Determines if a marker lies within the cluster's bounds.
+ *
+ * @param {google.maps.Marker} marker The marker to check.
+ * @return {boolean} True if the marker lies in the bounds.
+ * @ignore
+ */
+Cluster.prototype.isMarkerInClusterBounds = function (marker) {
+  return this.bounds_.contains(marker.getPosition());
+};
+
+
+/**
+ * Calculates the extended bounds of the cluster with the grid.
+ */
+Cluster.prototype.calculateBounds_ = function () {
+  var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
+  this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds);
+};
+
+
+/**
+ * Updates the cluster icon.
+ */
+Cluster.prototype.updateIcon_ = function () {
+  var mCount = this.markers_.length;
+  var mz = this.markerClusterer_.getMaxZoom();
+
+  if (mz !== null && this.map_.getZoom() > mz) {
+    this.clusterIcon_.hide();
+    return;
+  }
+
+  if (mCount < this.minClusterSize_) {
+    // Min cluster size not yet reached.
+    this.clusterIcon_.hide();
+    return;
+  }
+
+  var numStyles = this.markerClusterer_.getStyles().length;
+  var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles);
+  this.clusterIcon_.setCenter(this.center_);
+  this.clusterIcon_.useStyle(sums);
+  this.clusterIcon_.show();
+};
+
+
+/**
+ * Determines if a marker has already been added to the cluster.
+ *
+ * @param {google.maps.Marker} marker The marker to check.
+ * @return {boolean} True if the marker has already been added.
+ */
+Cluster.prototype.isMarkerAlreadyAdded_ = function (marker) {
+  var i;
+  if (this.markers_.indexOf) {
+    return this.markers_.indexOf(marker) !== -1;
+  } else {
+    for (i = 0; i < this.markers_.length; i++) {
+      if (marker === this.markers_[i]) {
+        return true;
+      }
+    }
+  }
+  return false;
+};
+
+
+/**
+ * @name MarkerClustererOptions
+ * @class This class represents the optional parameter passed to
+ *  the {@link MarkerClusterer} constructor.
+ * @property {number} [gridSize=60] The grid size of a cluster in pixels. The grid is a square.
+ * @property {number} [maxZoom=null] The maximum zoom level at which clustering is enabled or
+ *  <code>null</code> if clustering is to be enabled at all zoom levels.
+ * @property {boolean} [zoomOnClick=true] Whether to zoom the map when a cluster marker is
+ *  clicked. You may want to set this to <code>false</code> if you have installed a handler
+ *  for the <code>click</code> event and it deals with zooming on its own.
+ * @property {boolean} [averageCenter=false] Whether the position of a cluster marker should be
+ *  the average position of all markers in the cluster. If set to <code>false</code>, the
+ *  cluster marker is positioned at the location of the first marker added to the cluster.
+ * @property {number} [minimumClusterSize=2] The minimum number of markers needed in a cluster
+ *  before the markers are hidden and a cluster marker appears.
+ * @property {boolean} [ignoreHidden=false] Whether to ignore hidden markers in clusters. You
+ *  may want to set this to <code>true</code> to ensure that hidden markers are not included
+ *  in the marker count that appears on a cluster marker (this count is the value of the
+ *  <code>text</code> property of the result returned by the default <code>calculator</code>).
+ *  If set to <code>true</code> and you change the visibility of a marker being clustered, be
+ *  sure to also call <code>MarkerClusterer.repaint()</code>.
+ * @property {boolean} [printable=false] Whether to make the cluster icons printable. Do not
+ *  set to <code>true</code> if the <code>url</code> fields in the <code>styles</code> array
+ *  refer to image sprite files.
+ * @property {string} [title=""] The tooltip to display when the mouse moves over a cluster
+ *  marker. (Alternatively, you can use a custom <code>calculator</code> function to specify a
+ *  different tooltip for each cluster marker.)
+ * @property {function} [calculator=MarkerClusterer.CALCULATOR] The function used to determine
+ *  the text to be displayed on a cluster marker and the index indicating which style to use
+ *  for the cluster marker. The input parameters for the function are (1) the array of markers
+ *  represented by a cluster marker and (2) the number of cluster icon styles. It returns a
+ *  {@link ClusterIconInfo} object. The default <code>calculator</code> returns a
+ *  <code>text</code> property which is the number of markers in the cluster and an
+ *  <code>index</code> property which is one higher than the lowest integer such that
+ *  <code>10^i</code> exceeds the number of markers in the cluster, or the size of the styles
+ *  array, whichever is less. The <code>styles</code> array element used has an index of
+ *  <code>index</code> minus 1. For example, the default <code>calculator</code> returns a
+ *  <code>text</code> value of <code>"125"</code> and an <code>index</code> of <code>3</code>
+ *  for a cluster icon representing 125 markers so the element used in the <code>styles</code>
+ *  array is <code>2</code>. A <code>calculator</code> may also return a <code>title</code>
+ *  property that contains the text of the tooltip to be used for the cluster marker. If
+ *   <code>title</code> is not defined, the tooltip is set to the value of the <code>title</code>
+ *   property for the MarkerClusterer.
+ * @property {string} [clusterClass="cluster"] The name of the CSS class defining general styles
+ *  for the cluster markers. Use this class to define CSS styles that are not set up by the code
+ *  that processes the <code>styles</code> array.
+ * @property {Array} [styles] An array of {@link ClusterIconStyle} elements defining the styles
+ *  of the cluster markers to be used. The element to be used to style a given cluster marker
+ *  is determined by the function defined by the <code>calculator</code> property.
+ *  The default is an array of {@link ClusterIconStyle} elements whose properties are derived
+ *  from the values for <code>imagePath</code>, <code>imageExtension</code>, and
+ *  <code>imageSizes</code>.
+ * @property {number} [batchSize=MarkerClusterer.BATCH_SIZE] Set this property to the
+ *  number of markers to be processed in a single batch when using a browser other than
+ *  Internet Explorer (for Internet Explorer, use the batchSizeIE property instead).
+ * @property {number} [batchSizeIE=MarkerClusterer.BATCH_SIZE_IE] When Internet Explorer is
+ *  being used, markers are processed in several batches with a small delay inserted between
+ *  each batch in an attempt to avoid Javascript timeout errors. Set this property to the
+ *  number of markers to be processed in a single batch; select as high a number as you can
+ *  without causing a timeout error in the browser. This number might need to be as low as 100
+ *  if 15,000 markers are being managed, for example.
+ * @property {string} [imagePath=MarkerClusterer.IMAGE_PATH]
+ *  The full URL of the root name of the group of image files to use for cluster icons.
+ *  The complete file name is of the form <code>imagePath</code>n.<code>imageExtension</code>
+ *  where n is the image file number (1, 2, etc.).
+ * @property {string} [imageExtension=MarkerClusterer.IMAGE_EXTENSION]
+ *  The extension name for the cluster icon image files (e.g., <code>"png"</code> or
+ *  <code>"jpg"</code>).
+ * @property {Array} [imageSizes=MarkerClusterer.IMAGE_SIZES]
+ *  An array of numbers containing the widths of the group of
+ *  <code>imagePath</code>n.<code>imageExtension</code> image files.
+ *  (The images are assumed to be square.)
+ */
+/**
+ * Creates a MarkerClusterer object with the options specified in {@link MarkerClustererOptions}.
+ * @constructor
+ * @extends google.maps.OverlayView
+ * @param {google.maps.Map} map The Google map to attach to.
+ * @param {Array.<google.maps.Marker>} [opt_markers] The markers to be added to the cluster.
+ * @param {MarkerClustererOptions} [opt_options] The optional parameters.
+ */
+function MarkerClusterer(map, opt_markers, opt_options) {
+  // MarkerClusterer implements google.maps.OverlayView interface. We use the
+  // extend function to extend MarkerClusterer with google.maps.OverlayView
+  // because it might not always be available when the code is defined so we
+  // look for it at the last possible moment. If it doesn't exist now then
+  // there is no point going ahead :)
+  this.extend(MarkerClusterer, google.maps.OverlayView);
+
+  opt_markers = opt_markers || [];
+  opt_options = opt_options || {};
+
+  this.markers_ = [];
+  this.clusters_ = [];
+  this.listeners_ = [];
+  this.activeMap_ = null;
+  this.ready_ = false;
+
+  this.gridSize_ = opt_options.gridSize || 60;
+  this.minClusterSize_ = opt_options.minimumClusterSize || 2;
+  this.maxZoom_ = opt_options.maxZoom || null;
+  this.styles_ = opt_options.styles || [];
+  this.title_ = opt_options.title || "";
+  this.zoomOnClick_ = true;
+  if (opt_options.zoomOnClick !== undefined) {
+    this.zoomOnClick_ = opt_options.zoomOnClick;
+  }
+  this.averageCenter_ = false;
+  if (opt_options.averageCenter !== undefined) {
+    this.averageCenter_ = opt_options.averageCenter;
+  }
+  this.ignoreHidden_ = false;
+  if (opt_options.ignoreHidden !== undefined) {
+    this.ignoreHidden_ = opt_options.ignoreHidden;
+  }
+  this.printable_ = false;
+  if (opt_options.printable !== undefined) {
+    this.printable_ = opt_options.printable;
+  }
+  this.imagePath_ = opt_options.imagePath || MarkerClusterer.IMAGE_PATH;
+  this.imageExtension_ = opt_options.imageExtension || MarkerClusterer.IMAGE_EXTENSION;
+  this.imageSizes_ = opt_options.imageSizes || MarkerClusterer.IMAGE_SIZES;
+  this.calculator_ = opt_options.calculator || MarkerClusterer.CALCULATOR;
+  this.batchSize_ = opt_options.batchSize || MarkerClusterer.BATCH_SIZE;
+  this.batchSizeIE_ = opt_options.batchSizeIE || MarkerClusterer.BATCH_SIZE_IE;
+  this.clusterClass_ = opt_options.clusterClass || "cluster";
+
+  if (navigator.userAgent.toLowerCase().indexOf("msie") !== -1) {
+    // Try to avoid IE timeout when processing a huge number of markers:
+    this.batchSize_ = this.batchSizeIE_;
+  }
+
+  this.setupStyles_();
+
+  this.addMarkers(opt_markers, true);
+  this.setMap(map); // Note: this causes onAdd to be called
+}
+
+
+/**
+ * Implementation of the onAdd interface method.
+ * @ignore
+ */
+MarkerClusterer.prototype.onAdd = function () {
+  var cMarkerClusterer = this;
+
+  this.activeMap_ = this.getMap();
+  this.ready_ = true;
+
+  this.repaint();
+
+  // Add the map event listeners
+  this.listeners_ = [
+    google.maps.event.addListener(this.getMap(), "zoom_changed", function () {
+      cMarkerClusterer.resetViewport_(false);
+      // Workaround for this Google bug: when map is at level 0 and "-" of
+      // zoom slider is clicked, a "zoom_changed" event is fired even though
+      // the map doesn't zoom out any further. In this situation, no "idle"
+      // event is triggered so the cluster markers that have been removed
+      // do not get redrawn. Same goes for a zoom in at maxZoom.
+      if (this.getZoom() === (this.get("minZoom") || 0) || this.getZoom() === this.get("maxZoom")) {
+        google.maps.event.trigger(this, "idle");
+      }
+    }),
+    google.maps.event.addListener(this.getMap(), "idle", function () {
+      cMarkerClusterer.redraw_();
+    })
+  ];
+};
+
+
+/**
+ * Implementation of the onRemove interface method.
+ * Removes map event listeners and all cluster icons from the DOM.
+ * All managed markers are also put back on the map.
+ * @ignore
+ */
+MarkerClusterer.prototype.onRemove = function () {
+  var i;
+
+  // Put all the managed markers back on the map:
+  for (i = 0; i < this.markers_.length; i++) {
+    if (this.markers_[i].getMap() !== this.activeMap_) {
+      this.markers_[i].setMap(this.activeMap_);
+    }
+  }
+
+  // Remove all clusters:
+  for (i = 0; i < this.clusters_.length; i++) {
+    this.clusters_[i].remove();
+  }
+  this.clusters_ = [];
+
+  // Remove map event listeners:
+  for (i = 0; i < this.listeners_.length; i++) {
+    google.maps.event.removeListener(this.listeners_[i]);
+  }
+  this.listeners_ = [];
+
+  this.activeMap_ = null;
+  this.ready_ = false;
+};
+
+
+/**
+ * Implementation of the draw interface method.
+ * @ignore
+ */
+MarkerClusterer.prototype.draw = function () {};
+
+
+/**
+ * Sets up the styles object.
+ */
+MarkerClusterer.prototype.setupStyles_ = function () {
+  var i, size;
+  if (this.styles_.length > 0) {
+    return;
+  }
+
+  for (i = 0; i < this.imageSizes_.length; i++) {
+    size = this.imageSizes_[i];
+    this.styles_.push({
+      url: this.imagePath_ + (i + 1) + "." + this.imageExtension_,
+      height: size,
+      width: size
+    });
+  }
+};
+
+
+/**
+ *  Fits the map to the bounds of the markers managed by the clusterer.
+ */
+MarkerClusterer.prototype.fitMapToMarkers = function () {
+  var i;
+  var markers = this.getMarkers();
+  var bounds = new google.maps.LatLngBounds();
+  for (i = 0; i < markers.length; i++) {
+    bounds.extend(markers[i].getPosition());
+  }
+
+  this.getMap().fitBounds(bounds);
+};
+
+
+/**
+ * Returns the value of the <code>gridSize</code> property.
+ *
+ * @return {number} The grid size.
+ */
+MarkerClusterer.prototype.getGridSize = function () {
+  return this.gridSize_;
+};
+
+
+/**
+ * Sets the value of the <code>gridSize</code> property.
+ *
+ * @param {number} gridSize The grid size.
+ */
+MarkerClusterer.prototype.setGridSize = function (gridSize) {
+  this.gridSize_ = gridSize;
+};
+
+
+/**
+ * Returns the value of the <code>minimumClusterSize</code> property.
+ *
+ * @return {number} The minimum cluster size.
+ */
+MarkerClusterer.prototype.getMinimumClusterSize = function () {
+  return this.minClusterSize_;
+};
+
+/**
+ * Sets the value of the <code>minimumClusterSize</code> property.
+ *
+ * @param {number} minimumClusterSize The minimum cluster size.
+ */
+MarkerClusterer.prototype.setMinimumClusterSize = function (minimumClusterSize) {
+  this.minClusterSize_ = minimumClusterSize;
+};
+
+
+/**
+ *  Returns the value of the <code>maxZoom</code> property.
+ *
+ *  @return {number} The maximum zoom level.
+ */
+MarkerClusterer.prototype.getMaxZoom = function () {
+  return this.maxZoom_;
+};
+
+
+/**
+ *  Sets the value of the <code>maxZoom</code> property.
+ *
+ *  @param {number} maxZoom The maximum zoom level.
+ */
+MarkerClusterer.prototype.setMaxZoom = function (maxZoom) {
+  this.maxZoom_ = maxZoom;
+};
+
+
+/**
+ *  Returns the value of the <code>styles</code> property.
+ *
+ *  @return {Array} The array of styles defining the cluster markers to be used.
+ */
+MarkerClusterer.prototype.getStyles = function () {
+  return this.styles_;
+};
+
+
+/**
+ *  Sets the value of the <code>styles</code> property.
+ *
+ *  @param {Array.<ClusterIconStyle>} styles The array of styles to use.
+ */
+MarkerClusterer.prototype.setStyles = function (styles) {
+  this.styles_ = styles;
+};
+
+
+/**
+ * Returns the value of the <code>title</code> property.
+ *
+ * @return {string} The content of the title text.
+ */
+MarkerClusterer.prototype.getTitle = function () {
+  return this.title_;
+};
+
+
+/**
+ *  Sets the value of the <code>title</code> property.
+ *
+ *  @param {string} title The value of the title property.
+ */
+MarkerClusterer.prototype.setTitle = function (title) {
+  this.title_ = title;
+};
+
+
+/**
+ * Returns the value of the <code>zoomOnClick</code> property.
+ *
+ * @return {boolean} True if zoomOnClick property is set.
+ */
+MarkerClusterer.prototype.getZoomOnClick = function () {
+  return this.zoomOnClick_;
+};
+
+
+/**
+ *  Sets the value of the <code>zoomOnClick</code> property.
+ *
+ *  @param {boolean} zoomOnClick The value of the zoomOnClick property.
+ */
+MarkerClusterer.prototype.setZoomOnClick = function (zoomOnClick) {
+  this.zoomOnClick_ = zoomOnClick;
+};
+
+
+/**
+ * Returns the value of the <code>averageCenter</code> property.
+ *
+ * @return {boolean} True if averageCenter property is set.
+ */
+MarkerClusterer.prototype.getAverageCenter = function () {
+  return this.averageCenter_;
+};
+
+
+/**
+ *  Sets the value of the <code>averageCenter</code> property.
+ *
+ *  @param {boolean} averageCenter The value of the averageCenter property.
+ */
+MarkerClusterer.prototype.setAverageCenter = function (averageCenter) {
+  this.averageCenter_ = averageCenter;
+};
+
+
+/**
+ * Returns the value of the <code>ignoreHidden</code> property.
+ *
+ * @return {boolean} True if ignoreHidden property is set.
+ */
+MarkerClusterer.prototype.getIgnoreHidden = function () {
+  return this.ignoreHidden_;
+};
+
+
+/**
+ *  Sets the value of the <code>ignoreHidden</code> property.
+ *
+ *  @param {boolean} ignoreHidden The value of the ignoreHidden property.
+ */
+MarkerClusterer.prototype.setIgnoreHidden = function (ignoreHidden) {
+  this.ignoreHidden_ = ignoreHidden;
+};
+
+
+/**
+ * Returns the value of the <code>imageExtension</code> property.
+ *
+ * @return {string} The value of the imageExtension property.
+ */
+MarkerClusterer.prototype.getImageExtension = function () {
+  return this.imageExtension_;
+};
+
+
+/**
+ *  Sets the value of the <code>imageExtension</code> property.
+ *
+ *  @param {string} imageExtension The value of the imageExtension property.
+ */
+MarkerClusterer.prototype.setImageExtension = function (imageExtension) {
+  this.imageExtension_ = imageExtension;
+};
+
+
+/**
+ * Returns the value of the <code>imagePath</code> property.
+ *
+ * @return {string} The value of the imagePath property.
+ */
+MarkerClusterer.prototype.getImagePath = function () {
+  return this.imagePath_;
+};
+
+
+/**
+ *  Sets the value of the <code>imagePath</code> property.
+ *
+ *  @param {string} imagePath The value of the imagePath property.
+ */
+MarkerClusterer.prototype.setImagePath = function (imagePath) {
+  this.imagePath_ = imagePath;
+};
+
+
+/**
+ * Returns the value of the <code>imageSizes</code> property.
+ *
+ * @return {Array} The value of the imageSizes property.
+ */
+MarkerClusterer.prototype.getImageSizes = function () {
+  return this.imageSizes_;
+};
+
+
+/**
+ *  Sets the value of the <code>imageSizes</code> property.
+ *
+ *  @param {Array} imageSizes The value of the imageSizes property.
+ */
+MarkerClusterer.prototype.setImageSizes = function (imageSizes) {
+  this.imageSizes_ = imageSizes;
+};
+
+
+/**
+ * Returns the value of the <code>calculator</code> property.
+ *
+ * @return {function} the value of the calculator property.
+ */
+MarkerClusterer.prototype.getCalculator = function () {
+  return this.calculator_;
+};
+
+
+/**
+ * Sets the value of the <code>calculator</code> property.
+ *
+ * @param {function(Array.<google.maps.Marker>, number)} calculator The value
+ *  of the calculator property.
+ */
+MarkerClusterer.prototype.setCalculator = function (calculator) {
+  this.calculator_ = calculator;
+};
+
+
+/**
+ * Returns the value of the <code>printable</code> property.
+ *
+ * @return {boolean} the value of the printable property.
+ */
+MarkerClusterer.prototype.getPrintable = function () {
+  return this.printable_;
+};
+
+
+/**
+ * Sets the value of the <code>printable</code> property.
+ *
+ *  @param {boolean} printable The value of the printable property.
+ */
+MarkerClusterer.prototype.setPrintable = function (printable) {
+  this.printable_ = printable;
+};
+
+
+/**
+ * Returns the value of the <code>batchSizeIE</code> property.
+ *
+ * @return {number} the value of the batchSizeIE property.
+ */
+MarkerClusterer.prototype.getBatchSizeIE = function () {
+  return this.batchSizeIE_;
+};
+
+
+/**
+ * Sets the value of the <code>batchSizeIE</code> property.
+ *
+ *  @param {number} batchSizeIE The value of the batchSizeIE property.
+ */
+MarkerClusterer.prototype.setBatchSizeIE = function (batchSizeIE) {
+  this.batchSizeIE_ = batchSizeIE;
+};
+
+
+/**
+ * Returns the value of the <code>clusterClass</code> property.
+ *
+ * @return {string} the value of the clusterClass property.
+ */
+MarkerClusterer.prototype.getClusterClass = function () {
+  return this.clusterClass_;
+};
+
+
+/**
+ * Sets the value of the <code>clusterClass</code> property.
+ *
+ *  @param {string} clusterClass The value of the clusterClass property.
+ */
+MarkerClusterer.prototype.setClusterClass = function (clusterClass) {
+  this.clusterClass_ = clusterClass;
+};
+
+
+/**
+ *  Returns the array of markers managed by the clusterer.
+ *
+ *  @return {Array} The array of markers managed by the clusterer.
+ */
+MarkerClusterer.prototype.getMarkers = function () {
+  return this.markers_;
+};
+
+
+/**
+ *  Returns the number of markers managed by the clusterer.
+ *
+ *  @return {number} The number of markers.
+ */
+MarkerClusterer.prototype.getTotalMarkers = function () {
+  return this.markers_.length;
+};
+
+
+/**
+ * Returns the current array of clusters formed by the clusterer.
+ *
+ * @return {Array} The array of clusters formed by the clusterer.
+ */
+MarkerClusterer.prototype.getClusters = function () {
+  return this.clusters_;
+};
+
+
+/**
+ * Returns the number of clusters formed by the clusterer.
+ *
+ * @return {number} The number of clusters formed by the clusterer.
+ */
+MarkerClusterer.prototype.getTotalClusters = function () {
+  return this.clusters_.length;
+};
+
+
+/**
+ * Adds a marker to the clusterer. The clusters are redrawn unless
+ *  <code>opt_nodraw</code> is set to <code>true</code>.
+ *
+ * @param {google.maps.Marker} marker The marker to add.
+ * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.
+ */
+MarkerClusterer.prototype.addMarker = function (marker, opt_nodraw) {
+  this.pushMarkerTo_(marker);
+  if (!opt_nodraw) {
+    this.redraw_();
+  }
+};
+
+
+/**
+ * Adds an array of markers to the clusterer. The clusters are redrawn unless
+ *  <code>opt_nodraw</code> is set to <code>true</code>.
+ *
+ * @param {Array.<google.maps.Marker>} markers The markers to add.
+ * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.
+ */
+MarkerClusterer.prototype.addMarkers = function (markers, opt_nodraw) {
+  var i;
+  for (i = 0; i < markers.length; i++) {
+    this.pushMarkerTo_(markers[i]);
+  }
+  if (!opt_nodraw) {
+    this.redraw_();
+  }
+};
+
+
+/**
+ * Pushes a marker to the clusterer.
+ *
+ * @param {google.maps.Marker} marker The marker to add.
+ */
+MarkerClusterer.prototype.pushMarkerTo_ = function (marker) {
+  // If the marker is draggable add a listener so we can update the clusters on the dragend:
+  if (marker.getDraggable()) {
+    var cMarkerClusterer = this;
+    google.maps.event.addListener(marker, "dragend", function () {
+      if (cMarkerClusterer.ready_) {
+        this.isAdded = false;
+        cMarkerClusterer.repaint();
+      }
+    });
+  }
+  marker.isAdded = false;
+  this.markers_.push(marker);
+};
+
+
+/**
+ * Removes a marker from the cluster.  The clusters are redrawn unless
+ *  <code>opt_nodraw</code> is set to <code>true</code>. Returns <code>true</code> if the
+ *  marker was removed from the clusterer.
+ *
+ * @param {google.maps.Marker} marker The marker to remove.
+ * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.
+ * @return {boolean} True if the marker was removed from the clusterer.
+ */
+MarkerClusterer.prototype.removeMarker = function (marker, opt_nodraw) {
+  var removed = this.removeMarker_(marker);
+
+  if (!opt_nodraw && removed) {
+    this.repaint();
+  }
+
+  return removed;
+};
+
+
+/**
+ * Removes an array of markers from the cluster. The clusters are redrawn unless
+ *  <code>opt_nodraw</code> is set to <code>true</code>. Returns <code>true</code> if markers
+ *  were removed from the clusterer.
+ *
+ * @param {Array.<google.maps.Marker>} markers The markers to remove.
+ * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.
+ * @return {boolean} True if markers were removed from the clusterer.
+ */
+MarkerClusterer.prototype.removeMarkers = function (markers, opt_nodraw) {
+  var i, r;
+  var removed = false;
+
+  for (i = 0; i < markers.length; i++) {
+    r = this.removeMarker_(markers[i]);
+    removed = removed || r;
+  }
+
+  if (!opt_nodraw && removed) {
+    this.repaint();
+  }
+
+  return removed;
+};
+
+
+/**
+ * Removes a marker and returns true if removed, false if not.
+ *
+ * @param {google.maps.Marker} marker The marker to remove
+ * @return {boolean} Whether the marker was removed or not
+ */
+MarkerClusterer.prototype.removeMarker_ = function (marker) {
+  var i;
+  var index = -1;
+  if (this.markers_.indexOf) {
+    index = this.markers_.indexOf(marker);
+  } else {
+    for (i = 0; i < this.markers_.length; i++) {
+      if (marker === this.markers_[i]) {
+        index = i;
+        break;
+      }
+    }
+  }
+
+  if (index === -1) {
+    // Marker is not in our list of markers, so do nothing:
+    return false;
+  }
+
+  marker.setMap(null);
+  this.markers_.splice(index, 1); // Remove the marker from the list of managed markers
+  return true;
+};
+
+
+/**
+ * Removes all clusters and markers from the map and also removes all markers
+ *  managed by the clusterer.
+ */
+MarkerClusterer.prototype.clearMarkers = function () {
+  this.resetViewport_(true);
+  this.markers_ = [];
+};
+
+
+/**
+ * Recalculates and redraws all the marker clusters from scratch.
+ *  Call this after changing any properties.
+ */
+MarkerClusterer.prototype.repaint = function () {
+  var oldClusters = this.clusters_.slice();
+  this.clusters_ = [];
+  this.resetViewport_(false);
+  this.redraw_();
+
+  // Remove the old clusters.
+  // Do it in a timeout to prevent blinking effect.
+  setTimeout(function () {
+    var i;
+    for (i = 0; i < oldClusters.length; i++) {
+      oldClusters[i].remove();
+    }
+  }, 0);
+};
+
+
+/**
+ * Returns the current bounds extended by the grid size.
+ *
+ * @param {google.maps.LatLngBounds} bounds The bounds to extend.
+ * @return {google.maps.LatLngBounds} The extended bounds.
+ * @ignore
+ */
+MarkerClusterer.prototype.getExtendedBounds = function (bounds) {
+  var projection = this.getProjection();
+
+  // Turn the bounds into latlng.
+  var tr = new google.maps.LatLng(bounds.getNorthEast().lat(),
+      bounds.getNorthEast().lng());
+  var bl = new google.maps.LatLng(bounds.getSouthWest().lat(),
+      bounds.getSouthWest().lng());
+
+  // Convert the points to pixels and the extend out by the grid size.
+  var trPix = projection.fromLatLngToDivPixel(tr);
+  trPix.x += this.gridSize_;
+  trPix.y -= this.gridSize_;
+
+  var blPix = projection.fromLatLngToDivPixel(bl);
+  blPix.x -= this.gridSize_;
+  blPix.y += this.gridSize_;
+
+  // Convert the pixel points back to LatLng
+  var ne = projection.fromDivPixelToLatLng(trPix);
+  var sw = projection.fromDivPixelToLatLng(blPix);
+
+  // Extend the bounds to contain the new bounds.
+  bounds.extend(ne);
+  bounds.extend(sw);
+
+  return bounds;
+};
+
+
+/**
+ * Redraws all the clusters.
+ */
+MarkerClusterer.prototype.redraw_ = function () {
+  this.createClusters_(0);
+};
+
+
+/**
+ * Removes all clusters from the map. The markers are also removed from the map
+ *  if <code>opt_hide</code> is set to <code>true</code>.
+ *
+ * @param {boolean} [opt_hide] Set to <code>true</code> to also remove the markers
+ *  from the map.
+ */
+MarkerClusterer.prototype.resetViewport_ = function (opt_hide) {
+  var i, marker;
+  // Remove all the clusters
+  for (i = 0; i < this.clusters_.length; i++) {
+    this.clusters_[i].remove();
+  }
+  this.clusters_ = [];
+
+  // Reset the markers to not be added and to be removed from the map.
+  for (i = 0; i < this.markers_.length; i++) {
+    marker = this.markers_[i];
+    marker.isAdded = false;
+    if (opt_hide) {
+      marker.setMap(null);
+    }
+  }
+};
+
+
+/**
+ * Calculates the distance between two latlng locations in km.
+ *
+ * @param {google.maps.LatLng} p1 The first lat lng point.
+ * @param {google.maps.LatLng} p2 The second lat lng point.
+ * @return {number} The distance between the two points in km.
+ * @see http://www.movable-type.co.uk/scripts/latlong.html
+*/
+MarkerClusterer.prototype.distanceBetweenPoints_ = function (p1, p2) {
+  var R = 6371; // Radius of the Earth in km
+  var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;
+  var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;
+  var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
+    Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) *
+    Math.sin(dLon / 2) * Math.sin(dLon / 2);
+  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+  var d = R * c;
+  return d;
+};
+
+
+/**
+ * Determines if a marker is contained in a bounds.
+ *
+ * @param {google.maps.Marker} marker The marker to check.
+ * @param {google.maps.LatLngBounds} bounds The bounds to check against.
+ * @return {boolean} True if the marker is in the bounds.
+ */
+MarkerClusterer.prototype.isMarkerInBounds_ = function (marker, bounds) {
+  return bounds.contains(marker.getPosition());
+};
+
+
+/**
+ * Adds a marker to a cluster, or creates a new cluster.
+ *
+ * @param {google.maps.Marker} marker The marker to add.
+ */
+MarkerClusterer.prototype.addToClosestCluster_ = function (marker) {
+  var i, d, cluster, center;
+  var distance = 40000; // Some large number
+  var clusterToAddTo = null;
+  for (i = 0; i < this.clusters_.length; i++) {
+    cluster = this.clusters_[i];
+    center = cluster.getCenter();
+    if (center) {
+      d = this.distanceBetweenPoints_(center, marker.getPosition());
+      if (d < distance) {
+        distance = d;
+        clusterToAddTo = cluster;
+      }
+    }
+  }
+
+  if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) {
+    clusterToAddTo.addMarker(marker);
+  } else {
+    cluster = new Cluster(this);
+    cluster.addMarker(marker);
+    this.clusters_.push(cluster);
+  }
+};
+
+
+/**
+ * Creates the clusters. This is done in batches to avoid timeout errors
+ *  in some browsers when there is a huge number of markers.
+ *
+ * @param {number} iFirst The index of the first marker in the batch of
+ *  markers to be added to clusters.
+ */
+MarkerClusterer.prototype.createClusters_ = function (iFirst) {
+  var i, marker;
+  var mapBounds;
+  var cMarkerClusterer = this;
+  if (!this.ready_) {
+    return;
+  }
+
+  // Cancel previous batch processing if we're working on the first batch:
+  if (iFirst === 0) {
+    /**
+     * This event is fired when the <code>MarkerClusterer</code> begins
+     *  clustering markers.
+     * @name MarkerClusterer#clusteringbegin
+     * @param {MarkerClusterer} mc The MarkerClusterer whose markers are being clustered.
+     * @event
+     */
+    google.maps.event.trigger(this, "clusteringbegin", this);
+
+    if (typeof this.timerRefStatic !== "undefined") {
+      clearTimeout(this.timerRefStatic);
+      delete this.timerRefStatic;
+    }
+  }
+
+  // Get our current map view bounds.
+  // Create a new bounds object so we don't affect the map.
+  //
+  // See Comments 9 & 11 on Issue 3651 relating to this workaround for a Google Maps bug:
+  if (this.getMap().getZoom() > 3) {
+    mapBounds = new google.maps.LatLngBounds(this.getMap().getBounds().getSouthWest(),
+      this.getMap().getBounds().getNorthEast());
+  } else {
+    mapBounds = new google.maps.LatLngBounds(new google.maps.LatLng(85.02070771743472, -178.48388434375), new google.maps.LatLng(-85.08136444384544, 178.00048865625));
+  }
+  var bounds = this.getExtendedBounds(mapBounds);
+
+  var iLast = Math.min(iFirst + this.batchSize_, this.markers_.length);
+
+  for (i = iFirst; i < iLast; i++) {
+    marker = this.markers_[i];
+    if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) {
+      if (!this.ignoreHidden_ || (this.ignoreHidden_ && marker.getVisible())) {
+        this.addToClosestCluster_(marker);
+      }
+    }
+  }
+
+  if (iLast < this.markers_.length) {
+    this.timerRefStatic = setTimeout(function () {
+      cMarkerClusterer.createClusters_(iLast);
+    }, 0);
+  } else {
+    delete this.timerRefStatic;
+
+    /**
+     * This event is fired when the <code>MarkerClusterer</code> stops
+     *  clustering markers.
+     * @name MarkerClusterer#clusteringend
+     * @param {MarkerClusterer} mc The MarkerClusterer whose markers are being clustered.
+     * @event
+     */
+    google.maps.event.trigger(this, "clusteringend", this);
+  }
+};
+
+
+/**
+ * Extends an object's prototype by another's.
+ *
+ * @param {Object} obj1 The object to be extended.
+ * @param {Object} obj2 The object to extend with.
+ * @return {Object} The new extended object.
+ * @ignore
+ */
+MarkerClusterer.prototype.extend = function (obj1, obj2) {
+  return (function (object) {
+    var property;
+    for (property in object.prototype) {
+      this.prototype[property] = object.prototype[property];
+    }
+    return this;
+  }).apply(obj1, [obj2]);
+};
+
+
+/**
+ * The default function for determining the label text and style
+ * for a cluster icon.
+ *
+ * @param {Array.<google.maps.Marker>} markers The array of markers represented by the cluster.
+ * @param {number} numStyles The number of marker styles available.
+ * @return {ClusterIconInfo} The information resource for the cluster.
+ * @constant
+ * @ignore
+ */
+MarkerClusterer.CALCULATOR = function (markers, numStyles) {
+  var index = 0;
+  var title = "";
+  var count = markers.length.toString();
+
+  var dv = count;
+  while (dv !== 0) {
+    dv = parseInt(dv / 10, 10);
+    index++;
+  }
+
+  index = Math.min(index, numStyles);
+  return {
+    text: count,
+    index: index,
+    title: title
+  };
+};
+
+
+/**
+ * The number of markers to process in one batch.
+ *
+ * @type {number}
+ * @constant
+ */
+MarkerClusterer.BATCH_SIZE = 2000;
+
+
+/**
+ * The number of markers to process in one batch (IE only).
+ *
+ * @type {number}
+ * @constant
+ */
+MarkerClusterer.BATCH_SIZE_IE = 500;
+
+
+/**
+ * The default root name for the marker cluster images.
+ *
+ * @type {string}
+ * @constant
+ */
+MarkerClusterer.IMAGE_PATH = "http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclustererplus/images/m";
+
+
+/**
+ * The default extension name for the marker cluster images.
+ *
+ * @type {string}
+ * @constant
+ */
+MarkerClusterer.IMAGE_EXTENSION = "png";
+
+
+/**
+ * The default array of sizes for the marker cluster images.
+ *
+ * @type {Array.<number>}
+ * @constant
+ */
+MarkerClusterer.IMAGE_SIZES = [53, 56, 66, 78, 90];
diff --git a/third-party/markerclusterer/markerclusterer-2.0.16.js.url b/third-party/markerclusterer/markerclusterer-2.0.16.js.url
new file mode 100644 (file)
index 0000000..8c78d20
--- /dev/null
@@ -0,0 +1 @@
+http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.16/src/markerclusterer.js
diff --git a/third-party/markerclusterer/markerclusterer-2.0.16_packed.js b/third-party/markerclusterer/markerclusterer-2.0.16_packed.js
new file mode 100644 (file)
index 0000000..4a01ec6
--- /dev/null
@@ -0,0 +1 @@
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('5 H(b,a){b.17().Z(H,o.n.31);4.I=b;4.2E=b.17().2w();4.P=a;4.A=t;4.q=t;4.W=t;4.1s=s;4.L(b.v())}H.6.2D=5(){7 d=4;7 g;7 f;4.q=3E.3y("24");4.q.5n=4.2E;9(4.1s){4.2a()}4.4H().4E.4z(4.q);4.2X=o.n.u.1E(4.v(),"4b",5(){f=g});o.n.u.1D(4.q,"41",5(){g=K;f=s});o.n.u.1D(4.q,"2M",5(e){g=s;9(!f){7 c;7 b;7 a=d.I.17();o.n.u.14(a,"2M",d.I);o.n.u.14(a,"3Y",d.I);9(a.2B()){b=a.1K();c=d.I.1y();a.v().1O(c);1U(5(){a.v().1O(c);9(b!==t&&(a.v().1c()>b)){a.v().3I(b+1)}},3D)}e.3A=K;9(e.2h){e.2h()}}});o.n.u.1D(4.q,"2f",5(){7 a=d.I.17();o.n.u.14(a,"2f",d.I)});o.n.u.1D(4.q,"3m",5(){7 a=d.I.17();o.n.u.14(a,"3m",d.I)})};H.6.2Q=5(){9(4.q&&4.q.3j){4.1M();o.n.u.3f(4.2X);o.n.u.4Z(4.q);4.q.3j.4S(4.q);4.q=t}};H.6.39=5(){9(4.1s){7 a=4.28(4.A);4.q.13.1J=a.y+"B";4.q.13.1F=a.x+"B"}};H.6.1M=5(){9(4.q){4.q.13.3b="2V"}4.1s=s};H.6.2a=5(){9(4.q){7 a=4.28(4.A);4.q.13.4l=4.2T(a);9(4.I.18){4.q.2R="<49 42=\'"+4.22+"\'><24 13=\'20: 2P; 1J: 2N; 1F: 2N; 1a: "+4.X+"B;\'>"+4.W.19+"</24>"}C{4.q.2R=4.W.19}9(1q 4.W.15==="1g"||4.W.15===""){4.q.15=4.I.17().2H()}C{4.q.15=4.W.15}4.q.13.3b=""}4.1s=K};H.6.2F=5(a){4.W=a;7 b=z.3X(0,a.2A-1);b=z.2e(4.P.p-1,b);7 c=4.P[b];4.22=c.1W;4.Q=c.V;4.X=c.1a;4.J=c.3R;4.1T=c.3M||[1P(4.Q/2,10),1P(4.X/2,10)];4.2k=c.3F||"3C";4.2x=c.3z||11;4.2n=c.3w||"2V";4.2C=c.3u||"3t";4.2U=c.3p||"3n";4.3k=c.5j||"5f,5c-59";4.3e=c.4X||"0 0"};H.6.3d=5(a){4.A=a};H.6.2T=5(b){7 a=[];9(!4.I.18){a.F(\'3a-4N:1W(\'+4.22+\');\');a.F(\'3a-20:\'+4.3e+\';\')}9(1q 4.J===\'4L\'){9(1q 4.J[0]===\'36\'&&4.J[0]>0&&4.J[0]<4.Q){a.F(\'V:\'+(4.Q-4.J[0])+\'B; 35-1J:\'+4.J[0]+\'B;\')}C{a.F(\'V:\'+4.Q+\'B; 34-V:\'+4.Q+\'B;\')}9(1q 4.J[1]===\'36\'&&4.J[1]>0&&4.J[1]<4.X){a.F(\'1a:\'+(4.X-4.J[1])+\'B; 35-1F:\'+4.J[1]+\'B;\')}C{a.F(\'1a:\'+4.X+\'B; 19-32:1e;\')}}C{a.F(\'V:\'+4.Q+\'B; 34-V:\'+4.Q+\'B; 1a:\'+4.X+\'B; 19-32:1e;\')}a.F(\'4D:4B; 1J:\'+b.y+\'B; 1F:\'+b.x+\'B; 4A:\'+4.2k+\'; 20:2P; 1A-1l:\'+4.2x+\'B; 1A-4x:\'+4.3k+\'; 1A-4v:\'+4.2C+\'; 1A-13:\'+4.2U+\'; 19-4u:\'+4.2n+\';\');j a.4r("")};H.6.28=5(b){7 a=4.3l().2d(b);a.x-=4.1T[1];a.y-=4.1T[0];j a};5 E(a){4.16=a;4.U=a.v();4.S=a.2S();4.12=a.3i();4.1d=a.3g();4.18=a.3h();4.k=[];4.A=t;4.23=t;4.Y=G H(4,a.21())}E.6.40=5(){j 4.k.p};E.6.1C=5(){j 4.k};E.6.2O=5(){j 4.A};E.6.v=5(){j 4.U};E.6.17=5(){j 4.16};E.6.1y=5(){7 i;7 b=G o.n.1r(4.A,4.A);7 a=4.1C();w(i=0;i<a.p;i++){b.Z(a[i].T())}j b};E.6.1B=5(){4.Y.L(t);4.k=[];1Z 4.k};E.6.1G=5(e){7 i;7 c;7 b;9(4.2L(e)){j s}9(!4.A){4.A=e.T();4.1Y()}C{9(4.1d){7 l=4.k.p+1;7 a=(4.A.O()*(l-1)+e.T().O())/l;7 d=(4.A.1f()*(l-1)+e.T().1f())/l;4.A=G o.n.1u(a,d);4.1Y()}}e.1p=K;4.k.F(e);c=4.k.p;b=4.16.1K();9(b!==t&&4.U.1c()>b){9(e.v()!==4.U){e.L(4.U)}}C 9(c<4.12){9(e.v()!==4.U){e.L(4.U)}}C 9(c===4.12){w(i=0;i<c;i++){4.k[i].L(t)}}C{e.L(t)}4.2K();j K};E.6.2J=5(a){j 4.23.2I(a.T())};E.6.1Y=5(){7 a=G o.n.1r(4.A,4.A);4.23=4.16.1X(a)};E.6.2K=5(){7 c=4.k.p;7 a=4.16.1K();9(a!==t&&4.U.1c()>a){4.Y.1M();j}9(c<4.12){4.Y.1M();j}7 b=4.16.21().p;7 d=4.16.2G()(4.k,b);4.Y.3d(4.A);4.Y.2F(d);4.Y.2a()};E.6.2L=5(a){7 i;9(4.k.1o){j 4.k.1o(a)!==-1}C{w(i=0;i<4.k.p;i++){9(a===4.k[i]){j K}}}j s};5 8(a,c,b){4.Z(8,o.n.31);c=c||[];b=b||{};4.k=[];4.D=[];4.1n=[];4.1h=t;4.1j=s;4.S=b.3W||3V;4.12=b.3U||2;4.2c=b.2y||t;4.P=b.3T||[];4.1V=b.15||"";4.1L=K;9(b.2v!==1g){4.1L=b.2v}4.1d=s;9(b.2u!==1g){4.1d=b.2u}4.1b=s;9(b.2t!==1g){4.1b=b.2t}4.18=s;9(b.2s!==1g){4.18=b.2s}4.1z=b.3S||8.2r;4.1v=b.3Q||8.2p;4.1i=b.3L||8.2i;4.1S=b.3J||8.2m;4.1R=b.3H||8.2l;4.1x=b.3G||8.2j;4.1Q=b.3K||"N";9(3B.3N.3O().1o("3P")!==-1){4.1R=4.1x}4.2q();4.2o(c,K);4.L(a)}8.6.2D=5(){7 a=4;4.1h=4.v();4.1j=K;4.1k();4.1n=[o.n.u.1E(4.v(),"3x",5(){a.1w(s);9(4.1c()===(4.2g("3v")||0)||4.1c()===4.2g("2y")){o.n.u.14(4,"2z")}}),o.n.u.1E(4.v(),"2z",5(){a.1m()})]};8.6.2Q=5(){7 i;w(i=0;i<4.k.p;i++){9(4.k[i].v()!==4.1h){4.k[i].L(4.1h)}}w(i=0;i<4.D.p;i++){4.D[i].1B()}4.D=[];w(i=0;i<4.1n.p;i++){o.n.u.3f(4.1n[i])}4.1n=[];4.1h=t;4.1j=s};8.6.39=5(){};8.6.2q=5(){7 i,1l;9(4.P.p>0){j}w(i=0;i<4.1i.p;i++){1l=4.1i[i];4.P.F({1W:4.1z+(i+1)+"."+4.1v,V:1l,1a:1l})}};8.6.3Z=5(){7 i;7 a=4.1C();7 b=G o.n.1r();w(i=0;i<a.p;i++){b.Z(a[i].T())}4.v().1O(b)};8.6.2S=5(){j 4.S};8.6.3s=5(a){4.S=a};8.6.3i=5(){j 4.12};8.6.3r=5(a){4.12=a};8.6.1K=5(){j 4.2c};8.6.3q=5(a){4.2c=a};8.6.21=5(){j 4.P};8.6.43=5(a){4.P=a};8.6.2H=5(){j 4.1V};8.6.3o=5(a){4.1V=a};8.6.2B=5(){j 4.1L};8.6.45=5(a){4.1L=a};8.6.3g=5(){j 4.1d};8.6.46=5(a){4.1d=a};8.6.47=5(){j 4.1b};8.6.5m=5(a){4.1b=a};8.6.5k=5(){j 4.1v};8.6.5i=5(a){4.1v=a};8.6.5h=5(){j 4.1z};8.6.5e=5(a){4.1z=a};8.6.5d=5(){j 4.1i};8.6.5b=5(a){4.1i=a};8.6.2G=5(){j 4.1S};8.6.5a=5(a){4.1S=a};8.6.3h=5(){j 4.18};8.6.57=5(a){4.18=a};8.6.54=5(){j 4.1x};8.6.51=5(a){4.1x=a};8.6.2w=5(){j 4.1Q};8.6.50=5(a){4.1Q=a};8.6.1C=5(){j 4.k};8.6.4V=5(){j 4.k.p};8.6.4U=5(){j 4.D};8.6.4T=5(){j 4.D.p};8.6.1G=5(b,a){4.2b(b);9(!a){4.1m()}};8.6.2o=5(b,a){7 i;w(i=0;i<b.p;i++){4.2b(b[i])}9(!a){4.1m()}};8.6.2b=5(b){9(b.4R()){7 a=4;o.n.u.1E(b,"4P",5(){9(a.1j){4.1p=s;a.1k()}})}b.1p=s;4.k.F(b)};8.6.4O=5(c,a){7 b=4.29(c);9(!a&&b){4.1k()}j b};8.6.4M=5(a,c){7 i,r;7 b=s;w(i=0;i<a.p;i++){r=4.29(a[i]);b=b||r}9(!c&&b){4.1k()}j b};8.6.29=5(b){7 i;7 a=-1;9(4.k.1o){a=4.k.1o(b)}C{w(i=0;i<4.k.p;i++){9(b===4.k[i]){a=i;4K}}}9(a===-1){j s}b.L(t);4.k.4I(a,1);j K};8.6.4G=5(){4.1w(K);4.k=[]};8.6.1k=5(){7 a=4.D.4F();4.D=[];4.1w(s);4.1m();1U(5(){7 i;w(i=0;i<a.p;i++){a[i].1B()}},0)};8.6.1X=5(d){7 f=4.3l();7 c=G o.n.1u(d.25().O(),d.25().1f());7 a=G o.n.1u(d.26().O(),d.26().1f());7 e=f.2d(c);e.x+=4.S;e.y-=4.S;7 g=f.2d(a);g.x-=4.S;g.y+=4.S;7 b=f.33(e);7 h=f.33(g);d.Z(b);d.Z(h);j d};8.6.1m=5(){4.27(0)};8.6.1w=5(a){7 i,M;w(i=0;i<4.D.p;i++){4.D[i].1B()}4.D=[];w(i=0;i<4.k.p;i++){M=4.k[i];M.1p=s;9(a){M.L(t)}}};8.6.30=5(b,e){7 R=4C;7 g=(e.O()-b.O())*z.1I/1H;7 f=(e.1f()-b.1f())*z.1I/1H;7 a=z.1N(g/2)*z.1N(g/2)+z.3c(b.O()*z.1I/1H)*z.3c(e.O()*z.1I/1H)*z.1N(f/2)*z.1N(f/2);7 c=2*z.4J(z.2Z(a),z.2Z(1-a));7 d=R*c;j d};8.6.37=5(b,a){j a.2I(b.T())};8.6.2Y=5(c){7 i,d,N,1e;7 a=4y;7 b=t;w(i=0;i<4.D.p;i++){N=4.D[i];1e=N.2O();9(1e){d=4.30(1e,c.T());9(d<a){a=d;b=N}}}9(b&&b.2J(c)){b.1G(c)}C{N=G E(4);N.1G(c);4.D.F(N)}};8.6.27=5(e){7 i,M;7 d;7 c=4;9(!4.1j){j}9(e===0){o.n.u.14(4,"4w",4);9(1q 4.1t!=="1g"){4Q(4.1t);1Z 4.1t}}9(4.v().1c()>3){d=G o.n.1r(4.v().1y().26(),4.v().1y().25())}C{d=G o.n.1r(G o.n.1u(38.4t,-2W.4s),G o.n.1u(-38.4q,2W.4W))}7 a=4.1X(d);7 b=z.2e(e+4.1R,4.k.p);w(i=e;i<b;i++){M=4.k[i];9(!M.1p&&4.37(M,a)){9(!4.1b||(4.1b&&M.4p())){4.2Y(M)}}}9(b<4.k.p){4.1t=1U(5(){c.27(b)},0)}C{1Z 4.1t;o.n.u.14(4,"4Y",4)}};8.6.Z=5(d,c){j(5(b){7 a;w(a 4o b.6){4.6[a]=b.6[a]}j 4}).4n(d,[c])};8.2m=5(a,c){7 f=0;7 b="";7 d=a.p.4m();7 e=d;52(e!==0){e=1P(e/10,10);f++}f=z.2e(f,c);j{19:d,2A:f,15:b}};8.2l=4k;8.2j=55;8.2r="4j://o-n-58-4i-4h.4g.4f/4e/4d/4c/5g/m";8.2p="4a";8.2i=[53,56,48,5l,44];',62,334,'||||this|function|prototype|var|MarkerClusterer|if||||||||||return|markers_|||maps|google|length|div_||false|null|event|getMap|for|||Math|center_|px|else|clusters_|Cluster|push|new|ClusterIcon|cluster_|anchor_|true|setMap|marker|cluster|lat|styles_|height_||gridSize_|getPosition|map_|height|sums_|width_|clusterIcon_|extend|||minClusterSize_|style|trigger|title|markerClusterer_|getMarkerClusterer|printable_|text|width|ignoreHidden_|getZoom|averageCenter_|center|lng|undefined|activeMap_|imageSizes_|ready_|repaint|size|redraw_|listeners_|indexOf|isAdded|typeof|LatLngBounds|visible_|timerRefStatic|LatLng|imageExtension_|resetViewport_|batchSizeIE_|getBounds|imagePath_|font|remove|getMarkers|addDomListener|addListener|left|addMarker|180|PI|top|getMaxZoom|zoomOnClick_|hide|sin|fitBounds|parseInt|clusterClass_|batchSize_|calculator_|anchorIcon_|setTimeout|title_|url|getExtendedBounds|calculateBounds_|delete|position|getStyles|url_|bounds_|div|getNorthEast|getSouthWest|createClusters_|getPosFromLatLng_|removeMarker_|show|pushMarkerTo_|maxZoom_|fromLatLngToDivPixel|min|mouseover|get|stopPropagation|IMAGE_SIZES|BATCH_SIZE_IE|textColor_|BATCH_SIZE|CALCULATOR|textDecoration_|addMarkers|IMAGE_EXTENSION|setupStyles_|IMAGE_PATH|printable|ignoreHidden|averageCenter|zoomOnClick|getClusterClass|textSize_|maxZoom|idle|index|getZoomOnClick|fontWeight_|onAdd|className_|useStyle|getCalculator|getTitle|contains|isMarkerInClusterBounds|updateIcon_|isMarkerAlreadyAdded_|click|0px|getCenter|absolute|onRemove|innerHTML|getGridSize|createCss|fontStyle_|none|178|boundsChangedListener_|addToClosestCluster_|sqrt|distanceBetweenPoints_|OverlayView|align|fromDivPixelToLatLng|line|padding|number|isMarkerInBounds_|85|draw|background|display|cos|setCenter|backgroundPosition_|removeListener|getAverageCenter|getPrintable|getMinimumClusterSize|parentNode|fontFamily_|getProjection|mouseout|normal|setTitle|fontStyle|setMaxZoom|setMinimumClusterSize|setGridSize|bold|fontWeight|minZoom|textDecoration|zoom_changed|createElement|textSize|cancelBubble|navigator|black|100|document|textColor|batchSizeIE|batchSize|setZoom|calculator|clusterClass|imageSizes|anchorIcon|userAgent|toLowerCase|msie|imageExtension|anchor|imagePath|styles|minimumClusterSize|60|gridSize|max|clusterclick|fitMapToMarkers|getSize|mousedown|src|setStyles|90|setZoomOnClick|setAverageCenter|getIgnoreHidden|66|img|png|bounds_changed|markerclustererplus|trunk|svn|com|googlecode|v3|library|http|2000|cssText|toString|apply|in|getVisible|08136444384544|join|48388434375|02070771743472|decoration|weight|clusteringbegin|family|40000|appendChild|color|pointer|6371|cursor|overlayMouseTarget|slice|clearMarkers|getPanes|splice|atan2|break|object|removeMarkers|image|removeMarker|dragend|clearTimeout|getDraggable|removeChild|getTotalClusters|getClusters|getTotalMarkers|00048865625|backgroundPosition|clusteringend|clearInstanceListeners|setClusterClass|setBatchSizeIE|while||getBatchSizeIE|500||setPrintable|utility|serif|setCalculator|setImageSizes|sans|getImageSizes|setImagePath|Arial|images|getImagePath|setImageExtension|fontFamily|getImageExtension|78|setIgnoreHidden|className'.split('|'),0,{}))
\ No newline at end of file
diff --git a/third-party/markerclusterer/markerclusterer-2.0.16_packed.js.url b/third-party/markerclusterer/markerclusterer-2.0.16_packed.js.url
new file mode 100644 (file)
index 0000000..e56914a
--- /dev/null
@@ -0,0 +1 @@
+http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.16/src/markerclusterer_packed.js
diff --git a/third-party/markerclusterer/markerclusterer.js b/third-party/markerclusterer/markerclusterer.js
new file mode 120000 (symlink)
index 0000000..4086f5c
--- /dev/null
@@ -0,0 +1 @@
+markerclusterer-2.0.16.js
\ No newline at end of file
diff --git a/third-party/markerclusterer/markerclusterer_packed.js b/third-party/markerclusterer/markerclusterer_packed.js
new file mode 120000 (symlink)
index 0000000..74a48c9
--- /dev/null
@@ -0,0 +1 @@
+markerclusterer-2.0.16_packed.js
\ No newline at end of file