diff --git a/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_cluster.js b/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_cluster.js
new file mode 100644
index 0000000..1bcb298
--- /dev/null
+++ b/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_cluster.js
@@ -0,0 +1,38 @@
+// $Id$
+
+/**
+ * OpenLayers Cluster Behavior
+ */
+Drupal.behaviors.openlayers_cluster = function(context) {
+
+  var data = $(context).data('openlayers');
+  if (!data) return;
+
+  var opts = data.map.behaviors['openlayers_behavior_cluster'];
+  if (!opts) return;
+
+  var map = data.openlayers;
+
+  var distance = parseInt(opts.distance);
+  var threshold = parseInt(opts.threshold);
+  // should we explicitly handle NaN here ?
+
+  var layers = map.getLayersBy('drupalID', opts.clusterlayer);
+  for (var i in layers) {
+
+    var layer = layers[i];
+
+    // Would it be better to let it pass by and rely on inner exceptions ?
+    if(layer.CLASS_NAME != "OpenLayers.Layer.Vector") continue;
+
+    var cluster = new OpenLayers.Strategy.Cluster();
+    cluster.distance = distance;
+    cluster.threshold = threshold;
+    layer.addOptions({ 'strategies': [cluster] }); 
+    cluster.setLayer( layer );
+    cluster.features = layer.features.slice();
+    cluster.activate();
+    cluster.cluster();
+  }
+
+}
diff --git a/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_popup.js b/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_popup.js
index b9842f4..b98a901 100644
--- a/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_popup.js
+++ b/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_popup.js
@@ -10,10 +10,30 @@
  *  OpenLayers feature object
  * @return
  *  Formatted HTML
+ *
+ * @todo merge with openlayers_behavior_tooltip_popup_content ?
  */
 function openlayers_behavior_popup_popup_content(feature) {
-  return "<div class='openlayers-popup'>" + feature.attributes.name +"</div>" +
-         "<div class='openlayers-popup'>" + feature.attributes.description +"</div>";
+  if ( feature.cluster )
+  {
+    var visited = []; // to keep trac of already-visited items
+    var info = '';
+    for(var i = 0; i < feature.cluster.length; i++) {
+      var pf = feature.cluster[i]; // pseudo-feature
+      // should we use layer.name rather than drupalID here ?
+      var mapwide_id = feature.layer.drupalID+pf.drupalFID;
+      // skip duplicates
+      if ( visited[mapwide_id] ) continue;
+      visited[mapwide_id] = true;
+      info += openlayers_behavior_popup_popup_content(pf);
+    }
+    return info;
+  }
+  else
+  {
+    return "<div class='openlayers-popup'>" + feature.attributes.name + "</div>" +
+           "<div class='openlayers-popup'>" + feature.attributes.description +"</div>";
+  }
 }
 
 var openlayers_behavior_popup_popup_select, openlayers_behavior_popup_selected_feature;
diff --git a/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_tooltip.js b/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_tooltip.js
index 699e12d..3dcafbd 100644
--- a/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_tooltip.js
+++ b/sites/all/modules/openlayers/includes/behaviors/js/openlayers_behavior_tooltip.js
@@ -10,10 +10,30 @@
  *  OpenLayers feature object
  * @return
  *  Formatted HTML
+ *
+ * @todo merge with openlayers_behavior_popup_popup_content ?
  */
 function openlayers_behavior_tooltip_popup_content(feature) {
-  return "<div class='openlayers-popup'>" + feature.attributes.name +"</div>" +
-         "<div class='openlayers-popup'>" + feature.attributes.description +"</div>";
+  if ( feature.cluster )
+  {
+    var visited = []; // to keep trac of already-visited items
+    var info = '';
+    for(var i = 0; i < feature.cluster.length; i++) {
+      var pf = feature.cluster[i]; // pseudo-feature
+      // should we use layer.name rather than drupalID here ?
+      var mapwide_id = feature.layer.drupalID+pf.drupalFID;
+      // skip duplicates
+      if ( visited[mapwide_id] ) continue;
+      visited[mapwide_id] = true;
+      info += openlayers_behavior_popup_popup_content(pf);
+    }
+    return info;
+  }
+  else
+  {
+    return "<div class='openlayers-popup'>" + feature.attributes.name +"</div>" +
+           "<div class='openlayers-popup'>" + feature.attributes.description +"</div>";
+  }
 }
 
 
diff --git a/sites/all/modules/openlayers/includes/behaviors/openlayers_behavior_cluster.inc b/sites/all/modules/openlayers/includes/behaviors/openlayers_behavior_cluster.inc
new file mode 100644
index 0000000..99e2397
--- /dev/null
+++ b/sites/all/modules/openlayers/includes/behaviors/openlayers_behavior_cluster.inc
@@ -0,0 +1,70 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Implementation of OpenLayers Cluster behavior.
+ */
+
+/**
+ * Cluster behavior
+ */
+class openlayers_behavior_cluster extends openlayers_behavior {
+  /**
+   * Provide initial values for options.
+   */
+  function options_init() {
+    return array(
+      'distance' => '20',
+      'threshold' => null,
+    );
+  }
+
+  function options_form($defaults) {
+
+    // Only prompt for vector layers
+    $vector_layers = array();
+    foreach ($this->map['layers'] as $id => $name) {
+      // we could do better than this if $this->map['layers'] contained
+      // more than just a name...
+      $layer = openlayers_layer_load($id);
+      // we could do better than this, but layers must advertise their 'vector' nature
+      // in some way
+      if ( $layer->data['layer_type'] != 'openlayers_views_vector' ) continue;
+      $vector_layers[$id] = $name;
+    }
+
+    return array(
+      'clusterlayer' => array(
+        '#type' => 'select',
+        '#options' => $vector_layers,
+        '#description' => t('Select layer to cluster'),
+        '#default_value' => isset($defaults['clusterlayer']) ? $defaults['clusterlayer'] : NULL
+      ),
+      'distance' => array(
+        '#type' => 'textfield',
+        '#default_value' => (isset($defaults['distance'])) ?
+          $defaults['distance'] : 20, 
+        '#size' => 5,
+        '#title' => t('Distance'),
+	'#description' => t('Pixel distance between features that should be considered a single cluster')
+      ),
+      'threshold' => array(
+        '#type' => 'textfield',
+        '#default_value' => (isset($defaults['threshold'])) ?
+          $defaults['threshold'] : null,
+        '#size' => 5,
+        '#title' => t('Threshold'),
+	'#description' => t('Optional threshold below which original features will be added to the layer instead of clusters') 
+      )
+    );
+  }
+
+  /**
+   * Render.
+   */
+  function render(&$map) {
+    drupal_add_js(drupal_get_path('module', 'openlayers') .'/includes/behaviors/js/openlayers_behavior_cluster.js');
+    return $this->options;
+  }
+}
diff --git a/sites/all/modules/openlayers/includes/openlayers.behaviors.inc b/sites/all/modules/openlayers/includes/openlayers.behaviors.inc
index c88179b..f7635de 100644
--- a/sites/all/modules/openlayers/includes/openlayers.behaviors.inc
+++ b/sites/all/modules/openlayers/includes/openlayers.behaviors.inc
@@ -222,5 +222,16 @@ function _openlayers_openlayers_behaviors() {
          'parent' => 'openlayers_behavior',
        ),
     ),
+    'openlayers_behavior_cluster' => array(
+       'title' => t('Cluster'),
+       'description' => t('Provides vector layer features clustering by proximity'),
+       'type' => 'layer',
+       'path' => drupal_get_path('module', 'openlayers') .'/includes/behaviors',
+       'file' => 'openlayers_behavior_cluster.inc',
+       'behavior' => array(
+         'class' => 'openlayers_behavior_cluster',
+         'parent' => 'openlayers_behavior',
+       ),
+    ),
   );
 }
diff --git a/sites/all/modules/openlayers/js/CVS/Entries b/sites/all/modules/openlayers/js/CVS/Entries
index 4a5b2bf..de98830 100644
--- a/sites/all/modules/openlayers/js/CVS/Entries
+++ b/sites/all/modules/openlayers/js/CVS/Entries
@@ -1,2 +1,2 @@
-/openlayers.js/1.47.2.31/Tue May 18 09:11:47 2010//TDRUPAL-6--2
+/openlayers.js/1.47.2.31/Thu May 20 12:39:23 2010//TDRUPAL-6--2
 D
diff --git a/sites/all/modules/openlayers/js/openlayers.js b/sites/all/modules/openlayers/js/openlayers.js
index 8007f3e..39abb51 100644
--- a/sites/all/modules/openlayers/js/openlayers.js
+++ b/sites/all/modules/openlayers/js/openlayers.js
@@ -245,8 +245,19 @@ Drupal.openlayers = {
 
           // Add attribute data
           if (feature.attributes){
+            // Attributes belong to features, not single component geometries
+            // of them. But we're creating a geometry for each component for
+            // better performance and clustering support. Let's call these
+            // "pseudofeatures".
+            //
+            // In order to identify the real feature each geometry belongs to
+            // we then add a 'fid' parameter to the "pseudofeature".
+            // NOTE: 'drupalFID' is only unique within a single layer.
+            //
             newFeature.attributes = feature.attributes;
-            newFeature.data = feature.attributes;
+            newFeature.data = feature.attributes; // what is this needed for ?
+            newFeature.drupalFID = key; 
+            //newFeature.layer = layer; 
           }
 
           // Add style information
