[fusion-commits] r2234 - in branches/fusion-2.2: . layers layers/Generic layers/MapGuide layers/MapGuide/php layers/MapServer lib lib/OpenLayers templates/mapserver/standard text widgets widgets/BufferPanel widgets/QuickPlot widgets/Search widgets/SelectWithin widgets/widgetinfo

svn_fusion at osgeo.org svn_fusion at osgeo.org
Fri Sep 24 14:32:16 EDT 2010


Author: madair
Date: 2010-09-24 18:32:16 +0000 (Fri, 24 Sep 2010)
New Revision: 2234

Added:
   branches/fusion-2.2/lib/MapMessage.js
   branches/fusion-2.2/lib/proj4js-combined.js
   branches/fusion-2.2/widgets/QuickPlot.js
   branches/fusion-2.2/widgets/QuickPlot/
   branches/fusion-2.2/widgets/QuickPlot/GeneratePicture.php
   branches/fusion-2.2/widgets/QuickPlot/MapCapturer.js
   branches/fusion-2.2/widgets/QuickPlot/PreviewDialog.js
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.js
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.php
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.templ
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreview.js
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.php
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.templ
   branches/fusion-2.2/widgets/QuickPlot/north_arrow.png
   branches/fusion-2.2/widgets/QuickPlot/pixel.gif
   branches/fusion-2.2/widgets/QuickPlot/progress_indicator.gif
   branches/fusion-2.2/widgets/QuickPlot/rotate.cur
   branches/fusion-2.2/widgets/widgetinfo/quickplot.xml
Removed:
   branches/fusion-2.2/widgets/QuickPlot/GeneratePicture.php
   branches/fusion-2.2/widgets/QuickPlot/MapCapturer.js
   branches/fusion-2.2/widgets/QuickPlot/PreviewDialog.js
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.js
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.php
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.templ
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreview.js
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.php
   branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.templ
   branches/fusion-2.2/widgets/QuickPlot/north_arrow.png
   branches/fusion-2.2/widgets/QuickPlot/pixel.gif
   branches/fusion-2.2/widgets/QuickPlot/progress_indicator.gif
   branches/fusion-2.2/widgets/QuickPlot/rotate.cur
Modified:
   branches/fusion-2.2/
   branches/fusion-2.2/build.xml
   branches/fusion-2.2/config_dist.json
   branches/fusion-2.2/fusion.cfg
   branches/fusion-2.2/layers/Generic/Generic.js
   branches/fusion-2.2/layers/Layers.js
   branches/fusion-2.2/layers/MapGuide/
   branches/fusion-2.2/layers/MapGuide/MapGuide.js
   branches/fusion-2.2/layers/MapGuide/php/Common.php
   branches/fusion-2.2/layers/MapGuide/php/Utilities.php
   branches/fusion-2.2/layers/MapServer/
   branches/fusion-2.2/layers/MapServer/MapServer.js
   branches/fusion-2.2/lib/ApplicationDefinition.js
   branches/fusion-2.2/lib/Map.js
   branches/fusion-2.2/lib/OpenLayers/OpenLayers.js
   branches/fusion-2.2/lib/fusion.js
   branches/fusion-2.2/lib/proj4js-compressed.js
   branches/fusion-2.2/templates/mapserver/standard/ApplicationDefinition.xml
   branches/fusion-2.2/text/en
   branches/fusion-2.2/text/en.json
   branches/fusion-2.2/text/fr
   branches/fusion-2.2/text/fr.json
   branches/fusion-2.2/widgets/BasemapSwitcher.js
   branches/fusion-2.2/widgets/BufferPanel/Buffer.php
   branches/fusion-2.2/widgets/BufferPanel/BufferPanel.templ
   branches/fusion-2.2/widgets/BufferPanel/BufferReport.templ
   branches/fusion-2.2/widgets/BufferPanel/ErrorPage.templ
   branches/fusion-2.2/widgets/Measure.js
   branches/fusion-2.2/widgets/Search/ErrorPage.templ
   branches/fusion-2.2/widgets/Search/Search.templ
   branches/fusion-2.2/widgets/Search/SearchPrompt.templ
   branches/fusion-2.2/widgets/SelectWithin/SelectWithinPanel.templ
Log:
merge of revisions 2191-2233 from trunk to the 2.2 branch to bring it back in sync with trunk


Property changes on: branches/fusion-2.2
___________________________________________________________________
Added: svn:mergeinfo
   + /trunk:2192-2233

Modified: branches/fusion-2.2/build.xml
===================================================================
--- branches/fusion-2.2/build.xml	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/build.xml	2010-09-24 18:32:16 UTC (rev 2234)
@@ -221,7 +221,8 @@
                           MGBroker.js
                           Widget.js
                           Search.js
-                          Map.js"
+                          Map.js
+                          MapMessage.js"
         />
         <filelist dir="${build.home}/layers" files="Layers.js"/>
         <fileset dir="${build.home}/text" includes="**/*.json"/>


Property changes on: branches/fusion-2.2/config_dist.json
___________________________________________________________________
Deleted: svn:mergeinfo
   - 

Modified: branches/fusion-2.2/fusion.cfg
===================================================================
--- branches/fusion-2.2/fusion.cfg	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/fusion.cfg	2010-09-24 18:32:16 UTC (rev 2234)
@@ -32,6 +32,7 @@
 OpenLayers/Layer/Yahoo.js
 OpenLayers/Layer/Vector.js
 OpenLayers/Layer/Markers.js
+OpenLayers/Layer/XYZ.js
 OpenLayers/Tile.js
 OpenLayers/Tile/Image.js
 OpenLayers/Control/OverviewMap.js

Modified: branches/fusion-2.2/layers/Generic/Generic.js
===================================================================
--- branches/fusion-2.2/layers/Generic/Generic.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/layers/Generic/Generic.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -155,6 +155,14 @@
                 break;
             }
             break;
+         case 'OpenStreetMap':
+            if (this.mapTag.layerOptions.type) {
+                this.mapTag.layerOptions.type = this.mapTag.layerOptions.type;
+            }
+            else {
+                this.mapTag.layerOptions.type = 'Mapnik';
+            }
+            break;
           default:
             this.oLayerOL = new OpenLayers.Layer[this.layerType](
                                   this.getMapName(), 
@@ -185,7 +193,12 @@
             if (typeof this.mapTag.layerOptions.numZoomLevels == 'undefined') {
                 this.mapTag.layerOptions.numZoomLevels = 20;
             }
-            this.oLayerOL = new OpenLayers.Layer[this.layerType](this.getMapName(), this.mapTag.layerOptions );
+            if(this.layerType == 'OpenStreetMap') {
+                this.oLayerOL = new OpenLayers.Layer.OSM[this.mapTag.layerOptions.type](this.getMapName(), this.mapTag.layerOptions );
+            }
+            else {
+                this.oLayerOL = new OpenLayers.Layer[this.layerType](this.getMapName(), this.mapTag.layerOptions );
+            }
             this.mapWidget.fractionalZoom = false;        //fractionalZoom not permitted with Google layers
             this.mapWidget.oMapOL.setOptions({fractionalZoom: false});
         }
@@ -258,6 +271,13 @@
     
     getSessionID: function() {
         return '';
-    }
+    },
+    
+    getLinkParams: function() {
+      var queryParams = {};
+      queryParams.layerType = this.layerType; //need this? and one for this.mapTag.layerOptions.type?
 
+      return queryParams;
+    }    
+
 });

Modified: branches/fusion-2.2/layers/Layers.js
===================================================================
--- branches/fusion-2.2/layers/Layers.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/layers/Layers.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -327,9 +327,9 @@
             return;
         }
         this.oMap.showGroup(this, noDraw ? true : false);
-        this.visible = true;
-        if (this.legend && this.legend.checkBox) {
-            this.legend.checkBox.checked = true;
+        this.set('visible', true);
+        if (this.legend && this.legend.treeItem && this.legend.treeItem.checkBox) {
+            this.legend.treeItem.checkBox.checked = true;
         }
     },
 
@@ -338,9 +338,9 @@
             return;
         }
         this.oMap.hideGroup(this, noDraw ? true : false);
-        this.visible = false;
-        if (this.legend && this.legend.checkBox) {
-            this.legend.checkBox.checked = false;
+        this.set('visible', false);
+        if (this.legend && this.legend.treeItem && this.legend.treeItem.checkBox) {
+            this.legend.treeItem.checkBox.checked = false;
         }
     },
 
@@ -504,8 +504,8 @@
         }
         this.set('visible', true);
         this.oMap.showLayer(this, noDraw ? true : false);
-        if (this.legend && this.legend.checkBox) {
-            this.legend.checkBox.checked = true;
+        if (this.legend && this.legend.treeItem && this.legend.treeItem.checkBox) { 
+            this.legend.treeItem.checkBox.checked = true;
         }
     },
 
@@ -515,8 +515,8 @@
         }
         this.set('visible',false);
         this.oMap.hideLayer(this, noDraw ? true : false);
-        if (this.legend && this.legend.checkBox) {
-            this.legend.checkBox.checked = false;
+        if (this.legend && this.legend.treeItem && this.legend.treeItem.checkBox) { 
+            this.legend.treeItem.checkBox.checked = false;
         }
     },
 


Property changes on: branches/fusion-2.2/layers/MapGuide
___________________________________________________________________
Deleted: svn:mergeinfo
   - 

Modified: branches/fusion-2.2/layers/MapGuide/MapGuide.js
===================================================================
--- branches/fusion-2.2/layers/MapGuide/MapGuide.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/layers/MapGuide/MapGuide.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -165,7 +165,7 @@
         }
           this.loadMap(this.sMapResourceId, options);
         }
-        window.setInterval(OpenLayers.Function.bind(this.pingServer, this), this.keepAliveInterval * 1000);
+        this.keepAliveTimer = window.setInterval(OpenLayers.Function.bind(this.pingServer, this), this.keepAliveInterval * 1000);
     },
 
     sessionReady: function() {
@@ -301,18 +301,15 @@
             }
 
             //set projection units and code if supplied
+            var wktProj;
             if (o.epsg != 0) {
               this.mapTag.layerOptions.projection = "EPSG:" + o.epsg;
             } else {
-              if (o.wkt.length > 0) {
-                  var wkt = o.wkt;
-                  var wktContentRE = /(\w+)\[(.*)\]/;
-                  var wktContent = wkt.match(wktContentRE);
-                  var wktName = wktContent[2].split(",")[0];
-                  wktName = wktName.toUpperCase();
-                  this.mapTag.layerOptions.projection = wktName;
-                  Proj4js.defs[wktName] = "+proj=identity +"+wkt;
-              }  
+              //default to the local non-projected system if not otherwise specified
+              if (!o.wkt || o.wkt.length == 0){
+                o.wkt = "LOCAL_CS[\"Non-Earth (Meter)\",LOCAL_DATUM[\"Local Datum\",0],UNIT[\"Meter\", 1],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH]]";
+              }
+              wktProj = new OpenLayers.Projection(o.wkt);
             }
             //TODO: consider passing the metersPerUnit value into the framework
             //to allow for scaling that doesn't match any of the pre-canned units
@@ -334,6 +331,9 @@
             }
 
             this.oLayerOL = this.createOLLayer(this._sMapname, this.bSingleTile,2,false);
+            if (wktProj) {
+              this.oLayerOL.projection = wktProj;
+            }
             this.oLayerOL.events.register("loadstart", this, this.loadStart);
             this.oLayerOL.events.register("loadend", this, this.loadEnd);
             this.oLayerOL.events.register("loadcancel", this, this.loadEnd);
@@ -1127,10 +1127,21 @@
 
     pingServer: function() {
         var s = 'layers/' + this.arch + '/' + Fusion.getScriptLanguage() + "/Common." + Fusion.getScriptLanguage() ;
-        var params = {};
+        var params = {onSuccess: OpenLayers.Function.bind(this.checkPingResponse, this)};
         params.parameters = {'session': this.getSessionID()};
         Fusion.ajaxRequest(s, params);
     },
+    
+    checkPingResponse: function(xhr) {
+      if (xhr.responseText) {
+        var o;
+        eval("o="+xhr.responseText);
+        if (!o.success) {
+          Fusion.reportError(o.message);
+          clearInterval(this.keepAliveTimer);
+        }
+      }
+    },
 
     getLinkParams: function() {
       var queryParams = {};

Modified: branches/fusion-2.2/layers/MapGuide/php/Common.php
===================================================================
--- branches/fusion-2.2/layers/MapGuide/php/Common.php	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/layers/MapGuide/php/Common.php	2010-09-24 18:32:16 UTC (rev 2234)
@@ -138,6 +138,8 @@
     $initializationErrorDetail = $e->GetDetails();
     $initializationErrorStackTrace = $e->GetStackTrace();
     $initializationErrorOccurred = true;
+    echo "{success: false, message:'".$initializationErrorMessage."'}";
+    //DisplayInitializationErrorHTML();
 }
 
 function InitializationErrorOccurred()

Modified: branches/fusion-2.2/layers/MapGuide/php/Utilities.php
===================================================================
--- branches/fusion-2.2/layers/MapGuide/php/Utilities.php	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/layers/MapGuide/php/Utilities.php	2010-09-24 18:32:16 UTC (rev 2234)
@@ -773,7 +773,7 @@
     array_push($properties->$layerName->metadatanames, 'length');
 
     $mappings = $_SESSION['property_mappings'][$layerObj->GetObjectId()];
-    foreach($mappings as $name => $value)
+    foreach((array)$mappings as $name => $value)
     {
         $propType = $featureReader->GetPropertyType($name);
         array_push($properties->$layerName->propertynames, $name);


Property changes on: branches/fusion-2.2/layers/MapServer
___________________________________________________________________
Deleted: svn:mergeinfo
   - 

Modified: branches/fusion-2.2/layers/MapServer/MapServer.js
===================================================================
--- branches/fusion-2.2/layers/MapServer/MapServer.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/layers/MapServer/MapServer.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -174,12 +174,28 @@
 
     mapSessionCreated: function() {
         // restore the mapfile from a saved state.
-        if(this.bRestoreMapState === true && this.oRestoredState.loadmap ){
+        if (this.bRestoreMapState === true && this.oRestoredState.loadmap ) {
             this.loadMap(this.oRestoredState.loadmap);
+        } else if (this.sMapFile != '') {
+          var options = {};
+          if (this.bIsMapWidgetLayer) {
+            var showlayers = Fusion.getQueryParam('showlayers');
+            Fusion.queryParams['showlayers'] = null;
+            var hidelayers = Fusion.getQueryParam('hidelayers');
+            Fusion.queryParams['hidelayers'] = null;
+            var showgroups = Fusion.getQueryParam('showgroups');
+            Fusion.queryParams['showgroups'] = null;
+            var hidegroups = Fusion.getQueryParam('hidegroups');
+            Fusion.queryParams['hidegroups'] = null;
+            var options = {
+              showlayers: showlayers == '' ? [] : showlayers.split(','),
+              hidelayers: hidelayers == '' ? [] : hidelayers.split(','),
+              showgroups: showgroups == '' ? [] : showgroups.split(','),
+              hidegroups: hidegroups == '' ? [] : hidegroups.split(',')
+            };
+          }
+          this.loadMap(this.sMapFile, options);
         }
-        else if (this.sMapFile != '') {
-            this.loadMap(this.sMapFile);
-        }
         window.setInterval(OpenLayers.Function.bind(this.pingServer, this), 
                                                 this.keepAliveInterval * 1000);
     },
@@ -215,8 +231,11 @@
 
         options = options || {};
 
-        this.aVisibleLayers = options.showlayers || [];
-        this.aVisibleGroups = options.showgroups || [];
+        this.aShowLayers = options.showlayers || [];
+        this.aHideLayers = options.hidelayers || [];
+        this.aShowGroups = options.showgroups || [];
+        this.aHideGroups = options.showgroups || [];
+        this.aVisibleLayers = [];
         this.aLayers = [];
 
         this.oSelection = null;
@@ -273,8 +292,27 @@
             var minScale = 1.0e10;
             var maxScale = 0;
             for (var i=0; i<this.aLayers.length; i++) {
+              var testLayer = this.aLayers[i].layerName;
               if (this.aLayers[i].visible) {
-                  this.aVisibleLayers.push(this.aLayers[i].layerName);
+                var layerName = testLayer;
+                for (var j=0; j<this.aHideLayers.length; ++j) {
+                  if (layerName == this.aHideLayers[j]) {
+                    layerName = null;
+                    this.aLayers[i].hide(true);
+                    break;
+                  }
+                }
+                if (layerName) this.aVisibleLayers.push(layerName);
+              } else {
+                var layerName = null;
+                for (var j=0; j<this.aShowLayers.length; ++j) {
+                  if (testLayer == this.aShowLayers[j]) {
+                    layerName = testLayer;
+                    this.aLayers[i].show(true);
+                    break;
+                  }
+                }
+                if (layerName) this.aVisibleLayers.push(layerName);
               }
       				minScale = Math.min(minScale, this.aLayers[i].minScale);
       				maxScale = Math.max(maxScale, this.aLayers[i].maxScale);
@@ -529,19 +567,23 @@
         this.oLayerOL.mergeNewParams(params);
     },
 
-    showLayer: function( sLayer ) {
+    showLayer: function( sLayer, noDraw ) {
         this.aVisibleLayers.push(sLayer.layerName);
-        this.drawMap();
+        if (!noDraw) {
+          this.drawMap();
+        }
     },
 
-    hideLayer: function( sLayer ) {
+    hideLayer: function( sLayer, noDraw ) {
         for (var i=0; i<this.aLayers.length; i++) {
             if (this.aVisibleLayers[i] == sLayer.layerName) {
                 this.aVisibleLayers.splice(i,1);
                 break;
             }
         }
-        this.drawMap();
+        if (!noDraw) {
+          this.drawMap();
+        }
     },
 
     showGroup: function( group, noDraw ) {
@@ -859,6 +901,43 @@
         return url + '?'+params;
     },
 
+    getLinkParams: function() {
+      var queryParams = {};
+      queryParams.theme = this.sMapResourceId;
+
+      //determine which layers have been toggled
+      var showLayers = [];
+      var hideLayers = [];
+      for (var i=0; i<this.aLayers.length; ++i) {
+        var layer = this.aLayers[i];
+        if (layer.visible && !layer.initiallyVisible) {  //layer was turned on
+          showLayers.push(layer.layerName);
+        }
+        if (!layer.visible && layer.initiallyVisible) {  //layer was turned off
+          hideLayers.push(layer.layerName);
+        }
+      }
+      queryParams.showlayers = showLayers.join(',');
+      queryParams.hidelayers = hideLayers.join(',');
+
+      //determine which groups have been toggled
+      var showGroups = [];
+      var hideGroups = [];
+      for (var i=0; i<this.layerRoot.groups.length; ++i) {
+        var group = this.layerRoot.groups[i];
+        if (group.visible && !group.initiallyVisible) {  //layer was turned on
+          showGroups.push(group.groupName);
+        }
+        if (!group.visible && group.initiallyVisible) {  //layer was turned off
+          hideGroups.push(group.groupName);
+        }
+      }
+      queryParams.showgroups = showGroups.join(',');
+      queryParams.hidegroups = hideGroups.join(',');
+
+      return queryParams;
+    },
+    
     getMapTip: function(oMapTips){
         if(this.bMapTipFired == false){
             //console.log("MAPSERVER:getMapTip");

Modified: branches/fusion-2.2/lib/ApplicationDefinition.js
===================================================================
--- branches/fusion-2.2/lib/ApplicationDefinition.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/lib/ApplicationDefinition.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -677,6 +677,14 @@
         this.mapWidget.setMenu();
         $(this.mapWidgetTag.name).widget = this.mapWidget;
 
+        //create the floating map message
+        this.mapWidget.message = new Fusion.MapMessage(this.mapWidget.oMapOL.viewPortDiv);
+        this.mapWidget.registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, (function(){
+                if (this.message != null){
+                    this.message.refreshLayout();
+                }
+            }).bind(this.mapWidget));
+
         //create all the other widgets for the widget set
         for (var i=0; i<this.widgetTags.length; i++) {
             this.widgetTags[i].create(this);

Modified: branches/fusion-2.2/lib/Map.js
===================================================================
--- branches/fusion-2.2/lib/Map.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/lib/Map.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -533,10 +533,10 @@
         }
         this.oMapOL.addLayer(map.oLayerOL);
         if (map.oLayerOL.isBaseLayer) {
-          this.projection = map.projection;
-          this.units = map.units;
+          this.projection = this.oMapOL.baseLayer.projection;
+          this.units = this.oMapOL.baseLayer.units;
           this.oMapOL.setOptions({
-                  units: map.units,
+                  units: this.units,
                   projection: this.projection
           });
         }

Copied: branches/fusion-2.2/lib/MapMessage.js (from rev 2233, trunk/lib/MapMessage.js)
===================================================================
--- branches/fusion-2.2/lib/MapMessage.js	                        (rev 0)
+++ branches/fusion-2.2/lib/MapMessage.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,112 @@
+/*****************************************************************************
+ * Class: Fusion.MapMessage
+ *
+ * It is to show a floating message bar over the main map viewer
+ */
+Fusion.MapMessage = OpenLayers.Class({
+	parentNode : null,
+	domObj : null,
+	leadingIcon : null,
+	textCell : null,
+	message : "",
+	
+	infoIconName : "images/icons/info.png",
+	warningIconName : "images/icons/warning.png",
+	errorIconName : "images/icons/error.png",
+	
+	containerCssText : "position:absolute; z-index:10000; padding:10px; border:solid 2px #ECECEC; background:#FFFFBB",
+	iconCssText : "margin-right:10px",
+	textCellCssText : "width:100%; vertical-align:top; font: 8pt Tahoma",
+
+	opacity: 0.95,
+	
+	initialize : function(parentNode)
+	{
+		this.parentNode = $(parentNode);
+		// Create the div container
+		var container   = document.createElement("div");
+		container.style.visibility = "hidden";
+		this.container  = $(container);
+		parentNode.appendChild(container);
+
+		container.style.cssText = this.containerCssText;
+		var offset = {left:10, top:10};
+		container.style.left = offset.left + "px";
+		container.style.top  = offset.top  + "px";
+		
+		// Create the inner table
+		var table = document.createElement("table");
+		container.appendChild(table);
+		table.style.width = "100%";
+		table.cellSpacing = "0";
+		table.cellPadding = "0";
+		table.border      = "0";
+		// Create the table row
+		var row   = table.insertRow(0);
+		// The icon cell
+		var cell  = row.insertCell(0);
+		// Add the info icon by default
+		var icon  = document.createElement("img");
+		icon.src  = this.infoIconName;
+		cell.appendChild(icon);
+		icon.style.cssText = this.iconCssText;
+		this.leadingIcon   = icon;
+		// Create the text cell
+		cell      = row.insertCell(1);
+		cell.style.cssText = this.textCellCssText;
+		this.textCell = $(cell);
+		this.textCell.innerHTML = this.message;
+		
+		this.refreshLayout();
+		// Hide message bar by default
+		this.container.setOpacity(0);
+		this.container.style.visibility = "visible";
+	},
+	
+	info : function(message)
+	{
+		this.message = message;
+		this.leadingIcon.src = this.infoIconName;
+		this.show();
+	},
+	
+	warn : function(message)
+	{
+		this.message = message;
+		this.leadingIcon.src = this.warningIconName;
+		this.show();
+	},
+	
+	error : function(message)
+	{
+		this.message = message;
+		this.leadingIcon.src = this.errorIconName;
+		this.show();
+	},
+	
+	clear : function()
+	{
+		this.message = "";
+		this.textCell.innerHTML = "";
+		this.hide();
+	},
+	
+	show : function()
+	{
+		this.textCell.innerHTML = this.message;
+		this.container.fade(this.opacity);
+	},
+	
+	hide : function()
+	{
+		this.container.fade(0);
+	},
+	
+	refreshLayout: function()
+	{
+		// 44 = 2 * padding (10) + 2 * offset(10) + 2 * border (2)
+		this.container.style.width  = this.parentNode.offsetWidth - 44 + "px";
+	},
+	
+	CLASS_NAME: "Fusion.MapMessage"
+});
\ No newline at end of file

Modified: branches/fusion-2.2/lib/OpenLayers/OpenLayers.js
===================================================================
--- branches/fusion-2.2/lib/OpenLayers/OpenLayers.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/lib/OpenLayers/OpenLayers.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1,101 +1,102 @@
-/*
-
-  OpenLayers.js -- OpenLayers Map Viewer Library
-
-  Copyright 2005-2008 MetaCarta, Inc., released under the Clear BSD license.
-  Please see http://svn.openlayers.org/trunk/openlayers/license.txt
-  for the full text of the license.
-
-  Includes compressed code under the following licenses:
-
-  (For uncompressed versions of the code used please see the
-  OpenLayers SVN repository: <http://openlayers.org/>)
-
-*/
-
-/* Contains portions of Prototype.js:
- *
- * Prototype JavaScript framework, version 1.4.0
- *  (c) 2005 Sam Stephenson <sam at conio.net>
- *
- *  Prototype is freely distributable under the terms of an MIT-style license.
- *  For details, see the Prototype web site: http://prototype.conio.net/
- *
- *--------------------------------------------------------------------------*/
-
-/**
-*
-*  Contains portions of Rico <http://openrico.org/>
-*
-*  Copyright 2005 Sabre Airline Solutions
-*
-*  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.
-*
-**/
-
-/**
- * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
- * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
- *
- * 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
- */
-
-/**
- * Contains portions of Gears <http://code.google.com/apis/gears/>
- *
- * Copyright 2007, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *  1. Redistributions of source code must retain the above copyright notice,
- *     this list of conditions and the following disclaimer.
- *  2. Redistributions in binary form must reproduce the above copyright notice,
- *     this list of conditions and the following disclaimer in the documentation
- *     and/or other materials provided with the distribution.
- *  3. Neither the name of Google Inc. nor the names of its contributors may be
- *     used to endorse or promote products derived from this software without
- *     specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Sets up google.gears.*, which is *the only* supported way to access Gears.
- *
- * Circumvent this file at your own risk!
- *
- * In the future, Gears may automatically define google.gears.* without this
- * file. Gears may use these objects to transparently fix bugs and compatibility
- * issues. Applications that use the code below will continue to work seamlessly
- * when that happens.
- */
+/*
+
+  OpenLayers.js -- OpenLayers Map Viewer Library
+
+  Copyright 2005-2010 OpenLayers Contributors, released under the Clear BSD
+  license. Please see http://svn.openlayers.org/trunk/openlayers/license.txt
+  for the full text of the license.
+
+  Includes compressed code under the following licenses:
+
+  (For uncompressed versions of the code used please see the
+  OpenLayers SVN repository: <http://openlayers.org/>)
+
+*/
+
+/* Contains portions of Prototype.js:
+ *
+ * Prototype JavaScript framework, version 1.4.0
+ *  (c) 2005 Sam Stephenson <sam at conio.net>
+ *
+ *  Prototype is freely distributable under the terms of an MIT-style license.
+ *  For details, see the Prototype web site: http://prototype.conio.net/
+ *
+ *--------------------------------------------------------------------------*/
+
+/**  
+*  
+*  Contains portions of Rico <http://openrico.org/>
+* 
+*  Copyright 2005 Sabre Airline Solutions  
+*  
+*  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. 
+*
+**/
+
+/**
+ * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
+ * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
+ *
+ * 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
+ */
+
+/**
+ * Contains portions of Gears <http://code.google.com/apis/gears/>
+ *
+ * Copyright 2007, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. Neither the name of Google Inc. nor the names of its contributors may be
+ *     used to endorse or promote products derived from this software without
+ *     specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Sets up google.gears.*, which is *the only* supported way to access Gears.
+ *
+ * Circumvent this file at your own risk!
+ *
+ * In the future, Gears may automatically define google.gears.* without this
+ * file. Gears may use these objects to transparently fix bugs and compatibility
+ * issues. Applications that use the code below will continue to work seamlessly
+ * when that happens.
+ */
 /* ======================================================================
     OpenLayers/SingleFile.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 var OpenLayers = {
@@ -107,15 +108,16 @@
     OpenLayers.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
-/*
+/* 
  * @requires OpenLayers/BaseTypes.js
  * @requires OpenLayers/Lang/en.js
  * @requires OpenLayers/Console.js
- */
+ */ 
 
 (function() {
     /**
@@ -125,13 +127,19 @@
      * case with single file builds.
      */
     var singleFile = (typeof OpenLayers == "object" && OpenLayers.singleFile);
-
+    
     /**
+     * Cache for the script location returned from
+     * OpenLayers._getScriptLocation
+     */
+    var scriptLocation;
+    
+    /**
      * Namespace: OpenLayers
      * The OpenLayers object provides a namespace for all things OpenLayers
      */
     window.OpenLayers = {
-
+        
         /**
          * Property: _scriptName
          * {String} Relative path of this script.
@@ -146,9 +154,12 @@
          * {String} Path to this script
          */
         _getScriptLocation: function () {
-            var scriptLocation = "";
+            if (scriptLocation != undefined) {
+                return scriptLocation;
+            }
+            scriptLocation = "";            
             var isOL = new RegExp("(^|(.*?\\/))(" + OpenLayers._scriptName + ")(\\?|$)");
-
+         
             var scripts = document.getElementsByTagName('script');
             for (var i=0, len=scripts.length; i<len; i++) {
                 var src = scripts[i].getAttribute('src');
@@ -166,11 +177,11 @@
     /**
      * OpenLayers.singleFile is a flag indicating this file is being included
      * in a Single File Library build of the OpenLayers Library.
-     *
+     * 
      * When we are *not* part of a SFL build we dynamically include the
      * OpenLayers library code.
-     *
-     * When we *are* part of a SFL build we do not dynamically include the
+     * 
+     * When we *are* part of a SFL build we do not dynamically include the 
      * OpenLayers library code as it will be appended at the end of this file.
       */
     if(!singleFile) {
@@ -200,12 +211,14 @@
             "OpenLayers/Popup.js",
             "OpenLayers/Tile.js",
             "OpenLayers/Tile/Image.js",
+            "OpenLayers/Tile/Image/IFrame.js",
             "OpenLayers/Tile/WFS.js",
             "OpenLayers/Layer/Image.js",
             "OpenLayers/Layer/SphericalMercator.js",
             "OpenLayers/Layer/EventPane.js",
             "OpenLayers/Layer/FixedZoomLevels.js",
             "OpenLayers/Layer/Google.js",
+            "OpenLayers/Layer/Google/v3.js",
             "OpenLayers/Layer/VirtualEarth.js",
             "OpenLayers/Layer/Yahoo.js",
             "OpenLayers/Layer/HTTPRequest.js",
@@ -222,12 +235,15 @@
             "OpenLayers/Layer/ArcGIS93Rest.js",
             "OpenLayers/Layer/WMS.js",
             "OpenLayers/Layer/WMS/Untiled.js",
+            "OpenLayers/Layer/WMS/Post.js",
+            "OpenLayers/Layer/WMTS.js",
             "OpenLayers/Layer/ArcIMS.js",
             "OpenLayers/Layer/GeoRSS.js",
             "OpenLayers/Layer/Boxes.js",
             "OpenLayers/Layer/XYZ.js",
             "OpenLayers/Layer/TMS.js",
             "OpenLayers/Layer/TileCache.js",
+            "OpenLayers/Layer/Zoomify.js",
             "OpenLayers/Popup/Anchored.js",
             "OpenLayers/Popup/AnchoredBubble.js",
             "OpenLayers/Popup/Framed.js",
@@ -275,6 +291,10 @@
             "OpenLayers/Control/NavigationHistory.js",
             "OpenLayers/Control/Measure.js",
             "OpenLayers/Control/WMSGetFeatureInfo.js",
+            "OpenLayers/Control/WMTSGetFeatureInfo.js",
+            "OpenLayers/Control/Graticule.js",
+            "OpenLayers/Control/TransformFeature.js",
+            "OpenLayers/Control/SLDSelect.js",
             "OpenLayers/Geometry.js",
             "OpenLayers/Geometry/Rectangle.js",
             "OpenLayers/Geometry/Collection.js",
@@ -282,7 +302,7 @@
             "OpenLayers/Geometry/MultiPoint.js",
             "OpenLayers/Geometry/Curve.js",
             "OpenLayers/Geometry/LineString.js",
-            "OpenLayers/Geometry/LinearRing.js",
+            "OpenLayers/Geometry/LinearRing.js",        
             "OpenLayers/Geometry/Polygon.js",
             "OpenLayers/Geometry/MultiLineString.js",
             "OpenLayers/Geometry/MultiPolygon.js",
@@ -295,11 +315,18 @@
             "OpenLayers/Layer/Vector.js",
             "OpenLayers/Layer/Vector/RootContainer.js",
             "OpenLayers/Strategy.js",
+            "OpenLayers/Strategy/Filter.js",
             "OpenLayers/Strategy/Fixed.js",
             "OpenLayers/Strategy/Cluster.js",
             "OpenLayers/Strategy/Paging.js",
             "OpenLayers/Strategy/BBOX.js",
             "OpenLayers/Strategy/Save.js",
+            "OpenLayers/Strategy/Refresh.js",
+            "OpenLayers/Filter.js",
+            "OpenLayers/Filter/FeatureId.js",
+            "OpenLayers/Filter/Logical.js",
+            "OpenLayers/Filter/Comparison.js",
+            "OpenLayers/Filter/Spatial.js",
             "OpenLayers/Protocol.js",
             "OpenLayers/Protocol/HTTP.js",
             "OpenLayers/Protocol/SQL.js",
@@ -308,24 +335,24 @@
             "OpenLayers/Protocol/WFS/v1.js",
             "OpenLayers/Protocol/WFS/v1_0_0.js",
             "OpenLayers/Protocol/WFS/v1_1_0.js",
+            "OpenLayers/Protocol/SOS.js",
+            "OpenLayers/Protocol/SOS/v1_0_0.js",
             "OpenLayers/Layer/PointTrack.js",
             "OpenLayers/Layer/GML.js",
             "OpenLayers/Style.js",
+            "OpenLayers/Style2.js",
             "OpenLayers/StyleMap.js",
             "OpenLayers/Rule.js",
-            "OpenLayers/Filter.js",
-            "OpenLayers/Filter/FeatureId.js",
-            "OpenLayers/Filter/Logical.js",
-            "OpenLayers/Filter/Comparison.js",
-            "OpenLayers/Filter/Spatial.js",
             "OpenLayers/Format.js",
             "OpenLayers/Format/XML.js",
+            "OpenLayers/Format/Context.js",
             "OpenLayers/Format/ArcXML.js",
             "OpenLayers/Format/ArcXML/Features.js",
             "OpenLayers/Format/GML.js",
             "OpenLayers/Format/GML/Base.js",
             "OpenLayers/Format/GML/v2.js",
             "OpenLayers/Format/GML/v3.js",
+            "OpenLayers/Format/Atom.js",
             "OpenLayers/Format/KML.js",
             "OpenLayers/Format/GeoRSS.js",
             "OpenLayers/Format/WFS.js",
@@ -346,7 +373,13 @@
             "OpenLayers/Format/SLD.js",
             "OpenLayers/Format/SLD/v1.js",
             "OpenLayers/Format/SLD/v1_0_0.js",
-            "OpenLayers/Format/SLD/v1.js",
+            "OpenLayers/Format/OWSCommon/v1.js",
+            "OpenLayers/Format/OWSCommon/v1_0_0.js",
+            "OpenLayers/Format/OWSCommon/v1_1_0.js",
+            "OpenLayers/Format/CSWGetDomain.js",
+            "OpenLayers/Format/CSWGetDomain/v2_0_2.js",
+            "OpenLayers/Format/CSWGetRecords.js",
+            "OpenLayers/Format/CSWGetRecords/v2_0_2.js",
             "OpenLayers/Format/WFST.js",
             "OpenLayers/Format/WFST/v1.js",
             "OpenLayers/Format/WFST/v1_0_0.js",
@@ -359,10 +392,21 @@
             "OpenLayers/Format/WMC/v1_0_0.js",
             "OpenLayers/Format/WMC/v1_1_0.js",
             "OpenLayers/Format/WMSCapabilities.js",
+            "OpenLayers/Format/WMSCapabilities/v1.js",
             "OpenLayers/Format/WMSCapabilities/v1_1.js",
             "OpenLayers/Format/WMSCapabilities/v1_1_0.js",
             "OpenLayers/Format/WMSCapabilities/v1_1_1.js",
+            "OpenLayers/Format/WMSCapabilities/v1_3.js",
+            "OpenLayers/Format/WMSCapabilities/v1_3_0.js",
             "OpenLayers/Format/WMSGetFeatureInfo.js",
+            "OpenLayers/Format/SOSCapabilities.js",
+            "OpenLayers/Format/SOSCapabilities/v1_0_0.js",
+            "OpenLayers/Format/SOSGetObservation.js",
+            "OpenLayers/Format/SOSGetFeatureOfInterest.js",
+            "OpenLayers/Format/OWSContext.js",
+            "OpenLayers/Format/OWSContext/v0_3_1.js",
+            "OpenLayers/Format/WMTSCapabilities.js",
+            "OpenLayers/Format/WMTSCapabilities/v1_0_0.js",
             "OpenLayers/Layer/WFS.js",
             "OpenLayers/Control/GetFeature.js",
             "OpenLayers/Control/MouseToolbar.js",
@@ -373,6 +417,12 @@
             "OpenLayers/Control/ZoomOut.js",
             "OpenLayers/Control/ZoomPanel.js",
             "OpenLayers/Control/EditingToolbar.js",
+            "OpenLayers/Symbolizer.js",
+            "OpenLayers/Symbolizer/Point.js",
+            "OpenLayers/Symbolizer/Line.js",
+            "OpenLayers/Symbolizer/Polygon.js",
+            "OpenLayers/Symbolizer/Text.js",
+            "OpenLayers/Symbolizer/Raster.js",
             "OpenLayers/Lang.js",
             "OpenLayers/Lang/en.js"
         ); // etc.
@@ -382,16 +432,16 @@
         if(docWrite) {
             var allScriptTags = new Array(jsfiles.length);
         }
-        var host = OpenLayers._getScriptLocation() + "lib/";
+        var host = OpenLayers._getScriptLocation() + "lib/";    
         for (var i=0, len=jsfiles.length; i<len; i++) {
             if (docWrite) {
                 allScriptTags[i] = "<script src='" + host + jsfiles[i] +
-                                   "'></script>";
+                                   "'></script>"; 
             } else {
                 var s = document.createElement("script");
                 s.src = host + jsfiles[i];
-                var h = document.getElementsByTagName("head").length ?
-                           document.getElementsByTagName("head")[0] :
+                var h = document.getElementsByTagName("head").length ? 
+                           document.getElementsByTagName("head")[0] : 
                            document.body;
                 h.appendChild(s);
             }
@@ -405,13 +455,14 @@
 /**
  * Constant: VERSION_NUMBER
  */
-OpenLayers.VERSION_NUMBER="OpenLayers 2.8 -- $Revision$";
+OpenLayers.VERSION_NUMBER="OpenLayers 2.10 -- $Revision$";
 /* ======================================================================
     OpenLayers/Util.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -423,7 +474,7 @@
  */
 OpenLayers.Util = {};
 
-/**
+/** 
  * Function: getElement
  * This is the old $() from prototype
  */
@@ -444,10 +495,24 @@
 };
 
 /**
+ * Function: isElement
+ * A cross-browser implementation of "e instanceof Element".
+ *
+ * Parameters:
+ * o - {Object} The object to test.
+ *
+ * Returns:
+ * {Boolean}
+ */
+OpenLayers.Util.isElement = function(o) {
+    return !!(o && o.nodeType === 1);
+};
+
+/** 
  * Maintain existing definition of $.
  */
 if(typeof window.$  === "undefined") {
-    window.$ = OpenLayers.Util.getElement;
+    //window.$ = OpenLayers.Util.getElement;
 }
 
 /**
@@ -497,7 +562,7 @@
 };
 
 
-/**
+/** 
  * Function: removeItem
  * Remove an object from an array. Iterates through the array
  *     to find the item, then removes it.
@@ -505,7 +570,7 @@
  * Parameters:
  * array - {Array}
  * item - {Object}
- *
+ * 
  * Return
  * {Array} A reference to the array
  */
@@ -523,7 +588,7 @@
  * Function: clearArray
  * *Deprecated*. This function will disappear in 3.0.
  * Please use "array.length = 0" instead.
- *
+ * 
  * Parameters:
  * array - {Array}
  */
@@ -536,48 +601,52 @@
     array.length = 0;
 };
 
-/**
+/** 
  * Function: indexOf
  * Seems to exist already in FF, but not in MOZ.
- *
+ * 
  * Parameters:
  * array - {Array}
  * obj - {Object}
- *
+ * 
  * Returns:
- * {Integer} The index at, which the object was found in the array.
+ * {Integer} The index at, which the first object was found in the array.
  *           If not found, returns -1.
  */
 OpenLayers.Util.indexOf = function(array, obj) {
-
-    for(var i=0, len=array.length; i<len; i++) {
-        if (array[i] == obj) {
-            return i;
+    // use the build-in function if available.
+    if (typeof array.indexOf == "function") {
+        return array.indexOf(obj);
+    } else {
+        for (var i = 0, len = array.length; i < len; i++) {
+            if (array[i] == obj) {
+                return i;
+            }
         }
+        return -1;   
     }
-    return -1;
 };
 
 
 
 /**
  * Function: modifyDOMElement
- *
- * Modifies many properties of a DOM element all at once.  Passing in
+ * 
+ * Modifies many properties of a DOM element all at once.  Passing in 
  * null to an individual parameter will avoid setting the attribute.
  *
  * Parameters:
  * id - {String} The element id attribute to set.
  * px - {<OpenLayers.Pixel>} The left and top style position.
  * sz - {<OpenLayers.Size>}  The width and height style attributes.
- * position - {String}       The position attribute.  eg: absolute,
+ * position - {String}       The position attribute.  eg: absolute, 
  *                           relative, etc.
  * border - {String}         The style.border attribute.  eg:
  *                           solid black 2px
- * overflow - {String}       The style.overview attribute.
+ * overflow - {String}       The style.overview attribute.  
  * opacity - {Float}         Fractional value (0.0 - 1.0)
  */
-OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position,
+OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, 
                                             border, overflow, opacity) {
 
     if (id) {
@@ -609,32 +678,32 @@
     }
 };
 
-/**
+/** 
  * Function: createDiv
  * Creates a new div and optionally set some standard attributes.
  * Null may be passed to each parameter if you do not wish to
  * set a particular attribute.
  * Note - zIndex is NOT set on the resulting div.
- *
+ * 
  * Parameters:
  * id - {String} An identifier for this element.  If no id is
- *               passed an identifier will be created
+ *               passed an identifier will be created 
  *               automatically.
- * px - {<OpenLayers.Pixel>} The element left and top position.
+ * px - {<OpenLayers.Pixel>} The element left and top position. 
  * sz - {<OpenLayers.Size>} The element width and height.
- * imgURL - {String} A url pointing to an image to use as a
+ * imgURL - {String} A url pointing to an image to use as a 
  *                   background image.
  * position - {String} The style.position value. eg: absolute,
  *                     relative etc.
- * border - {String} The the style.border value.
+ * border - {String} The the style.border value. 
  *                   eg: 2px solid black
  * overflow - {String} The style.overflow value. Eg. hidden
  * opacity - {Float} Fractional value (0.0 - 1.0)
- *
- * Returns:
+ * 
+ * Returns: 
  * {DOMElement} A DOM Div created with the specified attributes.
  */
-OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position,
+OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, 
                                      border, overflow, opacity) {
 
     var dom = document.createElement('div');
@@ -650,7 +719,7 @@
     if (!position) {
         position = "absolute";
     }
-    OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position,
+    OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, 
                                      border, overflow, opacity);
 
     return dom;
@@ -659,7 +728,7 @@
 /**
  * Function: createImage
  * Creates an img element with specific attribute values.
- *
+ *  
  * Parameters:
  * id - {String} The id field for the img.  If none assigned one will be
  *               automatically generated.
@@ -671,7 +740,7 @@
  * opacity - {Float} Fractional value (0.0 - 1.0)
  * delayDisplay - {Boolean} If true waits until the image has been
  *                          loaded.
- *
+ * 
  * Returns:
  * {DOMElement} A DOM Image created with the specified attributes.
  */
@@ -687,18 +756,18 @@
     if (!position) {
         position = "relative";
     }
-    OpenLayers.Util.modifyDOMElement(image, id, px, sz, position,
+    OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, 
                                      border, null, opacity);
 
     if(delayDisplay) {
         image.style.display = "none";
-        OpenLayers.Event.observe(image, "load",
+        OpenLayers.Event.observe(image, "load", 
             OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
-        OpenLayers.Event.observe(image, "error",
+        OpenLayers.Event.observe(image, "error", 
             OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
-
+        
     }
-
+    
     //set special properties
     image.style.alt = id;
     image.galleryImg = "no";
@@ -707,17 +776,17 @@
     }
 
 
-
+        
     return image;
 };
 
 /**
  * Function: setOpacity
- * *Deprecated*.  This function has been deprecated. Instead, please use
- *     <OpenLayers.Util.modifyDOMElement>
- *     or
+ * *Deprecated*.  This function has been deprecated. Instead, please use 
+ *     <OpenLayers.Util.modifyDOMElement> 
+ *     or 
  *     <OpenLayers.Util.modifyAlphaImageDiv>
- *
+ * 
  * Set the opacity of a DOM Element
  *     Note that for this function to work in IE, elements must "have layout"
  *     according to:
@@ -739,34 +808,27 @@
  */
 OpenLayers.Util.onImageLoad = function() {
     // The complex check here is to solve issues described in #480.
-    // Every time a map view changes, it increments the 'viewRequestID'
+    // Every time a map view changes, it increments the 'viewRequestID' 
     // property. As the requests for the images for the new map view are sent
-    // out, they are tagged with this unique viewRequestID.
-    //
-    // If an image has no viewRequestID property set, we display it regardless,
-    // but if it does have a viewRequestID property, we check that it matches
+    // out, they are tagged with this unique viewRequestID. 
+    // 
+    // If an image has no viewRequestID property set, we display it regardless, 
+    // but if it does have a viewRequestID property, we check that it matches 
     // the viewRequestID set on the map.
-    //
+    // 
     // If the viewRequestID on the map has changed, that means that the user
     // has changed the map view since this specific request was sent out, and
     // therefore this tile does not need to be displayed (so we do not execute
     // this code that turns its display on).
     //
     if (!this.viewRequestID ||
-        (this.map && this.viewRequestID == this.map.viewRequestID)) {
-        this.style.backgroundColor ="transparent";
-        this.style.display = "";
+        (this.map && this.viewRequestID == this.map.viewRequestID)) { 
+        this.style.display = "";  
     }
+    OpenLayers.Element.removeClass(this, "olImageLoadError");
 };
 
 /**
- * Property: onImageLoadErrorColor
- * {String} The color tiles with load errors will turn.
- *          Default is "pink"
- */
-OpenLayers.Util.onImageLoadErrorColor = "pink";
-
-/**
  * Property: IMAGE_RELOAD_ATTEMPTS
  * {Integer} How many times should we try to reload an image before giving up?
  *           Default is 0
@@ -774,7 +836,7 @@
 OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
 
 /**
- * Function: onImageLoadError
+ * Function: onImageLoadError 
  */
 OpenLayers.Util.onImageLoadError = function() {
     this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
@@ -800,7 +862,7 @@
             this.src = this.src;
         }
     } else {
-        this.style.backgroundColor = OpenLayers.Util.onImageLoadErrorColor;
+        OpenLayers.Element.addClass(this, "olImageLoadError");
     }
     this.style.display = "";
 };
@@ -816,7 +878,7 @@
  * Checks whether it's necessary (and possible) to use the png alpha
  * hack which allows alpha transparency for png images under Internet
  * Explorer.
- *
+ * 
  * Returns:
  * {Boolean} true if the png alpha hack is necessary and possible, false otherwise.
  */
@@ -825,25 +887,25 @@
         var arVersion = navigator.appVersion.split("MSIE");
         var version = parseFloat(arVersion[1]);
         var filter = false;
-
-        // IEs4Lin dies when trying to access document.body.filters, because
+    
+        // IEs4Lin dies when trying to access document.body.filters, because 
         // the property is there, but requires a DLL that can't be provided. This
         // means that we need to wrap this in a try/catch so that this can
         // continue.
-
-        try {
+    
+        try { 
             filter = !!(document.body.filters);
-        } catch (e) {}
-
-        OpenLayers.Util.alphaHackNeeded = (filter &&
+        } catch (e) {}    
+    
+        OpenLayers.Util.alphaHackNeeded = (filter && 
                                            (version >= 5.5) && (version < 7));
     }
     return OpenLayers.Util.alphaHackNeeded;
 };
 
-/**
+/** 
  * Function: modifyAlphaImageDiv
- *
+ * 
  * div - {DOMElement} Div containing Alpha-adjusted Image
  * id - {String}
  * px - {<OpenLayers.Pixel>}
@@ -853,9 +915,9 @@
  * border - {String}
  * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
  * opacity - {Float} Fractional value (0.0 - 1.0)
- */
-OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL,
-                                               position, border, sizing,
+ */ 
+OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL, 
+                                               position, border, sizing, 
                                                opacity) {
 
     OpenLayers.Util.modifyDOMElement(div, id, px, sz, position,
@@ -866,9 +928,9 @@
     if (imgURL) {
         img.src = imgURL;
     }
-    OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz,
+    OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, 
                                      "relative", border);
-
+    
     if (OpenLayers.Util.alphaHack()) {
         if(div.style.display != "none") {
             div.style.display = "inline-block";
@@ -876,11 +938,11 @@
         if (sizing == null) {
             sizing = "scale";
         }
-
+        
         div.style.filter = "progid:DXImageTransform.Microsoft" +
                            ".AlphaImageLoader(src='" + img.src + "', " +
                            "sizingMethod='" + sizing + "')";
-        if (parseFloat(div.style.opacity) >= 0.0 &&
+        if (parseFloat(div.style.opacity) >= 0.0 && 
             parseFloat(div.style.opacity) < 1.0) {
             div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
         }
@@ -889,9 +951,9 @@
     }
 };
 
-/**
+/** 
  * Function: createAlphaImageDiv
- *
+ * 
  * id - {String}
  * px - {<OpenLayers.Pixel>}
  * sz - {<OpenLayers.Size>}
@@ -902,17 +964,17 @@
  * opacity - {Float} Fractional value (0.0 - 1.0)
  * delayDisplay - {Boolean} If true waits until the image has been
  *                          loaded.
- *
+ * 
  * Returns:
- * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is
+ * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is 
  *              needed for transparency in IE, it is added.
- */
-OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL,
-                                               position, border, sizing,
+ */ 
+OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL, 
+                                               position, border, sizing, 
                                                opacity, delayDisplay) {
-
+    
     var div = OpenLayers.Util.createDiv();
-    var img = OpenLayers.Util.createImage(null, null, null, null, null, null,
+    var img = OpenLayers.Util.createImage(null, null, null, null, null, null, 
                                           null, false);
     div.appendChild(img);
 
@@ -924,23 +986,23 @@
             OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
     }
 
-    OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position,
+    OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position, 
                                         border, sizing, opacity);
-
+    
     return div;
 };
 
 
-/**
+/** 
  * Function: upperCaseObject
- * Creates a new hashtable and copies over all the keys from the
+ * Creates a new hashtable and copies over all the keys from the 
  *     passed-in object, but storing them under an uppercased
  *     version of the key at which they were stored.
- *
- * Parameters:
+ * 
+ * Parameters: 
  * object - {Object}
- *
- * Returns:
+ * 
+ * Returns: 
  * {Object} A new Object with all the same keys but uppercased
  */
 OpenLayers.Util.upperCaseObject = function (object) {
@@ -951,12 +1013,12 @@
     return uObject;
 };
 
-/**
+/** 
  * Function: applyDefaults
  * Takes an object and copies any properties that don't exist from
  *     another properties, by analogy with OpenLayers.Util.extend() from
  *     Prototype.js.
- *
+ * 
  * Parameters:
  * to - {Object} The destination object.
  * from - {Object} The source object.  Any properties of this object that
@@ -992,27 +1054,27 @@
        && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) {
         to.toString = from.toString;
     }
-
+    
     return to;
 };
 
 /**
  * Function: getParameterString
- *
+ * 
  * Parameters:
  * params - {Object}
- *
+ * 
  * Returns:
- * {String} A concatenation of the properties of an object in
- *          http parameter notation.
+ * {String} A concatenation of the properties of an object in 
+ *          http parameter notation. 
  *          (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
  *          If a parameter is actually a list, that parameter will then
  *          be set to a comma-seperated list of values (foo,bar) instead
- *          of being URL escaped (foo%3Abar).
+ *          of being URL escaped (foo%3Abar). 
  */
 OpenLayers.Util.getParameterString = function(params) {
     var paramsArray = [];
-
+    
     for (var key in params) {
       var value = params[key];
       if ((value != null) && (typeof value != 'function')) {
@@ -1020,8 +1082,12 @@
         if (typeof value == 'object' && value.constructor == Array) {
           /* value is an array; encode items and separate with "," */
           var encodedItemArray = [];
+          var item;
           for (var itemIndex=0, len=value.length; itemIndex<len; itemIndex++) {
-            encodedItemArray.push(encodeURIComponent(value[itemIndex]));
+            item = value[itemIndex];
+            encodedItemArray.push(encodeURIComponent(
+                (item === null || item === undefined) ? "" : item)
+            );
           }
           encodedValue = encodedItemArray.join(",");
         }
@@ -1032,19 +1098,43 @@
         paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
       }
     }
-
+    
     return paramsArray.join("&");
 };
 
 /**
+ * Function: urlAppend
+ * Appends a parameter string to a url. This function includes the logic for
+ * using the appropriate character (none, & or ?) to append to the url before
+ * appending the param string.
+ * 
+ * Parameters:
+ * url - {String} The url to append to
+ * paramStr - {String} The param string to append
+ * 
+ * Returns:
+ * {String} The new url
+ */
+OpenLayers.Util.urlAppend = function(url, paramStr) {
+    var newUrl = url;
+    if(paramStr) {
+        var parts = (url + " ").split(/[?&]/);
+        newUrl += (parts.pop() === " " ?
+            paramStr :
+            parts.length ? "&" + paramStr : "?" + paramStr);
+    }
+    return newUrl;
+};
+
+/**
  * Property: ImgPath
  * {String} Default is ''.
  */
 OpenLayers.ImgPath = '';
 
-/**
+/** 
  * Function: getImagesLocation
- *
+ * 
  * Returns:
  * {String} The fully formatted image location string
  */
@@ -1053,18 +1143,18 @@
 };
 
 
-/**
+/** 
  * Function: Try
- * Execute functions until one of them doesn't throw an error.
+ * Execute functions until one of them doesn't throw an error. 
  *     Capitalized because "try" is a reserved word in JavaScript.
  *     Taken directly from OpenLayers.Util.Try()
- *
+ * 
  * Parameters:
  * [*] - {Function} Any number of parameters may be passed to Try()
- *    It will attempt to execute each of them until one of them
- *    successfully executes.
+ *    It will attempt to execute each of them until one of them 
+ *    successfully executes. 
  *    If none executes successfully, returns null.
- *
+ * 
  * Returns:
  * {*} The value returned by the first successfully executed function.
  */
@@ -1083,15 +1173,15 @@
 };
 
 
-/**
+/** 
  * Function: getNodes
- *
+ * 
  * These could/should be made namespace aware?
- *
+ * 
  * Parameters:
  * p - {}
  * tagName - {String}
- *
+ * 
  * Returns:
  * {Array}
  */
@@ -1110,11 +1200,11 @@
 
 /**
  * Function: _getNodes
- *
+ * 
  * Parameters:
  * nodes - {Array}
  * tagName - {String}
- *
+ * 
  * Returns:
  * {Array}
  */
@@ -1133,12 +1223,12 @@
 
 /**
  * Function: getTagText
- *
+ * 
  * Parameters:
  * parent - {}
  * item - {String}
  * index - {Integer}
- *
+ * 
  * Returns:
  * {String}
  */
@@ -1150,28 +1240,28 @@
             index=0;
         }
         if (result[index].childNodes.length > 1) {
-            return result.childNodes[1].nodeValue;
+            return result.childNodes[1].nodeValue; 
         }
         else if (result[index].childNodes.length == 1) {
-            return result[index].firstChild.nodeValue;
+            return result[index].firstChild.nodeValue; 
         }
-    } else {
-        return "";
+    } else { 
+        return ""; 
     }
 };
 
 /**
  * Function: getXmlNodeValue
- *
+ * 
  * Parameters:
  * node - {XMLNode}
- *
+ * 
  * Returns:
  * {String} The text value of the given node, without breaking in firefox or IE
  */
 OpenLayers.Util.getXmlNodeValue = function(node) {
     var val = null;
-    OpenLayers.Util.Try(
+    OpenLayers.Util.Try( 
         function() {
             val = node.text;
             if (!val) {
@@ -1180,20 +1270,20 @@
             if (!val) {
                 val = node.firstChild.nodeValue;
             }
-        },
+        }, 
         function() {
             val = node.textContent;
-        });
+        }); 
     return val;
 };
 
-/**
+/** 
  * Function: mouseLeft
- *
+ * 
  * Parameters:
  * evt - {Event}
  * div - {HTMLDivElement}
- *
+ * 
  * Returns:
  * {Boolean}
  */
@@ -1255,6 +1345,17 @@
 
 /**
  * Function: rad
+ * 
+ * Parameters:
+ * x - {Float}
+ * 
+ * Returns:
+ * {Float}
+ */
+OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
+
+/**
+ * Function: deg
  *
  * Parameters:
  * x - {Float}
@@ -1262,10 +1363,20 @@
  * Returns:
  * {Float}
  */
-OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
+OpenLayers.Util.deg = function(x) {return x*180/Math.PI;};
 
 /**
- * Function: distVincenty
+ * Property: VincentyConstants
+ * {Object} Constants for Vincenty functions.
+ */
+OpenLayers.Util.VincentyConstants = {
+    a: 6378137,
+    b: 6356752.3142,
+    f: 1/298.257223563
+};
+
+/**
+ * APIFunction: distVincenty
  * Given two objects representing points with geographic coordinates, this
  *     calculates the distance between those points on the surface of an
  *     ellipsoid.
@@ -1279,8 +1390,10 @@
  *     ellipsoid.  Note that the input point objects must be in geographic
  *     coordinates (decimal degrees) and the return distance is in kilometers.
  */
-OpenLayers.Util.distVincenty=function(p1, p2) {
-    var a = 6378137, b = 6356752.3142,  f = 1/298.257223563;
+OpenLayers.Util.distVincenty = function(p1, p2) {
+    var ct = OpenLayers.Util.VincentyConstants;
+    var a = ct.a, b = ct.b, f = ct.f;
+
     var L = OpenLayers.Util.rad(p2.lon - p1.lon);
     var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat)));
     var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat)));
@@ -1319,15 +1432,77 @@
 };
 
 /**
+ * APIFunction: destinationVincenty
+ * Calculate destination point given start point lat/long (numeric degrees),
+ * bearing (numeric degrees) & distance (in m).
+ * Adapted from Chris Veness work, see
+ * http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html
+ *
+ * Parameters:
+ * lonlat  - {<OpenLayers.LonLat>} (or any object with both .lat, .lon
+ *     properties) The start point.
+ * brng     - {Float} The bearing (degrees).
+ * distance - {Float} The ground distance (meters).
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} The destination point.
+ */
+OpenLayers.Util.destinationVincenty = function(lonlat, brng, dist) {
+    var u = OpenLayers.Util;
+    var ct = u.VincentyConstants;
+    var a = ct.a, b = ct.b, f = ct.f;
+
+    var lon1 = lonlat.lon;
+    var lat1 = lonlat.lat;
+
+    var s = dist;
+    var alpha1 = u.rad(brng);
+    var sinAlpha1 = Math.sin(alpha1);
+    var cosAlpha1 = Math.cos(alpha1);
+
+    var tanU1 = (1-f) * Math.tan(u.rad(lat1));
+    var cosU1 = 1 / Math.sqrt((1 + tanU1*tanU1)), sinU1 = tanU1*cosU1;
+    var sigma1 = Math.atan2(tanU1, cosAlpha1);
+    var sinAlpha = cosU1 * sinAlpha1;
+    var cosSqAlpha = 1 - sinAlpha*sinAlpha;
+    var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
+    var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
+    var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
+
+    var sigma = s / (b*A), sigmaP = 2*Math.PI;
+    while (Math.abs(sigma-sigmaP) > 1e-12) {
+        var cos2SigmaM = Math.cos(2*sigma1 + sigma);
+        var sinSigma = Math.sin(sigma);
+        var cosSigma = Math.cos(sigma);
+        var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
+            B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
+        sigmaP = sigma;
+        sigma = s / (b*A) + deltaSigma;
+    }
+
+    var tmp = sinU1*sinSigma - cosU1*cosSigma*cosAlpha1;
+    var lat2 = Math.atan2(sinU1*cosSigma + cosU1*sinSigma*cosAlpha1,
+        (1-f)*Math.sqrt(sinAlpha*sinAlpha + tmp*tmp));
+    var lambda = Math.atan2(sinSigma*sinAlpha1, cosU1*cosSigma - sinU1*sinSigma*cosAlpha1);
+    var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
+    var L = lambda - (1-C) * f * sinAlpha *
+        (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
+
+    var revAz = Math.atan2(sinAlpha, -tmp);  // final bearing
+
+    return new OpenLayers.LonLat(lon1+u.deg(L), u.deg(lat2));
+};
+
+/**
  * Function: getParameters
- * Parse the parameters from a URL or from the current page itself into a
+ * Parse the parameters from a URL or from the current page itself into a 
  *     JavaScript Object. Note that parameter values with commas are separated
  *     out into an Array.
- *
+ * 
  * Parameters:
  * url - {String} Optional url used to extract the query string.
  *                If null, query string is taken from page location.
- *
+ * 
  * Returns:
  * {Object} An object of key/value pairs from the query string.
  */
@@ -1352,17 +1527,14 @@
             var key = decodeURIComponent(keyValue[0]);
             var value = keyValue[1] || ''; //empty string if no value
 
-            //decode individual values
-            value = value.split(",");
-            for(var j=0, jlen=value.length; j<jlen; j++) {
-                value[j] = decodeURIComponent(value[j]);
-            }
+            //decode individual values (being liberal by replacing "+" with " ")
+            value = decodeURIComponent(value.replace(/\+/g, " ")).split(",");
 
-            //if there's only one value, do not return as array
+            //if there's only one value, do not return as array                    
             if (value.length == 1) {
                 value = value[0];
-            }
-
+            }                
+            
             parameters[key] = value;
          }
      }
@@ -1373,11 +1545,11 @@
  * Function: getArgs
  * *Deprecated*.  Will be removed in 3.0.  Please use instead
  *     <OpenLayers.Util.getParameters>
- *
+ * 
  * Parameters:
  * url - {String} Optional url used to extract the query string.
  *                If null, query string is taken from page location.
- *
+ * 
  * Returns:
  * {Object} An object of key/value pairs from the query string.
  */
@@ -1402,10 +1574,10 @@
  * Create a unique identifier for this session.  Each time this function
  *     is called, a counter is incremented.  The return will be the optional
  *     prefix (defaults to "id_") appended with the counter value.
- *
+ * 
  * Parameters:
  * prefix {String} Optionsal string to prefix unique id. Default is "id_".
- *
+ * 
  * Returns:
  * {String} A unique id string, built on the passed in prefix.
  */
@@ -1413,8 +1585,8 @@
     if (prefix == null) {
         prefix = "id_";
     }
-    OpenLayers.Util.lastSeqID += 1;
-    return prefix + OpenLayers.Util.lastSeqID;
+    OpenLayers.Util.lastSeqID += 1; 
+    return prefix + OpenLayers.Util.lastSeqID;        
 };
 
 /**
@@ -1426,7 +1598,7 @@
  * The hardcoded table is maintain in a CS-MAP source code module named CSdataU.c
  * The hardcoded table of PROJ.4 units are in pj_units.c.
  */
-OpenLayers.INCHES_PER_UNIT = {
+OpenLayers.INCHES_PER_UNIT = { 
     'inches': 1.0,
     'ft': 12.0,
     'mi': 63360.0,
@@ -1512,8 +1684,8 @@
     "ch": OpenLayers.INCHES_PER_UNIT["IntnlChain"],  //International Chain
     "link": OpenLayers.INCHES_PER_UNIT["IntnlLink"], //International Link
     "us-in": OpenLayers.INCHES_PER_UNIT["inches"], //U.S. Surveyor's Inch
-    "us-ft": OpenLayers.INCHES_PER_UNIT["Foot"],    //U.S. Surveyor's Foot
-    "us-yd": OpenLayers.INCHES_PER_UNIT["Yard"],    //U.S. Surveyor's Yard
+    "us-ft": OpenLayers.INCHES_PER_UNIT["Foot"],	//U.S. Surveyor's Foot
+    "us-yd": OpenLayers.INCHES_PER_UNIT["Yard"],	//U.S. Surveyor's Yard
     "us-ch": OpenLayers.INCHES_PER_UNIT["GunterChain"], //U.S. Surveyor's Chain
     "us-mi": OpenLayers.INCHES_PER_UNIT["Mile"],   //U.S. Surveyor's Statute Mile
     "ind-yd": OpenLayers.INCHES_PER_UNIT["IndianYd37"],  //Indian Yard
@@ -1521,7 +1693,7 @@
     "ind-ch": 20.11669506 / OpenLayers.METERS_PER_INCH  //Indian Chain
 });
 
-/**
+/** 
  * Constant: DOTS_PER_INCH
  * {Integer} 72 (A sensible default)
  */
@@ -1529,57 +1701,58 @@
 
 /**
  * Function: normalizeScale
- *
+ * 
  * Parameters:
  * scale - {float}
- *
+ * 
  * Returns:
- * {Float} A normalized scale value, in 1 / X format.
+ * {Float} A normalized scale value, in 1 / X format. 
  *         This means that if a value less than one ( already 1/x) is passed
- *         in, it just returns scale directly. Otherwise, it returns
+ *         in, it just returns scale directly. Otherwise, it returns 
  *         1 / scale
  */
 OpenLayers.Util.normalizeScale = function (scale) {
-    var normScale = (scale > 1.0) ? (1.0 / scale)
+    var normScale = (scale > 1.0) ? (1.0 / scale) 
                                   : scale;
     return normScale;
 };
 
 /**
  * Function: getResolutionFromScale
- *
+ * 
  * Parameters:
  * scale - {Float}
  * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
  *                  Default is degrees
- *
+ * 
  * Returns:
- * {Float} The corresponding resolution given passed-in scale and unit
- *         parameters.
+ * {Float} The corresponding resolution given passed-in scale and unit 
+ *     parameters.  If the given scale is falsey, the returned resolution will
+ *     be undefined.
  */
 OpenLayers.Util.getResolutionFromScale = function (scale, units) {
-
-    if (units == null) {
-        units = "degrees";
+    var resolution;
+    if (scale) {
+        if (units == null) {
+            units = "degrees";
+        }
+        var normScale = OpenLayers.Util.normalizeScale(scale);
+        resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
+                                        * OpenLayers.DOTS_PER_INCH);        
     }
-
-    var normScale = OpenLayers.Util.normalizeScale(scale);
-
-    var resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
-                                    * OpenLayers.DOTS_PER_INCH);
     return resolution;
 };
 
 /**
  * Function: getScaleFromResolution
- *
+ * 
  * Parameters:
  * resolution - {Float}
  * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
  *                  Default is degrees
- *
+ * 
  * Returns:
- * {Float} The corresponding scale given passed-in resolution and unit
+ * {Float} The corresponding scale given passed-in resolution and unit 
  *         parameters.
  */
 OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
@@ -1595,13 +1768,13 @@
 
 /**
  * Function: safeStopPropagation
- * *Deprecated*. This function has been deprecated. Please use directly
- *     <OpenLayers.Event.stop> passing 'true' as the 2nd
+ * *Deprecated*. This function has been deprecated. Please use directly 
+ *     <OpenLayers.Event.stop> passing 'true' as the 2nd 
  *     argument (preventDefault)
- *
+ * 
  * Safely stop the propagation of an event *without* preventing
  *   the default browser action from occurring.
- *
+ * 
  * Parameter:
  * evt - {Event}
  */
@@ -1611,11 +1784,11 @@
 
 /**
  * Function: pagePositon
- * Calculates the position of an element on the page.
+ * Calculates the position of an element on the page. 
  *
  * Parameters:
  * forElement - {DOMElement}
- *
+ * 
  * Returns:
  * {Array} two item array, L value then T value.
  */
@@ -1631,7 +1804,7 @@
                 break;
             }
         }
-
+        
         valueT += element.offsetTop  || 0;
         valueL += element.offsetLeft || 0;
 
@@ -1652,25 +1825,25 @@
         valueL -= element.scrollLeft || 0;
         element = element.parentNode;
     }
-
+    
     return [valueL, valueT];
 };
 
 
-/**
+/** 
  * Function: isEquivalentUrl
- * Test two URLs for equivalence.
- *
+ * Test two URLs for equivalence. 
+ * 
  * Setting 'ignoreCase' allows for case-independent comparison.
- *
- * Comparison is based on:
+ * 
+ * Comparison is based on: 
  *  - Protocol
  *  - Host (evaluated without the port)
  *  - Port (set 'ignorePort80' to ignore "80" values)
  *  - Hash ( set 'ignoreHash' to disable)
- *  - Pathname (for relative <-> absolute comparison)
+ *  - Pathname (for relative <-> absolute comparison) 
  *  - Arguments (so they can be out of order)
- *
+ *  
  * Parameters:
  * url1 - {String}
  * url2 - {String}
@@ -1714,22 +1887,22 @@
     for(var key in urlObj2.args) {
         return false;
     }
-
+    
     return true;
 };
 
 /**
  * Function: createUrlObject
- *
+ * 
  * Parameters:
  * url - {String}
  * options - {Object} A hash of options.  Can be one of:
  *            ignoreCase: lowercase url,
  *            ignorePort80: don't include explicit port if port is 80,
  *            ignoreHash: Don't include part of url after the hash (#).
- *
+ * 
  * Returns:
- * {Object} An object with separate url, a, port, host, and args parsed out
+ * {Object} An object with separate url, a, port, host, and args parsed out 
  *          and ready for comparison
  */
 OpenLayers.Util.createUrlObject = function(url, options) {
@@ -1750,21 +1923,21 @@
             url = fullUrl + parts.join("/") + "/" + url;
         }
     }
-
+  
     if (options.ignoreCase) {
-        url = url.toLowerCase();
+        url = url.toLowerCase(); 
     }
 
     var a = document.createElement('a');
     a.href = url;
-
+    
     var urlObject = {};
-
+    
     //host (without port)
     urlObject.host = a.host.split(":").shift();
 
     //protocol
-    urlObject.protocol = a.protocol;
+    urlObject.protocol = a.protocol;  
 
     //port (get uniform browser behavior with port 80 here)
     if(options.ignorePort80) {
@@ -1774,8 +1947,8 @@
     }
 
     //hash
-    urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash;
-
+    urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash;  
+    
     //args
     var queryString = a.search;
     if (!queryString) {
@@ -1786,30 +1959,30 @@
 
     //pathname (uniform browser behavior with leading "/")
     urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname;
-
-    return urlObject;
+    
+    return urlObject; 
 };
-
+ 
 /**
  * Function: removeTail
  * Takes a url and removes everything after the ? and #
- *
+ * 
  * Parameters:
  * url - {String} The url to process
- *
+ * 
  * Returns:
  * {String} The string with all queryString and Hash removed
  */
 OpenLayers.Util.removeTail = function(url) {
     var head = null;
-
+    
     var qMark = url.indexOf("?");
     var hashMark = url.indexOf("#");
 
     if (qMark == -1) {
         head = (hashMark != -1) ? url.substr(0,hashMark) : url;
     } else {
-        head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark))
+        head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark)) 
                                   : url.substr(0, qMark);
     }
     return head;
@@ -1818,24 +1991,24 @@
 
 /**
  * Function: getBrowserName
- *
+ * 
  * Returns:
- * {String} A string which specifies which is the current
- *          browser in which we are running.
- *
+ * {String} A string which specifies which is the current 
+ *          browser in which we are running. 
+ * 
  *          Currently-supported browser detection and codes:
  *           * 'opera' -- Opera
  *           * 'msie'  -- Internet Explorer
  *           * 'safari' -- Safari
  *           * 'firefox' -- FireFox
  *           * 'mozilla' -- Mozilla
- *
- *          If we are unable to property identify the browser, we
+ * 
+ *          If we are unable to property identify the browser, we 
  *           return an empty string.
  */
 OpenLayers.Util.getBrowserName = function() {
     var browserName = "";
-
+    
     var ua = navigator.userAgent.toLowerCase();
     if ( ua.indexOf( "opera" ) != -1 ) {
         browserName = "opera";
@@ -1850,46 +2023,46 @@
             browserName = "mozilla";
         }
     }
-
+    
     return browserName;
 };
 
 
 
-
+    
 /**
  * Method: getRenderedDimensions
  * Renders the contentHTML offscreen to determine actual dimensions for
  *     popup sizing. As we need layout to determine dimensions the content
- *     is rendered -9999px to the left and absolute to ensure the
+ *     is rendered -9999px to the left and absolute to ensure the 
  *     scrollbars do not flicker
- *
+ *     
  * Parameters:
  * contentHTML
- * size - {<OpenLayers.Size>} If either the 'w' or 'h' properties is
- *     specified, we fix that dimension of the div to be measured. This is
- *     useful in the case where we have a limit in one dimension and must
+ * size - {<OpenLayers.Size>} If either the 'w' or 'h' properties is 
+ *     specified, we fix that dimension of the div to be measured. This is 
+ *     useful in the case where we have a limit in one dimension and must 
  *     therefore meaure the flow in the other dimension.
  * options - {Object}
  *     displayClass - {String} Optional parameter.  A CSS class name(s) string
  *         to provide the CSS context of the rendered content.
- *     containerElement - {DOMElement} Optional parameter. Insert the HTML to
- *         this node instead of the body root when calculating dimensions.
- *
+ *     containerElement - {DOMElement} Optional parameter. Insert the HTML to 
+ *         this node instead of the body root when calculating dimensions. 
+ * 
  * Returns:
  * {OpenLayers.Size}
  */
 OpenLayers.Util.getRenderedDimensions = function(contentHTML, size, options) {
-
+    
     var w, h;
-
+    
     // create temp container div with restricted size
     var container = document.createElement("div");
     container.style.visibility = "hidden";
+        
+    var containerElement = (options && options.containerElement) 
+    	? options.containerElement : document.body;
 
-    var containerElement = (options && options.containerElement)
-        ? options.containerElement : document.body;
-
     //fix a dimension, if specified.
     if (size) {
         if (size.w) {
@@ -1905,11 +2078,11 @@
     if (options && options.displayClass) {
         container.className = options.displayClass;
     }
-
+    
     // create temp content div and assign content
     var content = document.createElement("div");
     content.innerHTML = contentHTML;
-
+    
     // we need overflow visible when calculating the size
     content.style.overflow = "visible";
     if (content.childNodes) {
@@ -1918,13 +2091,13 @@
             content.childNodes[i].style.overflow = "visible";
         }
     }
-
-    // add content to restricted container
+    
+    // add content to restricted container 
     container.appendChild(content);
-
+    
     // append container to body for rendering
     containerElement.appendChild(container);
-
+    
     // Opera and IE7 can't handle a node with position:aboslute if it inherits
     // position:absolute from a parent.
     var parentHasPositionAbsolute = false;
@@ -1943,14 +2116,14 @@
     if(!parentHasPositionAbsolute) {
         container.style.position = "absolute";
     }
-
+    
     // calculate scroll width of content and add corners and shadow width
     if (!w) {
         w = parseInt(content.scrollWidth);
-
+    
         // update container width to allow height to adjust
         container.style.width = w + "px";
-    }
+    }        
     // capture height and add shadow and corner image widths
     if (!h) {
         h = parseInt(content.scrollHeight);
@@ -1959,35 +2132,35 @@
     // remove elements
     container.removeChild(content);
     containerElement.removeChild(container);
-
+    
     return new OpenLayers.Size(w, h);
 };
 
 /**
  * APIFunction: getScrollbarWidth
  * This function has been modified by the OpenLayers from the original version,
- *     written by Matthew Eernisse and released under the Apache 2
+ *     written by Matthew Eernisse and released under the Apache 2 
  *     license here:
- *
+ * 
  *     http://www.fleegix.org/articles/2006/05/30/getting-the-scrollbar-width-in-pixels
- *
- *     It has been modified simply to cache its value, since it is physically
- *     impossible that this code could ever run in more than one browser at
- *     once.
- *
+ * 
+ *     It has been modified simply to cache its value, since it is physically 
+ *     impossible that this code could ever run in more than one browser at 
+ *     once. 
+ * 
  * Returns:
  * {Integer}
  */
 OpenLayers.Util.getScrollbarWidth = function() {
-
+    
     var scrollbarWidth = OpenLayers.Util._scrollbarWidth;
-
+    
     if (scrollbarWidth == null) {
         var scr = null;
         var inn = null;
         var wNoScroll = 0;
         var wScroll = 0;
-
+    
         // Outer scrolling div
         scr = document.createElement('div');
         scr.style.position = 'absolute';
@@ -1997,28 +2170,28 @@
         scr.style.height = '50px';
         // Start with no scrollbar
         scr.style.overflow = 'hidden';
-
+    
         // Inner content div
         inn = document.createElement('div');
         inn.style.width = '100%';
         inn.style.height = '200px';
-
+    
         // Put the inner div in the scrolling div
         scr.appendChild(inn);
         // Append the scrolling div to the doc
         document.body.appendChild(scr);
-
+    
         // Width of the inner div sans scrollbar
         wNoScroll = inn.offsetWidth;
-
+    
         // Add the scrollbar
         scr.style.overflow = 'scroll';
         // Width of the inner div width scrollbar
         wScroll = inn.offsetWidth;
-
+    
         // Remove the scrolling div from the doc
         document.body.removeChild(document.body.lastChild);
-
+    
         // Pixel width of the scroller
         OpenLayers.Util._scrollbarWidth = (wNoScroll - wScroll);
         scrollbarWidth = OpenLayers.Util._scrollbarWidth;
@@ -2026,12 +2199,71 @@
 
     return scrollbarWidth;
 };
+
+/**
+ * APIFunction: getFormattedLonLat
+ * This function will return latitude or longitude value formatted as 
+ *
+ * Parameters:
+ * coordinate - {Float} the coordinate value to be formatted
+ * axis - {String} value of either 'lat' or 'lon' to indicate which axis is to
+ *          to be formatted (default = lat)
+ * dmsOption - {String} specify the precision of the output can be one of:
+ *           'dms' show degrees minutes and seconds
+ *           'dm' show only degrees and minutes
+ *           'd' show only degrees
+ * 
+ * Returns:
+ * {String} the coordinate value formatted as a string
+ */
+OpenLayers.Util.getFormattedLonLat = function(coordinate, axis, dmsOption) {
+    if (!dmsOption) {
+        dmsOption = 'dms';    //default to show degree, minutes, seconds
+    }
+    var abscoordinate = Math.abs(coordinate)
+    var coordinatedegrees = Math.floor(abscoordinate);
+
+    var coordinateminutes = (abscoordinate - coordinatedegrees)/(1/60);
+    var tempcoordinateminutes = coordinateminutes;
+    coordinateminutes = Math.floor(coordinateminutes);
+    var coordinateseconds = (tempcoordinateminutes - coordinateminutes)/(1/60);
+    coordinateseconds =  Math.round(coordinateseconds*10);
+    coordinateseconds /= 10;
+
+    if( coordinatedegrees < 10 ) {
+        coordinatedegrees = "0" + coordinatedegrees;
+    }
+    var str = coordinatedegrees + "\u00B0";
+
+    if (dmsOption.indexOf('dm') >= 0) {
+        if( coordinateminutes < 10 ) {
+            coordinateminutes = "0" + coordinateminutes;
+        }
+        str += coordinateminutes + "'";
+  
+        if (dmsOption.indexOf('dms') >= 0) {
+            if( coordinateseconds < 10 ) {
+                coordinateseconds = "0" + coordinateseconds;
+            }
+            str += coordinateseconds + '"';
+        }
+    }
+    
+    if (axis == "lon") {
+        str += coordinate < 0 ? OpenLayers.i18n("W") : OpenLayers.i18n("E");
+    } else {
+        str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N");
+    }
+    return str;
+};
+
 /* ======================================================================
     OpenLayers/Console.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -2046,7 +2278,7 @@
  * Note that behavior will differ with the Firebug extention and Firebug Lite.
  * Most notably, the Firebug Lite console does not currently allow for
  * hyperlinks to code or for clicking on object to explore their properties.
- *
+ * 
  */
 OpenLayers.Console = {
     /**
@@ -2055,7 +2287,7 @@
      * included.  We explicitly require the Firebug Lite script to trigger
      * functionality of the OpenLayers.Console methods.
      */
-
+    
     /**
      * APIFunction: log
      * Log an object in the console.  The Firebug Lite console logs string
@@ -2065,7 +2297,7 @@
      * will be used in string substitution.  Any additional arguments (beyond
      * the number substituted in a format string) will be appended in a space-
      * delimited line.
-     *
+     * 
      * Parameters:
      * object - {Object}
      */
@@ -2077,7 +2309,7 @@
      * where it was called.
      *
      * May be called with multiple arguments as with OpenLayers.Console.log().
-     *
+     * 
      * Parameters:
      * object - {Object}
      */
@@ -2089,7 +2321,7 @@
      * coding and a hyperlink to the line where it was called.
      *
      * May be called with multiple arguments as with OpenLayers.Console.log().
-     *
+     * 
      * Parameters:
      * object - {Object}
      */
@@ -2101,7 +2333,7 @@
      * color coding and a hyperlink to the line where it was called.
      *
      * May be called with multiple arguments as with OpenLayers.Console.log().
-     *
+     * 
      * Parameters:
      * object - {Object}
      */
@@ -2113,12 +2345,12 @@
      * coding and a hyperlink to the line where it was called.
      *
      * May be called with multiple arguments as with OpenLayers.Console.log().
-     *
+     * 
      * Parameters:
      * object - {Object}
      */
     error: function() {},
-
+    
     /**
      * APIFunction: userError
      * A single interface for showing error messages to the user. The default
@@ -2126,7 +2358,7 @@
      * reassigning OpenLayers.Console.userError to a different function.
      *
      * Expects a single error message
-     *
+     * 
      * Parameters:
      * object - {Object}
      */
@@ -2140,7 +2372,7 @@
      * the console and throw an exception.
      *
      * May be called with multiple arguments as with OpenLayers.Console.log().
-     *
+     * 
      * Parameters:
      * object - {Object}
      */
@@ -2150,7 +2382,7 @@
      * APIFunction: dir
      * Prints an interactive listing of all properties of the object. This
      * looks identical to the view that you would see in the DOM tab.
-     *
+     * 
      * Parameters:
      * object - {Object}
      */
@@ -2161,7 +2393,7 @@
      * Prints the XML source tree of an HTML or XML element. This looks
      * identical to the view that you would see in the HTML tab. You can click
      * on any node to inspect it in the HTML tab.
-     *
+     * 
      * Parameters:
      * object - {Object}
      */
@@ -2174,7 +2406,7 @@
      * as well as the values that were passed as arguments to each function.
      * You can click each function to take you to its source in the Script tab,
      * and click each argument value to inspect it in the DOM or HTML tabs.
-     *
+     * 
      */
     trace: function() {},
 
@@ -2185,7 +2417,7 @@
      * to close the block.
      *
      * May be called with multiple arguments as with OpenLayers.Console.log().
-     *
+     * 
      * Parameters:
      * object - {Object}
      */
@@ -2197,7 +2429,7 @@
      * OpenLayers.Console.group
      */
     groupEnd: function() {},
-
+    
     /**
      * APIFunction: time
      * Creates a new timer under the given name. Call
@@ -2225,7 +2457,7 @@
      * contain the text to be printed in the header of the profile report.
      *
      * This function is not currently implemented in Firebug Lite.
-     *
+     * 
      * Parameters:
      * title - {String} Optional title for the profiler
      */
@@ -2234,7 +2466,7 @@
     /**
      * APIFunction: profileEnd
      * Turns off the JavaScript profiler and prints its report.
-     *
+     * 
      * This function is not currently implemented in Firebug Lite.
      */
     profileEnd: function() {},
@@ -2279,8 +2511,9 @@
     OpenLayers/BaseTypes.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -2293,8 +2526,8 @@
  * @requires OpenLayers/Lang/en.js
  * @requires OpenLayers/Console.js
  */
-
-/**
+ 
+/** 
  * Header: OpenLayers Base Types
  * OpenLayers custom string, number and function functions are described here.
  */
@@ -2307,12 +2540,12 @@
 
     /**
      * APIFunction: startsWith
-     * Test whether a string starts with another string.
-     *
+     * Test whether a string starts with another string. 
+     * 
      * Parameters:
      * str - {String} The string to test.
      * sub - {Sring} The substring to look for.
-     *
+     *  
      * Returns:
      * {Boolean} The first string starts with the second.
      */
@@ -2323,43 +2556,43 @@
     /**
      * APIFunction: contains
      * Test whether a string contains another string.
-     *
+     * 
      * Parameters:
      * str - {String} The string to test.
      * sub - {String} The substring to look for.
-     *
+     * 
      * Returns:
      * {Boolean} The first string contains the second.
      */
     contains: function(str, sub) {
         return (str.indexOf(sub) != -1);
     },
-
+    
     /**
      * APIFunction: trim
      * Removes leading and trailing whitespace characters from a string.
-     *
+     * 
      * Parameters:
      * str - {String} The (potentially) space padded string.  This string is not
      *     modified.
-     *
+     * 
      * Returns:
-     * {String} A trimmed version of the string with all leading and
+     * {String} A trimmed version of the string with all leading and 
      *     trailing spaces removed.
      */
     trim: function(str) {
         return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
     },
-
+    
     /**
      * APIFunction: camelize
-     * Camel-case a hyphenated string.
+     * Camel-case a hyphenated string. 
      *     Ex. "chicken-head" becomes "chickenHead", and
      *     "-chicken-head" becomes "ChickenHead".
      *
      * Parameters:
      * str - {String} The string to be camelized.  The original is not modified.
-     *
+     * 
      * Returns:
      * {String} The string, camelized
      */
@@ -2372,7 +2605,7 @@
         }
         return camelizedString;
     },
-
+    
     /**
      * APIFunction: format
      * Given a string with tokens in the form ${token}, return a string
@@ -2399,7 +2632,7 @@
             context = window;
         }
 
-        // Example matching:
+        // Example matching: 
         // str   = ${foo.bar}
         // match = foo.bar
         var replacer = function(str, match) {
@@ -2425,13 +2658,13 @@
             }
 
             // If replacement is undefined, return the string 'undefined'.
-            // This is a workaround for a bugs in browsers not properly
+            // This is a workaround for a bugs in browsers not properly 
             // dealing with non-participating groups in regular expressions:
             // http://blog.stevenlevithan.com/archives/npcg-javascript
             if (typeof replacement == 'undefined') {
                 return 'undefined';
             } else {
-                return replacement;
+                return replacement; 
             }
         };
 
@@ -2444,13 +2677,13 @@
      * Examples: ${a}, ${a.b.c}, ${a-b}, ${5}
      */
     tokenRegEx:  /\$\{([\w.]+?)\}/g,
-
+    
     /**
      * Property: OpenLayers.String.numberRegEx
      * Used to test strings as numbers.
      */
     numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,
-
+    
     /**
      * APIFunction: OpenLayers.String.isNumeric
      * Determine whether a string contains only a numeric value.
@@ -2469,14 +2702,14 @@
     isNumeric: function(value) {
         return OpenLayers.String.numberRegEx.test(value);
     },
-
+    
     /**
      * APIFunction: numericIf
      * Converts a string that appears to be a numeric value into a number.
-     *
+     * 
      * Returns
      * {Number|String} a Number if the passed value is a number, a String
-     *     otherwise.
+     *     otherwise. 
      */
     numericIf: function(value) {
         return OpenLayers.String.isNumeric(value) ? parseFloat(value) : value;
@@ -2487,11 +2720,11 @@
 if (!String.prototype.startsWith) {
     /**
      * APIMethod: String.startsWith
-     * *Deprecated*. Whether or not a string starts with another string.
-     *
+     * *Deprecated*. Whether or not a string starts with another string. 
+     * 
      * Parameters:
      * sStart - {Sring} The string we're testing for.
-     *
+     *  
      * Returns:
      * {Boolean} Whether or not this string starts with the string passed in.
      */
@@ -2506,10 +2739,10 @@
     /**
      * APIMethod: String.contains
      * *Deprecated*. Whether or not a string contains another string.
-     *
+     * 
      * Parameters:
      * str - {String} The string that we're testing for.
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not this string contains with the string passed in.
      */
@@ -2524,9 +2757,9 @@
     /**
      * APIMethod: String.trim
      * *Deprecated*. Removes leading and trailing whitespace characters from a string.
-     *
+     * 
      * Returns:
-     * {String} A trimmed version of the string - all leading and
+     * {String} A trimmed version of the string - all leading and 
      *          trailing spaces removed
      */
     String.prototype.trim = function() {
@@ -2539,10 +2772,10 @@
 if (!String.prototype.camelize) {
     /**
      * APIMethod: String.camelize
-     * *Deprecated*. Camel-case a hyphenated string.
+     * *Deprecated*. Camel-case a hyphenated string. 
      *     Ex. "chicken-head" becomes "chickenHead", and
      *     "-chicken-head" becomes "ChickenHead".
-     *
+     * 
      * Returns:
      * {String} The string, camelized
      */
@@ -2564,21 +2797,21 @@
      * Decimal separator to use when formatting numbers.
      */
     decimalSeparator: ".",
-
+    
     /**
      * Property: thousandsSeparator
      * Thousands separator to use when formatting numbers.
      */
     thousandsSeparator: ",",
-
+    
     /**
      * APIFunction: limitSigDigs
      * Limit the number of significant digits on a float.
-     *
+     * 
      * Parameters:
      * num - {Float}
      * sig - {Integer}
-     *
+     * 
      * Returns:
      * {Float} The number, rounded to the specified number of significant
      *     digits.
@@ -2590,11 +2823,11 @@
         }
         return fig;
     },
-
+    
     /**
      * APIFunction: format
      * Formats a number for output.
-     *
+     * 
      * Parameters:
      * num  - {Float}
      * dec  - {Integer} Number of decimal places to round to.
@@ -2608,9 +2841,9 @@
      * {String} A string representing the formatted number.
      */
     format: function(num, dec, tsep, dsep) {
-        dec = (typeof dec != "undefined") ? dec : 0;
+        dec = (typeof dec != "undefined") ? dec : 0; 
         tsep = (typeof tsep != "undefined") ? tsep :
-            OpenLayers.Number.thousandsSeparator;
+            OpenLayers.Number.thousandsSeparator; 
         dsep = (typeof dsep != "undefined") ? dsep :
             OpenLayers.Number.decimalSeparator;
 
@@ -2623,15 +2856,15 @@
             // integer where we do not want to touch the decimals
             dec = 0;
         }
-
+        
         var integer = parts[0];
         if (tsep) {
-            var thousands = /(-?[0-9]+)([0-9]{3})/;
-            while(thousands.test(integer)) {
-                integer = integer.replace(thousands, "$1" + tsep + "$2");
+            var thousands = /(-?[0-9]+)([0-9]{3})/; 
+            while(thousands.test(integer)) { 
+                integer = integer.replace(thousands, "$1" + tsep + "$2"); 
             }
         }
-
+        
         var str;
         if (dec == 0) {
             str = integer;
@@ -2651,10 +2884,10 @@
      * APIMethod: Number.limitSigDigs
      * *Deprecated*. Limit the number of significant digits on an integer. Does *not*
      *     work with floats!
-     *
+     * 
      * Parameters:
      * sig - {Integer}
-     *
+     * 
      * Returns:
      * {Integer} The number, rounded to the specified number of significant digits.
      *           If null, 0, or negative value passed in, returns 0
@@ -2675,11 +2908,11 @@
      * APIFunction: bind
      * Bind a function to an object.  Method to easily create closures with
      *     'this' altered.
-     *
+     * 
      * Parameters:
      * func - {Function} Input function.
      * object - {Object} The object to bind to the input function (as this).
-     *
+     * 
      * Returns:
      * {Function} A closure with 'this' set to the passed in object.
      */
@@ -2695,16 +2928,16 @@
             return func.apply(object, newArgs);
         };
     },
-
+    
     /**
      * APIFunction: bindAsEventListener
      * Bind a function to an object, and configure it to receive the event
-     *     object as first parameter when called.
-     *
+     *     object as first parameter when called. 
+     * 
      * Parameters:
      * func - {Function} Input function to serve as an event listener.
      * object - {Object} A reference to this.
-     *
+     * 
      * Returns:
      * {Function}
      */
@@ -2712,18 +2945,50 @@
         return function(event) {
             return func.call(object, event || window.event);
         };
+    },
+    
+    /**
+     * APIFunction: False
+     * A simple function to that just does "return false". We use this to 
+     * avoid attaching anonymous functions to DOM event handlers, which 
+     * causes "issues" on IE<8.
+     * 
+     * Usage:
+     * document.onclick = OpenLayers.Function.False;
+     * 
+     * Returns:
+     * {Boolean}
+     */
+    False : function() {
+        return false;
+    },
+
+    /**
+     * APIFunction: True
+     * A simple function to that just does "return true". We use this to 
+     * avoid attaching anonymous functions to DOM event handlers, which 
+     * causes "issues" on IE<8.
+     * 
+     * Usage:
+     * document.onclick = OpenLayers.Function.True;
+     * 
+     * Returns:
+     * {Boolean}
+     */
+    True : function() {
+        return true;
     }
 };
 
 if (!Function.prototype.bind) {
     /**
      * APIMethod: Function.bind
-     * *Deprecated*. Bind a function to an object.
+     * *Deprecated*. Bind a function to an object. 
      * Method to easily create closures with 'this' altered.
-     *
+     * 
      * Parameters:
      * object - {Object} the this parameter
-     *
+     * 
      * Returns:
      * {Function} A closure with 'this' altered to the first
      *            argument.
@@ -2741,11 +3006,11 @@
     /**
      * APIMethod: Function.bindAsEventListener
      * *Deprecated*. Bind a function to an object, and configure it to receive the
-     *     event object as first parameter when called.
-     *
+     *     event object as first parameter when called. 
+     * 
      * Parameters:
      * object - {Object} A reference to this.
-     *
+     * 
      * Returns:
      * {Function}
      */
@@ -2768,7 +3033,7 @@
      *     Array.prototype.filter extension to the ECMA-262 standard.  Where
      *     available, Array.prototype.filter will be used.
      *
-     * Based on well known example from http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:filter
+     * Based on well known example from http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/filter
      *
      * Parameters:
      * array - {Array} The array to be filtered.  This array is not mutated.
@@ -2802,29 +3067,150 @@
                         selected.push(val);
                     }
                 }
-            }
+            }        
         }
         return selected;
     }
+    
+};
 
+/**
+ * Namespace: OpenLayers.Date
+ * Contains implementations of Date.parse and date.toISOString that match the 
+ *     ECMAScript 5 specification for parsing RFC 3339 dates.
+ *     http://tools.ietf.org/html/rfc3339
+ */
+OpenLayers.Date = {
+    
+    /**
+     * APIMethod: toISOString
+     * Generates a string representing a date.  The format of the string follows 
+     *     the profile of ISO 8601 for date and time on the Internet (see 
+     *     http://tools.ietf.org/html/rfc3339).  If the toISOString method is 
+     *     available on the Date prototype, that is used.  The toISOString
+     *     method for Date instances is defined in ECMA-262.
+     *
+     * Parameters:
+     * date - {Date} A date object.
+     *
+     * Returns:
+     * {String} A string representing the date (e.g. 
+     *     "2010-08-07T16:58:23.123Z").  If the date does not have a valid time
+     *     (i.e. isNaN(date.getTime())) this method returns the string "Invalid
+     *     Date".  The ECMA standard says the toISOString method should throw
+     *     RangeError in this case, but Firefox returns a string instead.  For
+     *     best results, use isNaN(date.getTime()) to determine date validity
+     *     before generating date strings.  
+     */
+    toISOString: (function() {
+        if ("toISOString" in Date.prototype) {
+            return function(date) {
+                return date.toISOString();
+            }
+        } else {
+            function pad(num, len) {
+                var str = num + "";
+                while (str.length < len) {
+                    str = "0" + str;
+                }
+                return str;
+            }
+            return function(date) {
+                var str;
+                if (isNaN(date.getTime())) {
+                    // ECMA-262 says throw RangeError, Firefox returns 
+                    // "Invalid Date"
+                    str = "Invalid Date";
+                } else {
+                    str = 
+                        date.getUTCFullYear() + "-" +
+                        pad(date.getUTCMonth() + 1, 2) + "-" +
+                        pad(date.getUTCDate(), 2) + "T" +
+                        pad(date.getUTCHours(), 2) + ":" +
+                        pad(date.getUTCMinutes(), 2) + ":" +
+                        pad(date.getUTCSeconds(), 2) + "." +
+                        pad(date.getUTCMilliseconds(), 3) + "Z";
+                }
+                return str;
+            }
+        }
+
+    })(),
+    
+    /**
+     * APIMethod: parse
+     * Generate a date object from a string.  The format for the string follows
+     *     the profile of ISO 8601 for date and time on the Internet (see 
+     *     http://tools.ietf.org/html/rfc3339).  If the parse method on 
+     *     the Date constructor returns a valid date for the given string,
+     *     that method is used.
+     *
+     * Parameters:
+     * str - {String} A string representing the date (e.g. 
+     *     "2010", "2010-08", "2010-08-07", "2010-08-07T16:58:23.123Z",
+     *     "2010-08-07T11:58:23.123-06").
+     * 
+     * Returns:
+     * {Date} A date object.  If the string could not be parsed, an invalid
+     *     date is returned (i.e. isNaN(date.getTime())).
+     */
+    parse: function(str) {
+        var date;
+        // first check if the native parse method can parse it
+        var elapsed = Date.parse(str);
+        if (!isNaN(elapsed)) {
+            date = new Date(elapsed);
+        } else {
+            var match = str.match(/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))?$/);
+            var date;
+            if (match && (match[1] || match[7])) { // must have at least year or time
+                var year = parseInt(match[1], 10) || 0;
+                var month = (parseInt(match[2], 10) - 1) || 0;
+                var day = parseInt(match[3], 10) || 1;
+                date = new Date(Date.UTC(year, month, day));
+                // optional time
+                var type = match[7];
+                if (type) {
+                    var hours = parseInt(match[4], 10);
+                    var minutes = parseInt(match[5], 10);
+                    var secFrac = parseFloat(match[6]);
+                    var seconds = secFrac | 0;
+                    var milliseconds = Math.round(1000 * (secFrac - seconds));
+                    date.setUTCHours(hours, minutes, seconds, milliseconds);
+                    // check offset
+                    if (type !== "Z") {
+                        var hoursOffset = parseInt(type, 10);
+                        var minutesOffset = parseInt(match[8]) || 0;
+                        var offset = -1000 * (60 * (hoursOffset * 60) + minutesOffset * 60);
+                        date = new Date(date.getTime() + offset);
+                    }
+                }
+            } else {
+                date = new Date("invalid");
+            }
+        }
+        return date;
+    }
+
 };
 /* ======================================================================
     OpenLayers/BaseTypes/Class.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
  * Constructor: OpenLayers.Class
- * Base class used to construct all other classes. Includes support for
- *     multiple inheritance.
- *
- * This constructor is new in OpenLayers 2.5.  At OpenLayers 3.0, the old
- *     syntax for creating classes and dealing with inheritance
+ * Base class used to construct all other classes. Includes support for 
+ *     multiple inheritance. 
+ *     
+ * This constructor is new in OpenLayers 2.5.  At OpenLayers 3.0, the old 
+ *     syntax for creating classes and dealing with inheritance 
  *     will be removed.
- *
+ * 
  * To create a new OpenLayers-style class, use the following syntax:
  * > var MyClass = OpenLayers.Class(prototype);
  *
@@ -2849,30 +3235,31 @@
         }
     };
     var extended = {};
-    var parent, initialize;
+    var parent, initialize, Type;
     for(var i=0, len=arguments.length; i<len; ++i) {
-        if(typeof arguments[i] == "function") {
+        Type = arguments[i];
+        if(typeof Type == "function") {
             // make the class passed as the first argument the superclass
             if(i == 0 && len > 1) {
-                initialize = arguments[i].prototype.initialize;
+                initialize = Type.prototype.initialize;
                 // replace the initialize method with an empty function,
                 // because we do not want to create a real instance here
-                arguments[i].prototype.initialize = function() {};
+                Type.prototype.initialize = function() {};
                 // the line below makes sure that the new class has a
                 // superclass
-                extended = new arguments[i];
+                extended = new Type();
                 // restore the original initialize method
                 if(initialize === undefined) {
-                    delete arguments[i].prototype.initialize;
+                    delete Type.prototype.initialize;
                 } else {
-                    arguments[i].prototype.initialize = initialize;
+                    Type.prototype.initialize = initialize;
                 }
             }
             // get the prototype of the superclass
-            parent = arguments[i].prototype;
+            parent = Type.prototype;
         } else {
             // in this case we're extending with the prototype
-            parent = arguments[i];
+            parent = Type;
         }
         OpenLayers.Util.extend(extended, parent);
     }
@@ -2930,8 +3317,9 @@
     OpenLayers/BaseTypes/Size.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -2945,7 +3333,7 @@
      * {Number} width
      */
     w: 0.0,
-
+    
     /**
      * APIProperty: h
      * {Number} height
@@ -2971,7 +3359,7 @@
      * Return the string representation of a size object
      *
      * Returns:
-     * {String} The string representation of OpenLayers.Size object.
+     * {String} The string representation of OpenLayers.Size object. 
      * (ex. <i>"w=55,h=66"</i>)
      */
     toString:function() {
@@ -2998,7 +3386,7 @@
      * Parameters:
      * sz - {<OpenLayers.Size>}
      *
-     * Returns:
+     * Returns: 
      * {Boolean} The passed in size has the same h and w properties as this one.
      * Note that if sz passed in is null, returns false.
      *
@@ -3018,8 +3406,9 @@
     OpenLayers/BaseTypes/Bounds.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -3031,7 +3420,7 @@
  * Instances of this class represent bounding boxes.  Data stored as left,
  * bottom, right, top floats. All values are initialized to null, however,
  * you should make sure you set them before using the bounds for anything.
- *
+ * 
  * Possible use case:
  * > bounds = new OpenLayers.Bounds();
  * > bounds.extend(new OpenLayers.LonLat(4,5));
@@ -3063,7 +3452,7 @@
      * {Number} Maximum vertical coordinate.
      */
     top: null,
-
+    
     /**
      * Property: centerLonLat
      * {<OpenLayers.LonLat>} A cached center location.  This should not be
@@ -3106,7 +3495,7 @@
      * {<OpenLayers.Bounds>} A fresh copy of the bounds
      */
     clone:function() {
-        return new OpenLayers.Bounds(this.left, this.bottom,
+        return new OpenLayers.Bounds(this.left, this.bottom, 
                                      this.right, this.top);
     },
 
@@ -3119,25 +3508,25 @@
      *
      * Returns:
      * {Boolean} The passed-in bounds object has the same left,
-     *           right, top, bottom components as this.  Note that if bounds
+     *           right, top, bottom components as this.  Note that if bounds 
      *           passed in is null, returns false.
      */
     equals:function(bounds) {
         var equals = false;
         if (bounds != null) {
-            equals = ((this.left == bounds.left) &&
+            equals = ((this.left == bounds.left) && 
                       (this.right == bounds.right) &&
-                      (this.top == bounds.top) &&
+                      (this.top == bounds.top) && 
                       (this.bottom == bounds.bottom));
         }
         return equals;
     },
 
-    /**
+    /** 
      * APIMethod: toString
-     *
+     * 
      * Returns:
-     * {String} String representation of bounds object.
+     * {String} String representation of bounds object. 
      *          (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
      */
     toString:function() {
@@ -3148,37 +3537,48 @@
     /**
      * APIMethod: toArray
      *
+     * Parameters:
+     * reverseAxisOrder - {Boolean} Should we reverse the axis order?
+     *
      * Returns:
      * {Array} array of left, bottom, right, top
      */
-    toArray: function() {
-        return [this.left, this.bottom, this.right, this.top];
-    },
+    toArray: function(reverseAxisOrder) {
+        if (reverseAxisOrder === true) {
+            return [this.bottom, this.left, this.top, this.right];
+        } else {
+            return [this.left, this.bottom, this.right, this.top];
+        }
+    },    
 
-    /**
+    /** 
      * APIMethod: toBBOX
-     *
+     * 
      * Parameters:
      * decimal - {Integer} How many significant digits in the bbox coords?
      *                     Default is 6
-     *
+     * reverseAxisOrder - {Boolean} Should we reverse the axis order?
+     * 
      * Returns:
      * {String} Simple String representation of bounds object.
      *          (ex. <i>"5,42,10,45"</i>)
      */
-    toBBOX:function(decimal) {
+    toBBOX:function(decimal, reverseAxisOrder) {
         if (decimal== null) {
-            decimal = 6;
+            decimal = 6; 
         }
         var mult = Math.pow(10, decimal);
-        var bbox = Math.round(this.left * mult) / mult + "," +
-                   Math.round(this.bottom * mult) / mult + "," +
-                   Math.round(this.right * mult) / mult + "," +
-                   Math.round(this.top * mult) / mult;
-
-        return bbox;
+        var xmin = Math.round(this.left * mult) / mult;
+        var ymin = Math.round(this.bottom * mult) / mult;
+        var xmax = Math.round(this.right * mult) / mult;
+        var ymax = Math.round(this.top * mult) / mult;
+        if (reverseAxisOrder === true) {
+            return ymin + "," + xmin + "," + ymax + "," + xmax;
+        } else {
+            return xmin + "," + ymin + "," + xmax + "," + ymax;
+        }
     },
-
+ 
     /**
      * APIMethod: toGeometry
      * Create a new polygon geometry based on this bounds.
@@ -3197,10 +3597,10 @@
             ])
         ]);
     },
-
+    
     /**
      * APIMethod: getWidth
-     *
+     * 
      * Returns:
      * {Float} The width of the bounds
      */
@@ -3210,7 +3610,7 @@
 
     /**
      * APIMethod: getHeight
-     *
+     * 
      * Returns:
      * {Float} The height of the bounds (top minus bottom).
      */
@@ -3220,7 +3620,7 @@
 
     /**
      * APIMethod: getSize
-     *
+     * 
      * Returns:
      * {<OpenLayers.Size>} The size of the box.
      */
@@ -3230,7 +3630,7 @@
 
     /**
      * APIMethod: getCenterPixel
-     *
+     * 
      * Returns:
      * {<OpenLayers.Pixel>} The center of the bounds in pixel space.
      */
@@ -3241,7 +3641,7 @@
 
     /**
      * APIMethod: getCenterLonLat
-     *
+     * 
      * Returns:
      * {<OpenLayers.LonLat>} The center of the bounds in map space.
      */
@@ -3256,12 +3656,12 @@
 
     /**
      * Method: scale
-     * Scales the bounds around a pixel or lonlat. Note that the new
+     * Scales the bounds around a pixel or lonlat. Note that the new 
      *     bounds may return non-integer properties, even if a pixel
-     *     is passed.
-     *
+     *     is passed. 
+     * 
      * Parameters:
-     * ratio - {Float}
+     * ratio - {Float} 
      * origin - {<OpenLayers.Pixel> or <OpenLayers.LonLat>}
      *          Default is center.
      *
@@ -3274,9 +3674,7 @@
         if(origin == null){
             origin = this.getCenterLonLat();
         }
-
-        var bounds = [];
-
+        
         var origx,origy;
 
         // get origin coordinates
@@ -3292,17 +3690,17 @@
         var bottom = (this.bottom - origy) * ratio + origy;
         var right = (this.right - origx) * ratio + origx;
         var top = (this.top - origy) * ratio + origy;
-
+        
         return new OpenLayers.Bounds(left, bottom, right, top);
     },
 
     /**
      * APIMethod: add
-     *
+     * 
      * Parameters:
      * x - {Float}
      * y - {Float}
-     *
+     * 
      * Returns:
      * {<OpenLayers.Bounds>} A new bounds whose coordinates are the same as
      *     this, but shifted by the passed-in x and y values.
@@ -3316,13 +3714,13 @@
         return new OpenLayers.Bounds(this.left + x, this.bottom + y,
                                      this.right + x, this.top + y);
     },
-
+    
     /**
      * APIMethod: extend
      * Extend the bounds to include the point, lonlat, or bounds specified.
      *     Note, this function assumes that left < right and bottom < top.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * object - {Object} Can be LonLat, Point, or Bounds
      */
     extend:function(object) {
@@ -3330,7 +3728,7 @@
         if (object) {
             // clear cached center location
             switch(object.CLASS_NAME) {
-                case "OpenLayers.LonLat":
+                case "OpenLayers.LonLat":    
                     bounds = new OpenLayers.Bounds(object.lon, object.lat,
                                                     object.lon, object.lat);
                     break;
@@ -3338,12 +3736,12 @@
                     bounds = new OpenLayers.Bounds(object.x, object.y,
                                                     object.x, object.y);
                     break;
-
-                case "OpenLayers.Bounds":
+                    
+                case "OpenLayers.Bounds":    
                     bounds = object;
                     break;
             }
-
+    
             if (bounds) {
                 this.centerLonLat = null;
                 if ( (this.left == null) || (bounds.left < this.left)) {
@@ -3351,11 +3749,11 @@
                 }
                 if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) {
                     this.bottom = bounds.bottom;
-                }
+                } 
                 if ( (this.right == null) || (bounds.right > this.right) ) {
                     this.right = bounds.right;
                 }
-                if ( (this.top == null) || (bounds.top > this.top) ) {
+                if ( (this.top == null) || (bounds.top > this.top) ) { 
                     this.top = bounds.top;
                 }
             }
@@ -3364,7 +3762,7 @@
 
     /**
      * APIMethod: containsLonLat
-     *
+     * 
      * Parameters:
      * ll - {<OpenLayers.LonLat>}
      * inclusive - {Boolean} Whether or not to include the border.
@@ -3379,7 +3777,7 @@
 
     /**
      * APIMethod: containsPixel
-     *
+     * 
      * Parameters:
      * px - {<OpenLayers.Pixel>}
      * inclusive - {Boolean} Whether or not to include the border. Default is
@@ -3391,10 +3789,10 @@
     containsPixel:function(px, inclusive) {
         return this.contains(px.x, px.y, inclusive);
     },
-
+    
     /**
      * APIMethod: contains
-     *
+     * 
      * Parameters:
      * x - {Float}
      * y - {Float}
@@ -3420,12 +3818,12 @@
 
         var contains = false;
         if (inclusive) {
-            contains = ((x >= this.left) && (x <= this.right) &&
+            contains = ((x >= this.left) && (x <= this.right) && 
                         (y >= this.bottom) && (y <= this.top));
         } else {
-            contains = ((x > this.left) && (x < this.right) &&
+            contains = ((x > this.left) && (x < this.right) && 
                         (y > this.bottom) && (y < this.top));
-        }
+        }              
         return contains;
     },
 
@@ -3434,7 +3832,7 @@
      * Determine whether the target bounds intersects this bounds.  Bounds are
      *     considered intersecting if any of their edges intersect or if one
      *     bounds contains the other.
-     *
+     * 
      * Parameters:
      * bounds - {<OpenLayers.Bounds>} The target bounds.
      * inclusive - {Boolean} Treat coincident borders as intersecting.  Default
@@ -3455,7 +3853,7 @@
             this.top == bounds.bottom ||
             this.bottom == bounds.top
         );
-
+        
         // if the two bounds only touch at an edge, and inclusive is false,
         // then the bounds don't *really* intersect.
         if (inclusive || !mightTouch) {
@@ -3481,20 +3879,20 @@
         }
         return intersects;
     },
-
+    
     /**
      * APIMethod: containsBounds
      * Determine whether the target bounds is contained within this bounds.
-     *
+     * 
      * bounds - {<OpenLayers.Bounds>} The target bounds.
      * partial - {Boolean} If any of the target corners is within this bounds
-     *     consider the bounds contained.  Default is false.  If true, the
+     *     consider the bounds contained.  Default is false.  If false, the
      *     entire target bounds must be contained within this bounds.
      * inclusive - {Boolean} Treat shared edges as contained.  Default is
      *     true.
      *
      * Returns:
-     * {Boolean} The passed-in bounds object is contained within this bounds.
+     * {Boolean} The passed-in bounds object is contained within this bounds. 
      */
     containsBounds:function(bounds, partial, inclusive) {
         if (partial == null) {
@@ -3507,39 +3905,39 @@
         var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive);
         var topLeft  = this.contains(bounds.left, bounds.top, inclusive);
         var topRight = this.contains(bounds.right, bounds.top, inclusive);
-
+        
         return (partial) ? (bottomLeft || bottomRight || topLeft || topRight)
                          : (bottomLeft && bottomRight && topLeft && topRight);
     },
 
-    /**
+    /** 
      * APIMethod: determineQuadrant
-     *
+     * 
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>}
-     *
+     * 
      * Returns:
      * {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the
      *     coordinate lies.
      */
     determineQuadrant: function(lonlat) {
-
+    
         var quadrant = "";
         var center = this.getCenterLonLat();
-
+        
         quadrant += (lonlat.lat < center.lat) ? "b" : "t";
         quadrant += (lonlat.lon < center.lon) ? "l" : "r";
-
-        return quadrant;
+    
+        return quadrant; 
     },
-
+    
     /**
      * APIMethod: transform
-     * Transform the Bounds object from source to dest.
+     * Transform the Bounds object from source to dest. 
      *
-     * Parameters:
-     * source - {<OpenLayers.Projection>} Source projection.
-     * dest   - {<OpenLayers.Projection>} Destination projection.
+     * Parameters: 
+     * source - {<OpenLayers.Projection>} Source projection. 
+     * dest   - {<OpenLayers.Projection>} Destination projection. 
      *
      * Returns:
      * {<OpenLayers.Bounds>} Itself, for use in chaining operations.
@@ -3564,68 +3962,68 @@
 
     /**
      * APIMethod: wrapDateLine
-     *
+     *  
      * Parameters:
      * maxExtent - {<OpenLayers.Bounds>}
      * options - {Object} Some possible options are:
-     *                    leftTolerance - {float} Allow for a margin of error
-     *                                            with the 'left' value of this
+     *                    leftTolerance - {float} Allow for a margin of error 
+     *                                            with the 'left' value of this 
      *                                            bound.
      *                                            Default is 0.
-     *                    rightTolerance - {float} Allow for a margin of error
-     *                                             with the 'right' value of
+     *                    rightTolerance - {float} Allow for a margin of error 
+     *                                             with the 'right' value of 
      *                                             this bound.
      *                                             Default is 0.
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the
-     *                       "dateline" (as specified by the borders of
-     *                       maxExtent). Note that this function only returns
-     *                       a different bounds value if this bounds is
-     *                       *entirely* outside of the maxExtent. If this
-     *                       bounds straddles the dateline (is part in/part
-     *                       out of maxExtent), the returned bounds will be
+     * {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the 
+     *                       "dateline" (as specified by the borders of 
+     *                       maxExtent). Note that this function only returns 
+     *                       a different bounds value if this bounds is 
+     *                       *entirely* outside of the maxExtent. If this 
+     *                       bounds straddles the dateline (is part in/part 
+     *                       out of maxExtent), the returned bounds will be 
      *                       merely a copy of this one.
      */
-    wrapDateLine: function(maxExtent, options) {
+    wrapDateLine: function(maxExtent, options) {    
         options = options || {};
-
+        
         var leftTolerance = options.leftTolerance || 0;
         var rightTolerance = options.rightTolerance || 0;
 
         var newBounds = this.clone();
-
+    
         if (maxExtent) {
 
            //shift right?
-           while ( newBounds.left < maxExtent.left &&
-                   (newBounds.right - rightTolerance) <= maxExtent.left ) {
+           while ( newBounds.left < maxExtent.left && 
+                   (newBounds.right - rightTolerance) <= maxExtent.left ) { 
                 newBounds = newBounds.add(maxExtent.getWidth(), 0);
            }
 
            //shift left?
-           while ( (newBounds.left + leftTolerance) >= maxExtent.right &&
-                   newBounds.right > maxExtent.right ) {
+           while ( (newBounds.left + leftTolerance) >= maxExtent.right && 
+                   newBounds.right > maxExtent.right ) { 
                 newBounds = newBounds.add(-maxExtent.getWidth(), 0);
            }
         }
-
+                
         return newBounds;
     },
 
     CLASS_NAME: "OpenLayers.Bounds"
 });
 
-/**
+/** 
  * APIFunction: fromString
- * Alternative constructor that builds a new OpenLayers.Bounds from a
+ * Alternative constructor that builds a new OpenLayers.Bounds from a 
  *     parameter string
- *
- * Parameters:
+ * 
+ * Parameters: 
  * str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
- *
+ * 
  * Returns:
- * {<OpenLayers.Bounds>} New bounds object built from the
+ * {<OpenLayers.Bounds>} New bounds object built from the 
  *                       passed-in String.
  */
 OpenLayers.Bounds.fromString = function(str) {
@@ -3633,11 +4031,11 @@
     return OpenLayers.Bounds.fromArray(bounds);
 };
 
-/**
+/** 
  * APIFunction: fromArray
  * Alternative constructor that builds a new OpenLayers.Bounds
  *     from an array
- *
+ * 
  * Parameters:
  * bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
  *
@@ -3651,13 +4049,13 @@
                                  parseFloat(bbox[3]));
 };
 
-/**
+/** 
  * APIFunction: fromSize
  * Alternative constructor that builds a new OpenLayers.Bounds
  *     from a size
- *
+ * 
  * Parameters:
- * size - {<OpenLayers.Size>}
+ * size - {<OpenLayers.Size>} 
  *
  * Returns:
  * {<OpenLayers.Bounds>} New bounds object built from the passed-in size.
@@ -3677,24 +4075,25 @@
  * quadrant - {String} two character quadrant shortstring
  *
  * Returns:
- * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if
- *          you pass in "bl" it returns "tr", if you pass in "br" it
+ * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if 
+ *          you pass in "bl" it returns "tr", if you pass in "br" it 
  *          returns "tl", etc.
  */
 OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
     var opp = "";
-
+    
     opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
     opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
-
+    
     return opp;
 };
 /* ======================================================================
     OpenLayers/BaseTypes/Element.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -3704,10 +4103,10 @@
 
     /**
      * APIFunction: visible
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * element - {DOMElement}
-     *
+     * 
      * Returns:
      * {Boolean} Is the element visible?
      */
@@ -3718,14 +4117,14 @@
     /**
      * APIFunction: toggle
      * Toggle the visibility of element(s) passed in
-     *
+     * 
      * Parameters:
      * element - {DOMElement} Actually user can pass any number of elements
      */
     toggle: function() {
         for (var i=0, len=arguments.length; i<len; i++) {
             var element = OpenLayers.Util.getElement(arguments[i]);
-            var display = OpenLayers.Element.visible(element) ? 'hide'
+            var display = OpenLayers.Element.visible(element) ? 'hide' 
                                                               : 'show';
             OpenLayers.Element[display](element);
         }
@@ -3735,35 +4134,39 @@
     /**
      * APIFunction: hide
      * Hide element(s) passed in
-     *
+     * 
      * Parameters:
      * element - {DOMElement} Actually user can pass any number of elements
      */
     hide: function() {
         for (var i=0, len=arguments.length; i<len; i++) {
             var element = OpenLayers.Util.getElement(arguments[i]);
-            element.style.display = 'none';
+            if (element) {
+                element.style.display = 'none';
+            }
         }
     },
 
     /**
      * APIFunction: show
      * Show element(s) passed in
-     *
+     * 
      * Parameters:
      * element - {DOMElement} Actually user can pass any number of elements
      */
     show: function() {
         for (var i=0, len=arguments.length; i<len; i++) {
             var element = OpenLayers.Util.getElement(arguments[i]);
-            element.style.display = '';
+            if (element) {
+                element.style.display = '';
+            }
         }
     },
 
     /**
      * APIFunction: remove
      * Remove the specified element from the DOM.
-     *
+     * 
      * Parameters:
      * element - {DOMElement}
      */
@@ -3774,10 +4177,10 @@
 
     /**
      * APIFunction: getHeight
-     *
+     *  
      * Parameters:
      * element - {DOMElement}
-     *
+     * 
      * Returns:
      * {Integer} The offset height of the element passed in
      */
@@ -3788,12 +4191,13 @@
 
     /**
      * APIFunction: getDimensions
-     *
+     * *Deprecated*. Returns dimensions of the element passed in.
+     *  
      * Parameters:
      * element - {DOMElement}
-     *
+     * 
      * Returns:
-     * {Object} Object with 'width' and 'height' properties which are the
+     * {Object} Object with 'width' and 'height' properties which are the 
      *          dimensions of the element passed in.
      */
     getDimensions: function(element) {
@@ -3801,18 +4205,19 @@
         if (OpenLayers.Element.getStyle(element, 'display') != 'none') {
             return {width: element.offsetWidth, height: element.offsetHeight};
         }
-
+    
         // All *Width and *Height properties give 0 on elements with display none,
         // so enable the element temporarily
         var els = element.style;
         var originalVisibility = els.visibility;
         var originalPosition = els.position;
+        var originalDisplay = els.display;
         els.visibility = 'hidden';
         els.position = 'absolute';
         els.display = '';
         var originalWidth = element.clientWidth;
         var originalHeight = element.clientHeight;
-        els.display = 'none';
+        els.display = originalDisplay;
         els.position = originalPosition;
         els.visibility = originalVisibility;
         return {width: originalWidth, height: originalHeight};
@@ -3833,7 +4238,7 @@
         var names = element.className;
         return (!!names && new RegExp("(^|\\s)" + name + "(\\s|$)").test(names));
     },
-
+    
     /**
      * Function: addClass
      * Add a CSS class name to an element.  Safe where element already has
@@ -3900,11 +4305,11 @@
 
     /**
      * APIFunction: getStyle
-     *
+     * 
      * Parameters:
      * element - {DOMElement}
      * style - {?}
-     *
+     * 
      * Returns:
      * {?}
      */
@@ -3915,24 +4320,24 @@
         if (element && element.style) {
             value = element.style[OpenLayers.String.camelize(style)];
             if (!value) {
-                if (document.defaultView &&
+                if (document.defaultView && 
                     document.defaultView.getComputedStyle) {
-
+                    
                     var css = document.defaultView.getComputedStyle(element, null);
                     value = css ? css.getPropertyValue(style) : null;
                 } else if (element.currentStyle) {
                     value = element.currentStyle[OpenLayers.String.camelize(style)];
                 }
             }
-
+        
             var positions = ['left', 'top', 'right', 'bottom'];
             if (window.opera &&
                 (OpenLayers.Util.indexOf(positions,style) != -1) &&
-                (OpenLayers.Element.getStyle(element, 'position') == 'static')) {
+                (OpenLayers.Element.getStyle(element, 'position') == 'static')) { 
                 value = 'auto';
             }
         }
-
+    
         return value == 'auto' ? null : value;
     }
 
@@ -3941,8 +4346,9 @@
     OpenLayers/BaseTypes/LonLat.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -3955,13 +4361,13 @@
  */
 OpenLayers.LonLat = OpenLayers.Class({
 
-    /**
+    /** 
      * APIProperty: lon
      * {Float} The x-axis coodinate in map units
      */
     lon: 0.0,
-
-    /**
+    
+    /** 
      * APIProperty: lat
      * {Float} The y-axis coordinate in map units
      */
@@ -3983,51 +4389,51 @@
         this.lon = OpenLayers.Util.toFloat(lon);
         this.lat = OpenLayers.Util.toFloat(lat);
     },
-
+    
     /**
      * Method: toString
      * Return a readable string version of the lonlat
      *
      * Returns:
-     * {String} String representation of OpenLayers.LonLat object.
+     * {String} String representation of OpenLayers.LonLat object. 
      *           (ex. <i>"lon=5,lat=42"</i>)
      */
     toString:function() {
         return ("lon=" + this.lon + ",lat=" + this.lat);
     },
 
-    /**
+    /** 
      * APIMethod: toShortString
-     *
+     * 
      * Returns:
-     * {String} Shortened String representation of OpenLayers.LonLat object.
+     * {String} Shortened String representation of OpenLayers.LonLat object. 
      *         (ex. <i>"5, 42"</i>)
      */
     toShortString:function() {
         return (this.lon + ", " + this.lat);
     },
 
-    /**
+    /** 
      * APIMethod: clone
-     *
+     * 
      * Returns:
-     * {<OpenLayers.LonLat>} New OpenLayers.LonLat object with the same lon
+     * {<OpenLayers.LonLat>} New OpenLayers.LonLat object with the same lon 
      *                       and lat values
      */
     clone:function() {
         return new OpenLayers.LonLat(this.lon, this.lat);
     },
 
-    /**
+    /** 
      * APIMethod: add
-     *
+     * 
      * Parameters:
      * lon - {Float}
      * lat - {Float}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.LonLat>} A new OpenLayers.LonLat object with the lon and
-     *                       lat passed-in added to this's.
+     * {<OpenLayers.LonLat>} A new OpenLayers.LonLat object with the lon and 
+     *                       lat passed-in added to this's. 
      */
     add:function(lon, lat) {
         if ( (lon == null) || (lat == null) ) {
@@ -4035,18 +4441,19 @@
             OpenLayers.Console.error(msg);
             return null;
         }
-        return new OpenLayers.LonLat(this.lon + lon, this.lat + lat);
+        return new OpenLayers.LonLat(this.lon + OpenLayers.Util.toFloat(lon), 
+                                     this.lat + OpenLayers.Util.toFloat(lat));
     },
 
-    /**
+    /** 
      * APIMethod: equals
-     *
+     * 
      * Parameters:
      * ll - {<OpenLayers.LonLat>}
-     *
+     * 
      * Returns:
-     * {Boolean} Boolean value indicating whether the passed-in
-     *           <OpenLayers.LonLat> object has the same lon and lat
+     * {Boolean} Boolean value indicating whether the passed-in 
+     *           <OpenLayers.LonLat> object has the same lon and lat 
      *           components as this.
      *           Note: if ll passed in is null, returns false
      */
@@ -4064,9 +4471,9 @@
      * Transform the LonLat object from source to dest. This transformation is
      *    *in place*: if you want a *new* lonlat, use .clone() first.
      *
-     * Parameters:
-     * source - {<OpenLayers.Projection>} Source projection.
-     * dest   - {<OpenLayers.Projection>} Destination projection.
+     * Parameters: 
+     * source - {<OpenLayers.Projection>} Source projection. 
+     * dest   - {<OpenLayers.Projection>} Destination projection. 
      *
      * Returns:
      * {<OpenLayers.LonLat>} Itself, for use in chaining operations.
@@ -4078,64 +4485,64 @@
         this.lat = point.y;
         return this;
     },
-
+    
     /**
      * APIMethod: wrapDateLine
-     *
+     * 
      * Parameters:
      * maxExtent - {<OpenLayers.Bounds>}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.LonLat>} A copy of this lonlat, but wrapped around the
-     *                       "dateline" (as specified by the borders of
+     * {<OpenLayers.LonLat>} A copy of this lonlat, but wrapped around the 
+     *                       "dateline" (as specified by the borders of 
      *                       maxExtent)
      */
-    wrapDateLine: function(maxExtent) {
+    wrapDateLine: function(maxExtent) {    
 
         var newLonLat = this.clone();
-
+    
         if (maxExtent) {
             //shift right?
             while (newLonLat.lon < maxExtent.left) {
                 newLonLat.lon +=  maxExtent.getWidth();
-            }
-
+            }    
+           
             //shift left?
             while (newLonLat.lon > maxExtent.right) {
                 newLonLat.lon -= maxExtent.getWidth();
-            }
+            }    
         }
-
+                
         return newLonLat;
     },
 
     CLASS_NAME: "OpenLayers.LonLat"
 });
 
-/**
+/** 
  * Function: fromString
- * Alternative constructor that builds a new <OpenLayers.LonLat> from a
+ * Alternative constructor that builds a new <OpenLayers.LonLat> from a 
  *     parameter string
- *
+ * 
  * Parameters:
- * str - {String} Comma-separated Lon,Lat coordinate string.
+ * str - {String} Comma-separated Lon,Lat coordinate string. 
  *                 (ex. <i>"5,40"</i>)
- *
+ * 
  * Returns:
- * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the
+ * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the 
  *                       passed-in String.
  */
 OpenLayers.LonLat.fromString = function(str) {
     var pair = str.split(",");
-    return new OpenLayers.LonLat(parseFloat(pair[0]),
-                                 parseFloat(pair[1]));
+    return new OpenLayers.LonLat(pair[0], pair[1]);
 };
 /* ======================================================================
     OpenLayers/BaseTypes/Pixel.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -4147,7 +4554,7 @@
  * This class represents a screen coordinate, in x and y coordinates
  */
 OpenLayers.Pixel = OpenLayers.Class({
-
+    
     /**
      * APIProperty: x
      * {Number} The x coordinate
@@ -4159,7 +4566,7 @@
      * {Number} The y coordinate
      */
     y: 0.0,
-
+    
     /**
      * Constructor: OpenLayers.Pixel
      * Create a new OpenLayers.Pixel instance
@@ -4175,7 +4582,7 @@
         this.x = parseFloat(x);
         this.y = parseFloat(y);
     },
-
+    
     /**
      * Method: toString
      * Cast this object into a string
@@ -4195,9 +4602,9 @@
      * {<OpenLayers.Pixel>} A clone pixel
      */
     clone:function() {
-        return new OpenLayers.Pixel(this.x, this.y);
+        return new OpenLayers.Pixel(this.x, this.y); 
     },
-
+    
     /**
      * APIMethod: equals
      * Determine whether one pixel is equivalent to another
@@ -4226,7 +4633,7 @@
      * y - {Integer}
      *
      * Returns:
-     * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
+     * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
      * values passed in.
      */
     add:function(x, y) {
@@ -4240,12 +4647,12 @@
 
     /**
     * APIMethod: offset
-    *
+    * 
     * Parameters
     * px - {<OpenLayers.Pixel>}
-    *
+    * 
     * Returns:
-    * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
+    * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
     *                      x&y values of the pixel passed in.
     */
     offset:function(px) {
@@ -4262,69 +4669,69 @@
     OpenLayers/Icon.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
-
 /**
  * Class: OpenLayers.Icon
- *
+ * 
  * The icon represents a graphical icon on the screen.  Typically used in
  * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
  *
- * An icon has a url, size and position.  It also contains an offset which
+ * An icon has a url, size and position.  It also contains an offset which 
  * allows the center point to be represented correctly.  This can be
  * provided either as a fixed offset or a function provided to calculate
- * the desired offset.
- *
+ * the desired offset. 
+ * 
  */
 OpenLayers.Icon = OpenLayers.Class({
-
-    /**
-     * Property: url
+    
+    /** 
+     * Property: url 
      * {String}  image url
      */
     url: null,
-
-    /**
-     * Property: size
-     * {<OpenLayers.Size>}
+    
+    /** 
+     * Property: size 
+     * {<OpenLayers.Size>} 
      */
     size: null,
 
-    /**
-     * Property: offset
+    /** 
+     * Property: offset 
      * {<OpenLayers.Pixel>} distance in pixels to offset the image when being rendered
      */
-    offset: null,
-
-    /**
-     * Property: calculateOffset
-     * {<OpenLayers.Pixel>} Function to calculate the offset (based on the size)
+    offset: null,    
+    
+    /** 
+     * Property: calculateOffset 
+     * {<OpenLayers.Pixel>} Function to calculate the offset (based on the size) 
      */
-    calculateOffset: null,
-
-    /**
-     * Property: imageDiv
-     * {DOMElement}
+    calculateOffset: null,    
+    
+    /** 
+     * Property: imageDiv 
+     * {DOMElement} 
      */
     imageDiv: null,
 
-    /**
-     * Property: px
-     * {<OpenLayers.Pixel>}
+    /** 
+     * Property: px 
+     * {<OpenLayers.Pixel>} 
      */
     px: null,
-
-    /**
+    
+    /** 
      * Constructor: OpenLayers.Icon
-     * Creates an icon, which is an image tag in a div.
+     * Creates an icon, which is an image tag in a div.  
      *
-     * url - {String}
-     * size - {<OpenLayers.Size>}
+     * url - {String} 
+     * size - {<OpenLayers.Size>} 
      * offset - {<OpenLayers.Pixel>}
-     * calculateOffset - {Function}
+     * calculateOffset - {Function} 
      */
     initialize: function(url, size, offset, calculateOffset) {
         this.url = url;
@@ -4335,39 +4742,39 @@
         var id = OpenLayers.Util.createUniqueID("OL_Icon_");
         this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
     },
-
-    /**
+    
+    /** 
      * Method: destroy
-     * Nullify references and remove event listeners to prevent circular
+     * Nullify references and remove event listeners to prevent circular 
      * references and memory leaks
      */
     destroy: function() {
         // erase any drawn elements
         this.erase();
 
-        OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
+        OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); 
         this.imageDiv.innerHTML = "";
         this.imageDiv = null;
     },
 
-    /**
+    /** 
      * Method: clone
-     *
+     * 
      * Returns:
      * {<OpenLayers.Icon>} A fresh copy of the icon.
      */
     clone: function() {
-        return new OpenLayers.Icon(this.url,
-                                   this.size,
-                                   this.offset,
+        return new OpenLayers.Icon(this.url, 
+                                   this.size, 
+                                   this.offset, 
                                    this.calculateOffset);
     },
-
+    
     /**
      * Method: setSize
-     *
+     * 
      * Parameters:
-     * size - {<OpenLayers.Size>}
+     * size - {<OpenLayers.Size>} 
      */
     setSize: function(size) {
         if (size != null) {
@@ -4375,12 +4782,12 @@
         }
         this.draw();
     },
-
+    
     /**
      * Method: setUrl
-     *
+     * 
      * Parameters:
-     * url - {String}
+     * url - {String} 
      */
     setUrl: function(url) {
         if (url != null) {
@@ -4389,28 +4796,28 @@
         this.draw();
     },
 
-    /**
+    /** 
      * Method: draw
      * Move the div to the given pixel.
-     *
+     * 
      * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     *
+     * px - {<OpenLayers.Pixel>} 
+     * 
      * Returns:
      * {DOMElement} A new DOM Image of this icon set at the location passed-in
      */
     draw: function(px) {
-        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,
-                                            null,
-                                            null,
-                                            this.size,
-                                            this.url,
+        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, 
+                                            null, 
+                                            null, 
+                                            this.size, 
+                                            this.url, 
                                             "absolute");
         this.moveTo(px);
         return this.imageDiv;
-    },
+    }, 
 
-    /**
+    /** 
      * Method: erase
      * Erase the underlying image element.
      *
@@ -4419,27 +4826,27 @@
         if (this.imageDiv != null && this.imageDiv.parentNode != null) {
             OpenLayers.Element.remove(this.imageDiv);
         }
-    },
-
-    /**
+    }, 
+    
+    /** 
      * Method: setOpacity
      * Change the icon's opacity
      *
      * Parameters:
-     * opacity - {float}
+     * opacity - {float} 
      */
     setOpacity: function(opacity) {
-        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,
+        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, 
                                             null, null, null, null, opacity);
 
     },
-
+    
     /**
      * Method: moveTo
      * move icon to passed in px.
      *
      * Parameters:
-     * px - {<OpenLayers.Pixel>}
+     * px - {<OpenLayers.Pixel>} 
      */
     moveTo: function (px) {
         //if no px passed in, use stored location
@@ -4452,39 +4859,39 @@
                 this.display(false);
             } else {
                 if (this.calculateOffset) {
-                    this.offset = this.calculateOffset(this.size);
+                    this.offset = this.calculateOffset(this.size);  
                 }
                 var offsetPx = this.px.offset(this.offset);
                 OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
             }
         }
     },
-
-    /**
+    
+    /** 
      * Method: display
      * Hide or show the icon
      *
      * Parameters:
-     * display - {Boolean}
+     * display - {Boolean} 
      */
     display: function(display) {
-        this.imageDiv.style.display = (display) ? "" : "none";
+        this.imageDiv.style.display = (display) ? "" : "none"; 
     },
+    
 
-
     /**
      * APIMethod: isDrawn
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the icon is drawn.
      */
     isDrawn: function() {
         // nodeType 11 for ie, whose nodes *always* have a parentNode
         // (of type document fragment)
-        var isDrawn = (this.imageDiv && this.imageDiv.parentNode &&
-                       (this.imageDiv.parentNode.nodeType != 11));
+        var isDrawn = (this.imageDiv && this.imageDiv.parentNode && 
+                       (this.imageDiv.parentNode.nodeType != 11));    
 
-        return isDrawn;
+        return isDrawn;   
     },
 
     CLASS_NAME: "OpenLayers.Icon"
@@ -4493,112 +4900,113 @@
     OpenLayers/Popup.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
 /**
  * Class: OpenLayers.Popup
  * A popup is a small div that can opened and closed on the map.
- * Typically opened in response to clicking on a marker.
+ * Typically opened in response to clicking on a marker.  
  * See <OpenLayers.Marker>.  Popup's don't require their own
  * layer and are added the the map using the <OpenLayers.Map.addPopup>
  * method.
  *
  * Example:
  * (code)
- * popup = new OpenLayers.Popup("chicken",
+ * popup = new OpenLayers.Popup("chicken", 
  *                    new OpenLayers.LonLat(5,40),
  *                    new OpenLayers.Size(200,200),
  *                    "example popup",
  *                    true);
- *
+ *       
  * map.addPopup(popup);
  * (end)
  */
 OpenLayers.Popup = OpenLayers.Class({
 
-    /**
-     * Property: events
-     * {<OpenLayers.Events>} custom event manager
+    /** 
+     * Property: events  
+     * {<OpenLayers.Events>} custom event manager 
      */
     events: null,
-
+    
     /** Property: id
      * {String} the unique identifier assigned to this popup.
      */
     id: "",
 
-    /**
-     * Property: lonlat
+    /** 
+     * Property: lonlat 
      * {<OpenLayers.LonLat>} the position of this popup on the map
      */
     lonlat: null,
 
-    /**
-     * Property: div
+    /** 
+     * Property: div 
      * {DOMElement} the div that contains this popup.
      */
     div: null,
 
-    /**
-     * Property: contentSize
+    /** 
+     * Property: contentSize 
      * {<OpenLayers.Size>} the width and height of the content.
      */
-    contentSize: null,
+    contentSize: null,    
 
-    /**
-     * Property: size
+    /** 
+     * Property: size 
      * {<OpenLayers.Size>} the width and height of the popup.
      */
-    size: null,
+    size: null,    
 
-    /**
-     * Property: contentHTML
+    /** 
+     * Property: contentHTML 
      * {String} An HTML string for this popup to display.
      */
     contentHTML: null,
-
-    /**
-     * Property: backgroundColor
+    
+    /** 
+     * Property: backgroundColor 
      * {String} the background color used by the popup.
      */
     backgroundColor: "",
-
-    /**
-     * Property: opacity
+    
+    /** 
+     * Property: opacity 
      * {float} the opacity of this popup (between 0.0 and 1.0)
      */
     opacity: "",
 
-    /**
-     * Property: border
+    /** 
+     * Property: border 
      * {String} the border size of the popup.  (eg 2px)
      */
     border: "",
-
-    /**
-     * Property: contentDiv
+    
+    /** 
+     * Property: contentDiv 
      * {DOMElement} a reference to the element that holds the content of
      *              the div.
      */
     contentDiv: null,
-
-    /**
-     * Property: groupDiv
+    
+    /** 
+     * Property: groupDiv 
      * {DOMElement} First and only child of 'div'. The group Div contains the
      *     'contentDiv' and the 'closeDiv'.
      */
     groupDiv: null,
 
-    /**
+    /** 
      * Property: closeDiv
      * {DOMElement} the optional closer image
      */
     closeDiv: null,
 
-    /**
+    /** 
      * APIProperty: autoSize
      * {Boolean} Resize the popup to auto-fit the contents.
      *     Default is false.
@@ -4617,40 +5025,40 @@
      */
     maxSize: null,
 
-    /**
+    /** 
      * Property: displayClass
      * {String} The CSS class of the popup.
      */
     displayClass: "olPopup",
 
-    /**
+    /** 
      * Property: contentDisplayClass
      * {String} The CSS class of the popup content div.
      */
     contentDisplayClass: "olPopupContent",
 
-    /**
-     * Property: padding
-     * {int or <OpenLayers.Bounds>} An extra opportunity to specify internal
+    /** 
+     * Property: padding 
+     * {int or <OpenLayers.Bounds>} An extra opportunity to specify internal 
      *     padding of the content div inside the popup. This was originally
-     *     confused with the css padding as specified in style.css's
+     *     confused with the css padding as specified in style.css's 
      *     'olPopupContent' class. We would like to get rid of this altogether,
      *     except that it does come in handy for the framed and anchoredbubble
-     *     popups, who need to maintain yet another barrier between their
-     *     content and the outer border of the popup itself.
-     *
-     *     Note that in order to not break API, we must continue to support
-     *     this property being set as an integer. Really, though, we'd like to
+     *     popups, who need to maintain yet another barrier between their 
+     *     content and the outer border of the popup itself. 
+     * 
+     *     Note that in order to not break API, we must continue to support 
+     *     this property being set as an integer. Really, though, we'd like to 
      *     have this specified as a Bounds object so that user can specify
      *     distinct left, top, right, bottom paddings. With the 3.0 release
      *     we can make this only a bounds.
      */
     padding: 0,
 
-    /**
+    /** 
      * Property: disableFirefoxOverflowHack
-     * {Boolean} The hack for overflow in Firefox causes all elements
-     *     to be re-drawn, which causes Flash elements to be
+     * {Boolean} The hack for overflow in Firefox causes all elements 
+     *     to be re-drawn, which causes Flash elements to be 
      *     re-initialized, which is troublesome.
      *     With this property the hack can be disabled.
      */
@@ -4658,8 +5066,8 @@
 
     /**
      * Method: fixPadding
-     * To be removed in 3.0, this function merely helps us to deal with the
-     *     case where the user may have set an integer value for padding,
+     * To be removed in 3.0, this function merely helps us to deal with the 
+     *     case where the user may have set an integer value for padding, 
      *     instead of an <OpenLayers.Bounds> object.
      */
     fixPadding: function() {
@@ -4677,17 +5085,17 @@
      *     Default is false.
      */
     panMapIfOutOfView: false,
-
+    
     /**
-     * APIProperty: keepInMap
-     * {Boolean} If panMapIfOutOfView is false, and this property is true,
+     * APIProperty: keepInMap 
+     * {Boolean} If panMapIfOutOfView is false, and this property is true, 
      *     contrain the popup such that it always fits in the available map
      *     space. By default, this is not set on the base class. If you are
      *     creating popups that are near map edges and not allowing pannning,
      *     and especially if you have a popup which has a
      *     fixedRelativePosition, setting this to false may be a smart thing to
      *     do. Subclasses may want to override this setting.
-     *
+     *   
      *     Default is false.
      */
     keepInMap: false,
@@ -4698,24 +5106,24 @@
      *     Default is false.
      */
     closeOnMove: false,
-
-    /**
-     * Property: map
+    
+    /** 
+     * Property: map 
      * {<OpenLayers.Map>} this gets set in Map.js when the popup is added to the map
      */
     map: null,
 
-    /**
+    /** 
     * Constructor: OpenLayers.Popup
     * Create a popup.
-    *
-    * Parameters:
+    * 
+    * Parameters: 
     * id - {String} a unqiue identifier for this popup.  If null is passed
-    *               an identifier will be automatically generated.
+    *               an identifier will be automatically generated. 
     * lonlat - {<OpenLayers.LonLat>}  The position on the map the popup will
     *                                 be shown.
     * contentSize - {<OpenLayers.Size>} The size of the content.
-    * contentHTML - {String}          An HTML string to display inside the
+    * contentHTML - {String}          An HTML string to display inside the   
     *                                 popup.
     * closeBox - {Boolean}            Whether to display a close box inside
     *                                 the popup.
@@ -4729,28 +5137,28 @@
         this.id = id;
         this.lonlat = lonlat;
 
-        this.contentSize = (contentSize != null) ? contentSize
+        this.contentSize = (contentSize != null) ? contentSize 
                                   : new OpenLayers.Size(
                                                    OpenLayers.Popup.WIDTH,
                                                    OpenLayers.Popup.HEIGHT);
-        if (contentHTML != null) {
+        if (contentHTML != null) { 
              this.contentHTML = contentHTML;
         }
         this.backgroundColor = OpenLayers.Popup.COLOR;
         this.opacity = OpenLayers.Popup.OPACITY;
         this.border = OpenLayers.Popup.BORDER;
 
-        this.div = OpenLayers.Util.createDiv(this.id, null, null,
+        this.div = OpenLayers.Util.createDiv(this.id, null, null, 
                                              null, null, null, "hidden");
         this.div.className = this.displayClass;
-
+        
         var groupDivId = this.id + "_GroupDiv";
-        this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null,
+        this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null, 
                                                     null, "relative", null,
                                                     "hidden");
 
         var id = this.div.id + "_contentDiv";
-        this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(),
+        this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(), 
                                                     null, "relative");
         this.contentDiv.className = this.contentDisplayClass;
         this.groupDiv.appendChild(this.contentDiv);
@@ -4758,12 +5166,12 @@
 
         if (closeBox) {
             this.addCloseBox(closeBoxCallback);
-        }
+        } 
 
         this.registerEvents();
     },
 
-    /**
+    /** 
      * Method: destroy
      * nullify references to prevent circular references and memory leaks
      */
@@ -4773,24 +5181,24 @@
         this.lonlat = null;
         this.size = null;
         this.contentHTML = null;
-
+        
         this.backgroundColor = null;
         this.opacity = null;
         this.border = null;
-
+        
         if (this.closeOnMove && this.map) {
             this.map.events.unregister("movestart", this, this.hide);
         }
 
         this.events.destroy();
         this.events = null;
-
+        
         if (this.closeDiv) {
-            OpenLayers.Event.stopObservingElement(this.closeDiv);
+            OpenLayers.Event.stopObservingElement(this.closeDiv); 
             this.groupDiv.removeChild(this.closeDiv);
         }
         this.closeDiv = null;
-
+        
         this.div.removeChild(this.groupDiv);
         this.groupDiv = null;
 
@@ -4799,7 +5207,7 @@
         }
         this.map = null;
         this.div = null;
-
+        
         this.autoSize = null;
         this.minSize = null;
         this.maxSize = null;
@@ -4807,13 +5215,13 @@
         this.panMapIfOutOfView = null;
     },
 
-    /**
+    /** 
     * Method: draw
     * Constructs the elements that make up the popup.
     *
     * Parameters:
     * px - {<OpenLayers.Pixel>} the position the popup in pixels.
-    *
+    * 
     * Returns:
     * {DOMElement} Reference to a div that contains the drawn popup
     */
@@ -4824,12 +5232,12 @@
             }
         }
 
-        // this assumes that this.map already exists, which is okay because
+        // this assumes that this.map already exists, which is okay because 
         // this.draw is only called once the popup has been added to the map.
         if (this.closeOnMove) {
             this.map.events.register("movestart", this, this.hide);
         }
-
+        
         //listen to movestart, moveend to disable overflow (FF bug)
         if (!this.disableFirefoxOverflowHack && OpenLayers.Util.getBrowserName() == 'firefox') {
             this.map.events.register("movestart", this, function() {
@@ -4859,33 +5267,33 @@
         this.setOpacity();
         this.setBorder();
         this.setContentHTML();
-
+        
         if (this.panMapIfOutOfView) {
             this.panIntoView();
-        }
+        }    
 
         return this.div;
     },
 
-    /**
+    /** 
      * Method: updatePosition
-     * if the popup has a lonlat and its map members set,
+     * if the popup has a lonlat and its map members set, 
      * then have it move itself to its proper position
      */
     updatePosition: function() {
         if ((this.lonlat) && (this.map)) {
             var px = this.map.getLayerPxFromLonLat(this.lonlat);
             if (px) {
-                this.moveTo(px);
-            }
+                this.moveTo(px);           
+            }    
         }
     },
 
     /**
      * Method: moveTo
-     *
+     * 
      * Parameters:
-     * px - {<OpenLayers.Pixel>} the top and left position of the popup div.
+     * px - {<OpenLayers.Pixel>} the top and left position of the popup div. 
      */
     moveTo: function(px) {
         if ((px != null) && (this.div != null)) {
@@ -4897,7 +5305,7 @@
     /**
      * Method: visible
      *
-     * Returns:
+     * Returns:      
      * {Boolean} Boolean indicating whether or not the popup is visible
      */
     visible: function() {
@@ -4925,7 +5333,7 @@
 
         if (this.panMapIfOutOfView) {
             this.panIntoView();
-        }
+        }    
     },
 
     /**
@@ -4938,17 +5346,17 @@
 
     /**
      * Method: setSize
-     * Used to adjust the size of the popup.
+     * Used to adjust the size of the popup. 
      *
      * Parameters:
-     * contentSize - {<OpenLayers.Size>} the new size for the popup's
+     * contentSize - {<OpenLayers.Size>} the new size for the popup's 
      *     contents div (in pixels).
      */
-    setSize:function(contentSize) {
-        this.size = contentSize.clone();
-
-        // if our contentDiv has a css 'padding' set on it by a stylesheet, we
-        //  must add that to the desired "size".
+    setSize:function(contentSize) { 
+        this.size = contentSize.clone(); 
+        
+        // if our contentDiv has a css 'padding' set on it by a stylesheet, we 
+        //  must add that to the desired "size". 
         var contentDivPadding = this.getContentDivPadding();
         var wPadding = contentDivPadding.left + contentDivPadding.right;
         var hPadding = contentDivPadding.top + contentDivPadding.bottom;
@@ -4964,18 +5372,18 @@
             wPadding += closeDivWidth + contentDivPadding.right;
         }
 
-        //increase size of the main popup div to take into account the
-        // users's desired padding and close div.
+        //increase size of the main popup div to take into account the 
+        // users's desired padding and close div.        
         this.size.w += wPadding;
         this.size.h += hPadding;
 
-        //now if our browser is IE, we need to actually make the contents
-        // div itself bigger to take its own padding into effect. this makes
+        //now if our browser is IE, we need to actually make the contents 
+        // div itself bigger to take its own padding into effect. this makes 
         // me want to shoot someone, but so it goes.
         if (OpenLayers.Util.getBrowserName() == "msie") {
-            this.contentSize.w +=
+            this.contentSize.w += 
                 contentDivPadding.left + contentDivPadding.right;
-            this.contentSize.h +=
+            this.contentSize.h += 
                 contentDivPadding.bottom + contentDivPadding.top;
         }
 
@@ -4987,26 +5395,26 @@
             this.contentDiv.style.width = contentSize.w + "px";
             this.contentDiv.style.height = contentSize.h + "px";
         }
-    },
+    },  
 
     /**
      * APIMethod: updateSize
-     * Auto size the popup so that it precisely fits its contents (as
+     * Auto size the popup so that it precisely fits its contents (as 
      *     determined by this.contentDiv.innerHTML). Popup size will, of
      *     course, be limited by the available space on the current map
      */
     updateSize: function() {
-
+        
         // determine actual render dimensions of the contents by putting its
         // contents into a fake contentDiv (for the CSS) and then measuring it
-        var preparedHTML = "<div class='" + this.contentDisplayClass+ "'>" +
-            this.contentDiv.innerHTML +
+        var preparedHTML = "<div class='" + this.contentDisplayClass+ "'>" + 
+            this.contentDiv.innerHTML + 
             "</div>";
-
+ 
         var containerElement = (this.map) ? this.map.layerContainerDiv
-                                          : document.body;
+        								  : document.body;
         var realSize = OpenLayers.Util.getRenderedDimensions(
-            preparedHTML, null, {
+            preparedHTML, null,	{
                 displayClass: this.displayClass,
                 containerElement: containerElement
             }
@@ -5017,25 +5425,25 @@
 
         var newSize = null;
         if (safeSize.equals(realSize)) {
-            //real size of content is small enough to fit on the map,
+            //real size of content is small enough to fit on the map, 
             // so we use real size.
             newSize = realSize;
 
         } else {
 
-            //make a new OL.Size object with the clipped dimensions
+            //make a new OL.Size object with the clipped dimensions 
             // set or null if not clipped.
             var fixedSize = new OpenLayers.Size();
             fixedSize.w = (safeSize.w < realSize.w) ? safeSize.w : null;
             fixedSize.h = (safeSize.h < realSize.h) ? safeSize.h : null;
-
+        
             if (fixedSize.w && fixedSize.h) {
-                //content is too big in both directions, so we will use
-                // max popup size (safeSize), knowing well that it will
-                // overflow both ways.
+                //content is too big in both directions, so we will use 
+                // max popup size (safeSize), knowing well that it will 
+                // overflow both ways.                
                 newSize = safeSize;
             } else {
-                //content is clipped in only one direction, so we need to
+                //content is clipped in only one direction, so we need to 
                 // run getRenderedDimensions() again with a fixed dimension
                 var clippedSize = OpenLayers.Util.getRenderedDimensions(
                     preparedHTML, fixedSize, {
@@ -5043,17 +5451,17 @@
                         containerElement: containerElement
                     }
                 );
-
-                //if the clipped size is still the same as the safeSize,
-                // that means that our content must be fixed in the
-                // offending direction. If overflow is 'auto', this means
-                // we are going to have a scrollbar for sure, so we must
+                
+                //if the clipped size is still the same as the safeSize, 
+                // that means that our content must be fixed in the 
+                // offending direction. If overflow is 'auto', this means 
+                // we are going to have a scrollbar for sure, so we must 
                 // adjust for that.
                 //
                 var currentOverflow = OpenLayers.Element.getStyle(
                     this.contentDiv, "overflow"
                 );
-                if ( (currentOverflow != "hidden") &&
+                if ( (currentOverflow != "hidden") && 
                      (clippedSize.equals(safeSize)) ) {
                     var scrollBar = OpenLayers.Util.getScrollbarWidth();
                     if (fixedSize.w) {
@@ -5062,12 +5470,12 @@
                         clippedSize.w += scrollBar;
                     }
                 }
-
+                
                 newSize = this.getSafeContentSize(clippedSize);
             }
-        }
-        this.setSize(newSize);
-    },
+        }                        
+        this.setSize(newSize);     
+    },    
 
     /**
      * Method: setBackgroundColor
@@ -5076,28 +5484,28 @@
      * Parameters:
      * color - {String} the background color.  eg "#FFBBBB"
      */
-    setBackgroundColor:function(color) {
+    setBackgroundColor:function(color) { 
         if (color != undefined) {
-            this.backgroundColor = color;
+            this.backgroundColor = color; 
         }
-
+        
         if (this.div != null) {
             this.div.style.backgroundColor = this.backgroundColor;
         }
-    },
-
+    },  
+    
     /**
      * Method: setOpacity
      * Sets the opacity of the popup.
-     *
+     * 
      * Parameters:
-     * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid).
+     * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid).   
      */
-    setOpacity:function(opacity) {
+    setOpacity:function(opacity) { 
         if (opacity != undefined) {
-            this.opacity = opacity;
+            this.opacity = opacity; 
         }
-
+        
         if (this.div != null) {
             // for Mozilla and Safari
             this.div.style.opacity = this.opacity;
@@ -5105,25 +5513,25 @@
             // for IE
             this.div.style.filter = 'alpha(opacity=' + this.opacity*100 + ')';
         }
-    },
-
+    },  
+    
     /**
      * Method: setBorder
      * Sets the border style of the popup.
      *
      * Parameters:
-     * border - {String} The border style value. eg 2px
+     * border - {String} The border style value. eg 2px 
      */
-    setBorder:function(border) {
+    setBorder:function(border) { 
         if (border != undefined) {
             this.border = border;
         }
-
+        
         if (this.div != null) {
             this.div.style.border = this.border;
         }
-    },
-
+    },      
+    
     /**
      * Method: setContentHTML
      * Allows the user to set the HTML content of the popup.
@@ -5136,15 +5544,15 @@
         if (contentHTML != null) {
             this.contentHTML = contentHTML;
         }
-
-        if ((this.contentDiv != null) &&
+       
+        if ((this.contentDiv != null) && 
             (this.contentHTML != null) &&
             (this.contentHTML != this.contentDiv.innerHTML)) {
-
+       
             this.contentDiv.innerHTML = this.contentHTML;
-
+       
             if (this.autoSize) {
-
+                
                 //if popup has images, listen for when they finish
                 // loading and resize accordingly
                 this.registerImageListeners();
@@ -5152,31 +5560,31 @@
                 //auto size the popup to its current contents
                 this.updateSize();
             }
-        }
+        }    
 
     },
-
+    
     /**
      * Method: registerImageListeners
      * Called when an image contained by the popup loaded. this function
      *     updates the popup size, then unregisters the image load listener.
-     */
-    registerImageListeners: function() {
+     */   
+    registerImageListeners: function() { 
 
-        // As the images load, this function will call updateSize() to
+        // As the images load, this function will call updateSize() to 
         // resize the popup to fit the content div (which presumably is now
         // bigger than when the image was not loaded).
-        //
+        // 
         // If the 'panMapIfOutOfView' property is set, we will pan the newly
         // resized popup back into view.
-        //
-        // Note that this function, when called, will have 'popup' and
+        // 
+        // Note that this function, when called, will have 'popup' and 
         // 'img' properties in the context.
         //
         var onImgLoad = function() {
-
+            
             this.popup.updateSize();
-
+     
             if ( this.popup.visible() && this.popup.panMapIfOutOfView ) {
                 this.popup.panIntoView();
             }
@@ -5184,12 +5592,12 @@
             OpenLayers.Event.stopObserving(
                 this.img, "load", this.img._onImageLoad
             );
-
+    
         };
 
-        //cycle through the images and if their size is 0x0, that means that
-        // they haven't been loaded yet, so we attach the listener, which
-        // will fire when the images finish loading and will resize the
+        //cycle through the images and if their size is 0x0, that means that 
+        // they haven't been loaded yet, so we attach the listener, which 
+        // will fire when the images finish loading and will resize the 
         // popup accordingly to its new size.
         var images = this.contentDiv.getElementsByTagName("img");
         for (var i = 0, len = images.length; i < len; i++) {
@@ -5206,27 +5614,27 @@
                 img._onImgLoad = OpenLayers.Function.bind(onImgLoad, context);
 
                 OpenLayers.Event.observe(img, 'load', img._onImgLoad);
-            }
-        }
+            }    
+        } 
     },
 
     /**
      * APIMethod: getSafeContentSize
-     *
+     * 
      * Parameters:
      * size - {<OpenLayers.Size>} Desired size to make the popup.
-     *
+     * 
      * Returns:
      * {<OpenLayers.Size>} A size to make the popup which is neither smaller
-     *     than the specified minimum size, nor bigger than the maximum
+     *     than the specified minimum size, nor bigger than the maximum 
      *     size (which is calculated relative to the size of the viewport).
      */
     getSafeContentSize: function(size) {
 
         var safeContentSize = size.clone();
 
-        // if our contentDiv has a css 'padding' set on it by a stylesheet, we
-        //  must add that to the desired "size".
+        // if our contentDiv has a css 'padding' set on it by a stylesheet, we 
+        //  must add that to the desired "size". 
         var contentDivPadding = this.getContentDivPadding();
         var wPadding = contentDivPadding.left + contentDivPadding.right;
         var hPadding = contentDivPadding.top + contentDivPadding.bottom;
@@ -5243,25 +5651,25 @@
 
         // prevent the popup from being smaller than a specified minimal size
         if (this.minSize) {
-            safeContentSize.w = Math.max(safeContentSize.w,
+            safeContentSize.w = Math.max(safeContentSize.w, 
                 (this.minSize.w - wPadding));
-            safeContentSize.h = Math.max(safeContentSize.h,
+            safeContentSize.h = Math.max(safeContentSize.h, 
                 (this.minSize.h - hPadding));
         }
 
         // prevent the popup from being bigger than a specified maximum size
         if (this.maxSize) {
-            safeContentSize.w = Math.min(safeContentSize.w,
+            safeContentSize.w = Math.min(safeContentSize.w, 
                 (this.maxSize.w - wPadding));
-            safeContentSize.h = Math.min(safeContentSize.h,
+            safeContentSize.h = Math.min(safeContentSize.h, 
                 (this.maxSize.h - hPadding));
         }
-
-        //make sure the desired size to set doesn't result in a popup that
+        
+        //make sure the desired size to set doesn't result in a popup that 
         // is bigger than the map's viewport.
         //
         if (this.map && this.map.size) {
-
+            
             var extraX = 0, extraY = 0;
             if (this.keepInMap && !this.panMapIfOutOfView) {
                 var px = this.map.getPixelFromLonLat(this.lonlat);
@@ -5282,39 +5690,39 @@
                         extraX = px.x;
                         extraY = px.y;
                         break;
-                    default:
+                    default:    
                         extraX = px.x;
                         extraY = this.map.size.h - px.y;
                         break;
                 }
-            }
-
-            var maxY = this.map.size.h -
-                this.map.paddingForPopups.top -
-                this.map.paddingForPopups.bottom -
+            }    
+          
+            var maxY = this.map.size.h - 
+                this.map.paddingForPopups.top - 
+                this.map.paddingForPopups.bottom - 
                 hPadding - extraY;
-
-            var maxX = this.map.size.w -
-                this.map.paddingForPopups.left -
-                this.map.paddingForPopups.right -
+            
+            var maxX = this.map.size.w - 
+                this.map.paddingForPopups.left - 
+                this.map.paddingForPopups.right - 
                 wPadding - extraX;
-
+            
             safeContentSize.w = Math.min(safeContentSize.w, maxX);
             safeContentSize.h = Math.min(safeContentSize.h, maxY);
         }
-
+        
         return safeContentSize;
     },
-
+    
     /**
      * Method: getContentDivPadding
-     * Glorious, oh glorious hack in order to determine the css 'padding' of
-     *     the contentDiv. IE/Opera return null here unless we actually add the
-     *     popup's main 'div' element (which contains contentDiv) to the DOM.
-     *     So we make it invisible and then add it to the document temporarily.
+     * Glorious, oh glorious hack in order to determine the css 'padding' of 
+     *     the contentDiv. IE/Opera return null here unless we actually add the 
+     *     popup's main 'div' element (which contains contentDiv) to the DOM. 
+     *     So we make it invisible and then add it to the document temporarily. 
      *
-     *     Once we've taken the padding readings we need, we then remove it
-     *     from the DOM (it will actually get added to the DOM in
+     *     Once we've taken the padding readings we need, we then remove it 
+     *     from the DOM (it will actually get added to the DOM in 
      *     Map.js's addPopup)
      *
      * Returns:
@@ -5326,27 +5734,27 @@
         var contentDivPadding = this._contentDivPadding;
         if (!contentDivPadding) {
 
-            if (this.div.parentNode == null) {
-                //make the div invisible and add it to the page
-                this.div.style.display = "none";
-                document.body.appendChild(this.div);
-            }
-
-            //read the padding settings from css, put them in an OL.Bounds
+        	if (this.div.parentNode == null) {
+	        	//make the div invisible and add it to the page        
+	            this.div.style.display = "none";
+	            document.body.appendChild(this.div);
+	    	}
+	            
+            //read the padding settings from css, put them in an OL.Bounds        
             contentDivPadding = new OpenLayers.Bounds(
                 OpenLayers.Element.getStyle(this.contentDiv, "padding-left"),
                 OpenLayers.Element.getStyle(this.contentDiv, "padding-bottom"),
                 OpenLayers.Element.getStyle(this.contentDiv, "padding-right"),
                 OpenLayers.Element.getStyle(this.contentDiv, "padding-top")
             );
-
+    
             //cache the value
             this._contentDivPadding = contentDivPadding;
 
             if (this.div.parentNode == document.body) {
-                //remove the div from the page and make it visible again
-                document.body.removeChild(this.div);
-                this.div.style.display = "";
+	            //remove the div from the page and make it visible again
+	            document.body.removeChild(this.div);
+	            this.div.style.display = "";
             }
         }
         return contentDivPadding;
@@ -5354,7 +5762,7 @@
 
     /**
      * Method: addCloseBox
-     *
+     * 
      * Parameters:
      * callback - {Function} The callback to be called when the close button
      *     is clicked.
@@ -5364,12 +5772,12 @@
         this.closeDiv = OpenLayers.Util.createDiv(
             this.id + "_close", null, new OpenLayers.Size(17, 17)
         );
-        this.closeDiv.className = "olPopupCloseBox";
-
+        this.closeDiv.className = "olPopupCloseBox"; 
+        
         // use the content div's css padding to determine if we should
         //  padd the close div
         var contentDivPadding = this.getContentDivPadding();
-
+         
         this.closeDiv.style.right = contentDivPadding.right + "px";
         this.closeDiv.style.top = contentDivPadding.top + "px";
         this.groupDiv.appendChild(this.closeDiv);
@@ -5378,7 +5786,7 @@
             this.hide();
             OpenLayers.Event.stop(e);
         };
-        OpenLayers.Event.observe(this.closeDiv, "click",
+        OpenLayers.Event.observe(this.closeDiv, "click", 
                 OpenLayers.Function.bindAsEventListener(closePopup, this));
     },
 
@@ -5387,58 +5795,58 @@
      * Pans the map such that the popup is totaly viewable (if necessary)
      */
     panIntoView: function() {
-
+        
         var mapSize = this.map.getSize();
-
-        //start with the top left corner of the popup, in px,
+    
+        //start with the top left corner of the popup, in px, 
         // relative to the viewport
         var origTL = this.map.getViewPortPxFromLayerPx( new OpenLayers.Pixel(
             parseInt(this.div.style.left),
             parseInt(this.div.style.top)
         ));
         var newTL = origTL.clone();
-
+    
         //new left (compare to margins, using this.size to calculate right)
         if (origTL.x < this.map.paddingForPopups.left) {
             newTL.x = this.map.paddingForPopups.left;
-        } else
+        } else 
         if ( (origTL.x + this.size.w) > (mapSize.w - this.map.paddingForPopups.right)) {
             newTL.x = mapSize.w - this.map.paddingForPopups.right - this.size.w;
         }
-
+        
         //new top (compare to margins, using this.size to calculate bottom)
         if (origTL.y < this.map.paddingForPopups.top) {
             newTL.y = this.map.paddingForPopups.top;
-        } else
+        } else 
         if ( (origTL.y + this.size.h) > (mapSize.h - this.map.paddingForPopups.bottom)) {
             newTL.y = mapSize.h - this.map.paddingForPopups.bottom - this.size.h;
         }
-
+        
         var dx = origTL.x - newTL.x;
         var dy = origTL.y - newTL.y;
-
+        
         this.map.pan(dx, dy);
     },
 
-    /**
+    /** 
      * Method: registerEvents
      * Registers events on the popup.
      *
-     * Do this in a separate function so that subclasses can
+     * Do this in a separate function so that subclasses can 
      *   choose to override it if they wish to deal differently
      *   with mouse events
-     *
+     * 
      *   Note in the following handler functions that some special
-     *    care is needed to deal correctly with mousing and popups.
-     *
+     *    care is needed to deal correctly with mousing and popups. 
+     *   
      *   Because the user might select the zoom-rectangle option and
      *    then drag it over a popup, we need a safe way to allow the
      *    mousemove and mouseup events to pass through the popup when
      *    they are initiated from outside.
-     *
+     * 
      *   Otherwise, we want to essentially kill the event propagation
-     *    for all other events, though we have to do so carefully,
-     *    without disabling basic html functionality, like clicking on
+     *    for all other events, though we have to do so carefully, 
+     *    without disabling basic html functionality, like clicking on 
      *    hyperlinks or drag-selecting text.
      */
      registerEvents:function() {
@@ -5453,31 +5861,31 @@
             "dblclick": this.ondblclick,
             scope: this
         });
-
+        
      },
 
-    /**
-     * Method: onmousedown
+    /** 
+     * Method: onmousedown 
      * When mouse goes down within the popup, make a note of
-     *   it locally, and then do not propagate the mousedown
+     *   it locally, and then do not propagate the mousedown 
      *   (but do so safely so that user can select text inside)
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     onmousedown: function (evt) {
         this.mousedown = true;
         OpenLayers.Event.stop(evt, true);
     },
 
-    /**
+    /** 
      * Method: onmousemove
-     * If the drag was started within the popup, then
+     * If the drag was started within the popup, then 
      *   do not propagate the mousemove (but do so safely
      *   so that user can select text inside)
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     onmousemove: function (evt) {
         if (this.mousedown) {
@@ -5485,15 +5893,15 @@
         }
     },
 
-    /**
+    /** 
      * Method: onmouseup
-     * When mouse comes up within the popup, after going down
-     *   in it, reset the flag, and then (once again) do not
-     *   propagate the event, but do so safely so that user can
+     * When mouse comes up within the popup, after going down 
+     *   in it, reset the flag, and then (once again) do not 
+     *   propagate the event, but do so safely so that user can 
      *   select text inside
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     onmouseup: function (evt) {
         if (this.mousedown) {
@@ -5505,32 +5913,32 @@
     /**
      * Method: onclick
      * Ignore clicks, but allowing default browser handling
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     onclick: function (evt) {
         OpenLayers.Event.stop(evt, true);
     },
 
-    /**
+    /** 
      * Method: onmouseout
      * When mouse goes out of the popup set the flag to false so that
      *   if they let go and then drag back in, we won't be confused.
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     onmouseout: function (evt) {
         this.mousedown = false;
     },
-
-    /**
+    
+    /** 
      * Method: ondblclick
      * Ignore double-clicks, but allowing default browser handling
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     ondblclick: function (evt) {
         OpenLayers.Event.stop(evt, true);
@@ -5548,8 +5956,9 @@
     OpenLayers/Protocol.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -5558,13 +5967,13 @@
  *     one of the protocol subclasses instead.
  */
 OpenLayers.Protocol = OpenLayers.Class({
-
+    
     /**
      * Property: format
      * {<OpenLayers.Format>} The format used by this protocol.
      */
     format: null,
-
+    
     /**
      * Property: options
      * {Object} Any options sent to the constructor.
@@ -5578,8 +5987,14 @@
      *      true.
      */
     autoDestroy: true,
-
+   
     /**
+     * Property: defaultFilter
+     * {OpenLayers.Filter} Optional default filter to read requests
+     */
+    defaultFilter: null,
+    
+    /**
      * Constructor: OpenLayers.Protocol
      * Abstract class for vector protocols.  Create instances of a subclass.
      *
@@ -5594,6 +6009,26 @@
     },
 
     /**
+     * Method: mergeWithDefaultFilter
+     * Merge filter passed to the read method with the default one
+     *
+     * Parameters:
+     * filter - {OpenLayers.Filter}
+     */
+    mergeWithDefaultFilter: function(filter) {
+        var merged;
+        if (filter && this.defaultFilter) {
+            merged = new OpenLayers.Filter.Logical({
+                type: OpenLayers.Filter.Logical.AND,
+                filters: [this.defaultFilter, filter]
+            });
+        } else {
+            merged = filter || this.defaultFilter || undefined;
+        }
+        return merged;
+    },
+
+    /**
      * APIMethod: destroy
      * Clean up the protocol.
      */
@@ -5601,7 +6036,7 @@
         this.options = null;
         this.format = null;
     },
-
+    
     /**
      * APIMethod: read
      * Construct a request for reading new features.
@@ -5614,10 +6049,12 @@
      * object, the same object will be passed to the callback function passed
      * if one exists in the options object.
      */
-    read: function() {
+    read: function(options) {
+        options = options || {};
+        options.filter = this.mergeWithDefaultFilter(options.filter);
     },
-
-
+    
+    
     /**
      * APIMethod: create
      * Construct a request for writing newly created features.
@@ -5634,7 +6071,7 @@
      */
     create: function() {
     },
-
+    
     /**
      * APIMethod: update
      * Construct a request updating modified features.
@@ -5651,7 +6088,7 @@
      */
     update: function() {
     },
-
+    
     /**
      * APIMethod: delete
      * Construct a request deleting a removed feature.
@@ -5699,8 +6136,24 @@
      */
     abort: function(response) {
     },
-
-    CLASS_NAME: "OpenLayers.Protocol"
+   
+    /**
+     * Method: createCallback
+     * Returns a function that applies the given public method with resp and
+     *     options arguments.
+     *
+     * Parameters:
+     * method - {Function} The method to be applied by the callback.
+     * response - {<OpenLayers.Protocol.Response>} The protocol response object.
+     * options - {Object} Options sent to the protocol method
+     */
+    createCallback: function(method, response, options) {
+        return OpenLayers.Function.bind(function() {
+            method.apply(this, [response, options]);
+        }, this);
+    },
+   
+    CLASS_NAME: "OpenLayers.Protocol" 
 });
 
 /**
@@ -5779,42 +6232,43 @@
     OpenLayers/Renderer.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
- * Class: OpenLayers.Renderer
+ * Class: OpenLayers.Renderer 
  * This is the base class for all renderers.
  *
  * This is based on a merger code written by Paul Spencer and Bertil Chapuis.
  * It is largely composed of virtual functions that are to be implemented
  * in technology-specific subclasses, but there is some generic code too.
- *
+ * 
  * The functions that *are* implemented here merely deal with the maintenance
- *  of the size and extent variables, as well as the cached 'resolution'
- *  value.
- *
+ *  of the size and extent variables, as well as the cached 'resolution' 
+ *  value. 
+ * 
  * A note to the user that all subclasses should use getResolution() instead
- *  of directly accessing this.resolution in order to correctly use the
+ *  of directly accessing this.resolution in order to correctly use the 
  *  cacheing system.
  *
  */
 OpenLayers.Renderer = OpenLayers.Class({
 
-    /**
+    /** 
      * Property: container
-     * {DOMElement}
+     * {DOMElement} 
      */
     container: null,
-
+    
     /**
      * Property: root
      * {DOMElement}
      */
     root: null,
 
-    /**
+    /** 
      * Property: extent
      * {<OpenLayers.Bounds>}
      */
@@ -5823,44 +6277,44 @@
     /**
      * Property: locked
      * {Boolean} If the renderer is currently in a state where many things
-     *     are changing, the 'locked' property is set to true. This means
+     *     are changing, the 'locked' property is set to true. This means 
      *     that renderers can expect at least one more drawFeature event to be
      *     called with the 'locked' property set to 'true': In some renderers,
      *     this might make sense to use as a 'only update local information'
-     *     flag.
-     */
+     *     flag. 
+     */  
     locked: false,
-
-    /**
+    
+    /** 
      * Property: size
-     * {<OpenLayers.Size>}
+     * {<OpenLayers.Size>} 
      */
     size: null,
-
+    
     /**
      * Property: resolution
      * {Float} cache of current map resolution
      */
     resolution: null,
-
+    
     /**
-     * Property: map
+     * Property: map  
      * {<OpenLayers.Map>} Reference to the map -- this is set in Vector's setMap()
      */
     map: null,
-
+    
     /**
-     * Constructor: OpenLayers.Renderer
+     * Constructor: OpenLayers.Renderer 
      *
      * Parameters:
-     * containerID - {<String>}
+     * containerID - {<String>} 
      * options - {Object} options for this renderer. See sublcasses for
      *     supported options.
      */
     initialize: function(containerID, options) {
         this.container = OpenLayers.Util.getElement(containerID);
     },
-
+    
     /**
      * APIMethod: destroy
      */
@@ -5875,20 +6329,20 @@
     /**
      * APIMethod: supported
      * This should be overridden by specific subclasses
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the browser supports the renderer class
      */
     supported: function() {
         return false;
-    },
-
+    },    
+    
     /**
      * Method: setExtent
      * Set the visible part of the layer.
      *
-     * Resolution has probably changed, so we nullify the resolution
-     * cache (this.resolution) -- this way it will be re-computed when
+     * Resolution has probably changed, so we nullify the resolution 
+     * cache (this.resolution) -- this way it will be re-computed when 
      * next it is needed.
      * We nullify the resolution cache (this.resolution) if resolutionChanged
      * is set to true - this way it will be re-computed on the next
@@ -5904,27 +6358,27 @@
             this.resolution = null;
         }
     },
-
+    
     /**
      * Method: setSize
      * Sets the size of the drawing surface.
-     *
-     * Resolution has probably changed, so we nullify the resolution
-     * cache (this.resolution) -- this way it will be re-computed when
+     * 
+     * Resolution has probably changed, so we nullify the resolution 
+     * cache (this.resolution) -- this way it will be re-computed when 
      * next it is needed.
      *
      * Parameters:
-     * size - {<OpenLayers.Size>}
+     * size - {<OpenLayers.Size>} 
      */
     setSize: function(size) {
         this.size = size.clone();
         this.resolution = null;
     },
-
-    /**
+    
+    /** 
      * Method: getResolution
      * Uses cached copy of resolution if available to minimize computing
-     *
+     * 
      * Returns:
      * The current map's resolution
      */
@@ -5932,7 +6386,7 @@
         this.resolution = this.resolution || this.map.getResolution();
         return this.resolution;
     },
-
+    
     /**
      * Method: drawFeature
      * Draw the feature.  The optional style argument can be used
@@ -5940,9 +6394,9 @@
      * be called from layer.drawFeature().
      *
      * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>}
+     * feature - {<OpenLayers.Feature.Vector>} 
      * style - {<Object>}
-     *
+     * 
      * Returns:
      * {Boolean} true if the feature has been drawn completely, false if not,
      *     undefined if the feature had no geometry
@@ -5959,7 +6413,14 @@
                 }
                 var rendered = this.drawGeometry(feature.geometry, style, feature.id);
                 if(style.display != "none" && style.label && rendered !== false) {
-                    this.drawText(feature.id, style, feature.geometry.getCentroid());
+                    var location = feature.geometry.getCentroid(); 
+                    if(style.labelXOffset || style.labelYOffset) {
+                        xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;
+                        yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;
+                        var res = this.getResolution();
+                        location.move(xOffset*res, yOffset*res);
+                    }
+                    this.drawText(feature.id, style, location);
                 } else {
                     this.removeText(feature.id);
                 }
@@ -5969,26 +6430,26 @@
     },
 
 
-    /**
+    /** 
      * Method: drawGeometry
-     *
+     * 
      * Draw a geometry.  This should only be called from the renderer itself.
      * Use layer.drawFeature() from outside the renderer.
      * virtual function
      *
      * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * style - {Object}
-     * featureId - {<String>}
+     * geometry - {<OpenLayers.Geometry>} 
+     * style - {Object} 
+     * featureId - {<String>} 
      */
     drawGeometry: function(geometry, style, featureId) {},
-
+        
     /**
      * Method: drawText
      * Function for drawing text labels.
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * featureId - {String}
      * style -
      * location - {<OpenLayers.Geometry.Point>}
@@ -5999,67 +6460,69 @@
      * Method: removeText
      * Function for removing text labels.
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * featureId - {String}
      */
     removeText: function(featureId) {},
-
+    
     /**
      * Method: clear
      * Clear all vectors from the renderer.
      * virtual function.
-     */
+     */    
     clear: function() {},
 
     /**
      * Method: getFeatureIdFromEvent
-     * Returns a feature id from an event on the renderer.
+     * Returns a feature id from an event on the renderer.  
      * How this happens is specific to the renderer.  This should be
      * called from layer.getFeatureFromEvent().
      * Virtual function.
-     *
+     * 
      * Parameters:
-     * evt - {<OpenLayers.Event>}
+     * evt - {<OpenLayers.Event>} 
      *
      * Returns:
      * {String} A feature id or null.
      */
     getFeatureIdFromEvent: function(evt) {},
-
+    
     /**
-     * Method: eraseFeatures
+     * Method: eraseFeatures 
      * This is called by the layer to erase features
-     *
+     * 
      * Parameters:
-     * features - {Array(<OpenLayers.Feature.Vector>)}
+     * features - {Array(<OpenLayers.Feature.Vector>)} 
      */
     eraseFeatures: function(features) {
         if(!(features instanceof Array)) {
             features = [features];
         }
         for(var i=0, len=features.length; i<len; ++i) {
-            this.eraseGeometry(features[i].geometry);
-            this.removeText(features[i].id);
+            var feature = features[i];
+            this.eraseGeometry(feature.geometry, feature.id);
+            this.removeText(feature.id);
         }
     },
-
+    
     /**
      * Method: eraseGeometry
      * Remove a geometry from the renderer (by id).
      * virtual function.
-     *
+     * 
      * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
+     * geometry - {<OpenLayers.Geometry>} 
+     * featureId - {String}
      */
-    eraseGeometry: function(geometry) {},
-
+    eraseGeometry: function(geometry, featureId) {},
+    
     /**
      * Method: moveRoot
      * moves this renderer's root to a (different) renderer.
      * To be implemented by subclasses that require a common renderer root for
      * feature selection.
-     *
+     * 
      * Parameters:
      * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
      */
@@ -6070,22 +6533,74 @@
      * Gets the layer that this renderer's output appears on. If moveRoot was
      * used, this will be different from the id of the layer containing the
      * features rendered by this renderer.
-     *
+     * 
      * Returns:
      * {String} the id of the output layer.
      */
     getRenderLayerId: function() {
         return this.container.id;
     },
+    
+    /**
+     * Method: applyDefaultSymbolizer
+     * 
+     * Parameters:
+     * symbolizer - {Object}
+     * 
+     * Returns:
+     * {Object}
+     */
+    applyDefaultSymbolizer: function(symbolizer) {
+        var result = OpenLayers.Util.extend({},
+            OpenLayers.Renderer.defaultSymbolizer);
+        if(symbolizer.stroke === false) {
+            delete result.strokeWidth;
+            delete result.strokeColor;
+        }
+        if(symbolizer.fill === false) {
+            delete result.fillColor;
+        }
+        OpenLayers.Util.extend(result, symbolizer);
+        return result;
+    },
 
     CLASS_NAME: "OpenLayers.Renderer"
 });
+
+/**
+ * Constant: OpenLayers.Renderer.defaultSymbolizer
+ * {Object} Properties from this symbolizer will be applied to symbolizers
+ *     with missing properties. This can also be used to set a global
+ *     symbolizer default in OpenLayers. To be SLD 1.x compliant, add the
+ *     following code before rendering any vector features:
+ * (code)
+ * OpenLayers.Renderer.defaultSymbolizer = {
+ *     fillColor: "#808080",
+ *     fillOpacity: 1,
+ *     strokeColor: "#000000",
+ *     strokeOpacity: 1,
+ *     strokeWidth: 1,
+ *     pointRadius: 3,
+ *     graphicName: "square"
+ * };
+ * (end)
+ */
+OpenLayers.Renderer.defaultSymbolizer = {
+    fillColor: "#000000",
+    strokeColor: "#000000",
+    strokeWidth: 2,
+    fillOpacity: 1,
+    strokeOpacity: 1,
+    pointRadius: 0
+};
+    
 /* ======================================================================
     OpenLayers/Strategy.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -6094,21 +6609,21 @@
  *     one of the strategy subclasses instead.
  */
 OpenLayers.Strategy = OpenLayers.Class({
-
+    
     /**
      * Property: layer
      * {<OpenLayers.Layer.Vector>} The layer this strategy belongs to.
      */
     layer: null,
-
+    
     /**
      * Property: options
      * {Object} Any options sent to the constructor.
      */
     options: null,
 
-    /**
-     * Property: active
+    /** 
+     * Property: active 
      * {Boolean} The control is active.
      */
     active: null,
@@ -6143,7 +6658,7 @@
         // set the active property here, so that user cannot override it
         this.active = false;
     },
-
+    
     /**
      * APIMethod: destroy
      * Clean up the strategy.
@@ -6164,7 +6679,7 @@
     setLayer: function(layer) {
         this.layer = layer;
     },
-
+    
     /**
      * Method: activate
      * Activate the strategy.  Register any listeners, do appropriate setup.
@@ -6180,7 +6695,7 @@
         }
         return false;
     },
-
+    
     /**
      * Method: deactivate
      * Deactivate the strategy.  Unregister any listeners, do appropriate
@@ -6197,15 +6712,71 @@
         }
         return false;
     },
+   
+    CLASS_NAME: "OpenLayers.Strategy" 
+});
+/* ======================================================================
+    OpenLayers/Symbolizer.js
+   ====================================================================== */
 
-    CLASS_NAME: "OpenLayers.Strategy"
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.Symbolizer
+ * Base class representing a symbolizer used for feature rendering.
+ */
+OpenLayers.Symbolizer = OpenLayers.Class({
+    
+
+    /**
+     * APIProperty: zIndex
+     * {Number} The zIndex determines the rendering order for a symbolizer.
+     *     Symbolizers with larger zIndex values are rendered over symbolizers
+     *     with smaller zIndex values.  Default is 0.
+     */
+    zIndex: 0,
+    
+    /**
+     * Constructor: OpenLayers.Symbolizer
+     * Instances of this class are not useful.  See one of the subclasses.
+     *
+     * Parameters:
+     * config - {Object} An object containing properties to be set on the 
+     *     symbolizer.  Any documented symbolizer property can be set at 
+     *     construction.
+     *
+     * Returns:
+     * A new symbolizer.
+     */
+    initialize: function(config) {
+        OpenLayers.Util.extend(this, config);
+    },
+    
+    /** 
+     * APIMethod: clone
+     * Create a copy of this symbolizer.
+     *
+     * Returns a symbolizer of the same type with the same properties.
+     */
+    clone: function() {
+        var Type = eval(this.CLASS_NAME);
+        return new Type(OpenLayers.Util.extend({}, this));
+    },
+    
+    CLASS_NAME: "OpenLayers.Symbolizer"
+    
 });
+
 /* ======================================================================
     OpenLayers/Control.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -6215,15 +6786,15 @@
 /**
  * Class: OpenLayers.Control
  * Controls affect the display or behavior of the map. They allow everything
- * from panning and zooming to displaying a scale indicator. Controls by
+ * from panning and zooming to displaying a scale indicator. Controls by 
  * default are added to the map they are contained within however it is
  * possible to add a control to an external div by passing the div in the
  * options parameter.
- *
+ * 
  * Example:
  * The following example shows how to add many of the common controls
  * to a map.
- *
+ * 
  * > var map = new OpenLayers.Map('map', { controls: [] });
  * >
  * > map.addControl(new OpenLayers.Control.PanZoomBar());
@@ -6235,10 +6806,10 @@
  * > map.addControl(new OpenLayers.Control.OverviewMap());
  * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
  *
- * The next code fragment is a quick example of how to intercept
+ * The next code fragment is a quick example of how to intercept 
  * shift-mouse click to display the extent of the bounding box
  * dragged out by the user.  Usually controls are not created
- * in exactly this manner.  See the source for a more complete
+ * in exactly this manner.  See the source for a more complete 
  * example:
  *
  * > var control = new OpenLayers.Control();
@@ -6246,7 +6817,7 @@
  * >     draw: function () {
  * >         // this Handler.Box will intercept the shift-mousedown
  * >         // before Control.MouseDefault gets to see it
- * >         this.box = new OpenLayers.Handler.Box( control,
+ * >         this.box = new OpenLayers.Handler.Box( control, 
  * >             {"done": this.notice},
  * >             {keyMask: OpenLayers.Handler.MOD_SHIFT});
  * >         this.box.activate();
@@ -6255,70 +6826,77 @@
  * >     notice: function (bounds) {
  * >         OpenLayers.Console.userError(bounds);
  * >     }
- * > });
+ * > }); 
  * > map.addControl(control);
- *
+ * 
  */
 OpenLayers.Control = OpenLayers.Class({
 
-    /**
-     * Property: id
-     * {String}
+    /** 
+     * Property: id 
+     * {String} 
      */
     id: null,
-
-    /**
-     * Property: map
+    
+    /** 
+     * Property: map 
      * {<OpenLayers.Map>} this gets set in the addControl() function in
-     * OpenLayers.Map
+     * OpenLayers.Map 
      */
     map: null,
 
-    /**
-     * Property: div
-     * {DOMElement}
+    /** 
+     * Property: div 
+     * {DOMElement} 
      */
     div: null,
 
-    /**
-     * Property: type
-     * {OpenLayers.Control.TYPES} Controls can have a 'type'. The type
-     * determines the type of interactions which are possible with them when
-     * they are placed into a toolbar.
+    /** 
+     * Property: type 
+     * {Number} Controls can have a 'type'. The type determines the type of
+     * interactions which are possible with them when they are placed in an
+     * <OpenLayers.Control.Panel>. 
      */
-    type: null,
+    type: null, 
 
-    /**
+    /** 
      * Property: allowSelection
      * {Boolean} By deafault, controls do not allow selection, because
      * it may interfere with map dragging. If this is true, OpenLayers
      * will not prevent selection of the control.
      * Default is false.
      */
-    allowSelection: false,
+    allowSelection: false,  
 
-    /**
-     * Property: displayClass
+    /** 
+     * Property: displayClass 
      * {string}  This property is used for CSS related to the drawing of the
-     * Control.
+     * Control. 
      */
     displayClass: "",
-
+    
     /**
-    * Property: title
-    * {string}  This property is used for showing a tooltip over the
-    * Control.
-    */
+    * Property: title  
+    * {string}  This property is used for showing a tooltip over the  
+    * Control.  
+    */ 
     title: "",
 
     /**
-     * Property: active
+     * APIProperty: autoActivate
+     * {Boolean} Activate the control when it is added to a map.  Default is
+     *     false.
+     */
+    autoActivate: false,
+
+    /** 
+     * Property: active 
      * {Boolean} The control is active.
      */
     active: null,
 
-    /**
-     * Property: handler
+    /** 
+     * Property: handler 
      * {<OpenLayers.Handler>} null
      */
     handler: null,
@@ -6332,7 +6910,7 @@
      */
     eventListeners: null,
 
-    /**
+    /** 
      * Property: events
      * {<OpenLayers.Events>} Events instance for triggering control specific
      *     events.
@@ -6366,22 +6944,22 @@
      * Constructor: OpenLayers.Control
      * Create an OpenLayers Control.  The options passed as a parameter
      * directly extend the control.  For example passing the following:
-     *
+     * 
      * > var control = new OpenLayers.Control({div: myDiv});
      *
      * Overrides the default div attribute value of null.
-     *
+     * 
      * Parameters:
-     * options - {Object}
+     * options - {Object} 
      */
     initialize: function (options) {
         // We do this before the extend so that instances can override
         // className in options.
-        this.displayClass =
+        this.displayClass = 
             this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
-
+        
         OpenLayers.Util.extend(this, options);
-
+        
         this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
         if(this.eventListeners instanceof Object) {
             this.events.on(this.eventListeners);
@@ -6427,14 +7005,14 @@
         }
     },
 
-    /**
+    /** 
      * Method: setMap
      * Set the map property for the control. This is done through an accessor
-     * so that subclasses can override this and take special action once
-     * they have their map variable set.
+     * so that subclasses can override this and take special action once 
+     * they have their map variable set. 
      *
      * Parameters:
-     * map - {<OpenLayers.Map>}
+     * map - {<OpenLayers.Map>} 
      */
     setMap: function(map) {
         this.map = map;
@@ -6442,13 +7020,13 @@
             this.handler.setMap(map);
         }
     },
-
+  
     /**
      * Method: draw
      * The draw method is called when the control is ready to be displayed
      * on the page.  If a div has not been created one is created.  Controls
-     * with a visual component will almost always want to override this method
-     * to customize the look of control.
+     * with a visual component will almost always want to override this method 
+     * to customize the look of control. 
      *
      * Parameters:
      * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
@@ -6464,8 +7042,8 @@
             if (!this.allowSelection) {
                 this.div.className += " olControlNoSelect";
                 this.div.setAttribute("unselectable", "on", 0);
-                this.div.onselectstart = function() { return(false); };
-            }
+                this.div.onselectstart = OpenLayers.Function.False; 
+            }    
             if (this.title != "") {
                 this.div.title = this.title;
             }
@@ -6479,7 +7057,7 @@
 
     /**
      * Method: moveTo
-     * Sets the left and top style attributes to the passed in pixel
+     * Sets the left and top style attributes to the passed in pixel 
      * coordinates.
      *
      * Parameters:
@@ -6497,7 +7075,7 @@
      * Explicitly activates a control and it's associated
      * handler if one has been set.  Controls can be
      * deactivated by calling the deactivate() method.
-     *
+     * 
      * Returns:
      * {Boolean}  True if the control was successfully activated or
      *            false if the control was already active.
@@ -6519,12 +7097,12 @@
         this.events.triggerEvent("activate");
         return true;
     },
-
+    
     /**
      * Method: deactivate
      * Deactivates a control and it's associated handler if any.  The exact
      * effect of this depends on the control itself.
-     *
+     * 
      * Returns:
      * {Boolean} True if the control was effectively deactivated or false
      *           if the control was already inactive.
@@ -6550,15 +7128,27 @@
     CLASS_NAME: "OpenLayers.Control"
 });
 
+/**
+ * Constant: OpenLayers.Control.TYPE_BUTTON
+ */
 OpenLayers.Control.TYPE_BUTTON = 1;
+
+/**
+ * Constant: OpenLayers.Control.TYPE_TOGGLE
+ */
 OpenLayers.Control.TYPE_TOGGLE = 2;
+
+/**
+ * Constant: OpenLayers.Control.TYPE_TOOL
+ */
 OpenLayers.Control.TYPE_TOOL   = 3;
 /* ======================================================================
     OpenLayers/Lang.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -6571,8 +7161,8 @@
  *     and methods to set and get the current language.
  */
 OpenLayers.Lang = {
-
-    /**
+    
+    /** 
      * Property: code
      * {String}  Current language code to use in OpenLayers.  Use the
      *     <setCode> method to set this value and the <getCode> method to
@@ -6580,13 +7170,13 @@
      */
     code: null,
 
-    /**
+    /** 
      * APIProperty: defaultCode
      * {String} Default language to use when a specific language can't be
      *     found.  Default is "en".
      */
     defaultCode: "en",
-
+        
     /**
      * APIFunction: getCode
      * Get the current language code.
@@ -6600,7 +7190,7 @@
         }
         return OpenLayers.Lang.code;
     },
-
+    
     /**
      * APIFunction: setCode
      * Set the language code for string translation.  This code is used by
@@ -6639,7 +7229,7 @@
             );
             lang = OpenLayers.Lang.defaultCode;
         }
-
+        
         OpenLayers.Lang.code = lang;
     },
 
@@ -6653,7 +7243,7 @@
      * key - {String} The key for an i18n string value in the dictionary.
      * context - {Object} Optional context to be used with
      *     <OpenLayers.String.format>.
-     *
+     * 
      * Returns:
      * {String} A internationalized string.
      */
@@ -6669,7 +7259,7 @@
         }
         return message;
     }
-
+    
 };
 
 
@@ -6684,7 +7274,7 @@
  * key - {String} The key for an i18n string value in the dictionary.
  * context - {Object} Optional context to be used with
  *     <OpenLayers.String.format>.
- *
+ * 
  * Returns:
  * {String} A internationalized string.
  */
@@ -6693,8 +7283,9 @@
     OpenLayers/Popup/Anchored.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -6704,28 +7295,28 @@
 
 /**
  * Class: OpenLayers.Popup.Anchored
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Popup>
  */
-OpenLayers.Popup.Anchored =
+OpenLayers.Popup.Anchored = 
   OpenLayers.Class(OpenLayers.Popup, {
 
-    /**
+    /** 
      * Parameter: relativePosition
      * {String} Relative position of the popup ("br", "tr", "tl" or "bl").
      */
     relativePosition: null,
-
+    
     /**
-     * APIProperty: keepInMap
-     * {Boolean} If panMapIfOutOfView is false, and this property is true,
+     * APIProperty: keepInMap 
+     * {Boolean} If panMapIfOutOfView is false, and this property is true, 
      *     contrain the popup such that it always fits in the available map
      *     space. By default, this is set. If you are creating popups that are
      *     near map edges and not allowing pannning, and especially if you have
      *     a popup which has a fixedRelativePosition, setting this to false may
      *     be a smart thing to do.
-     *
+     *   
      *     For anchored popups, default is true, since subclasses will
      *     usually want this functionality.
      */
@@ -6733,20 +7324,20 @@
 
     /**
      * Parameter: anchor
-     * {Object} Object to which we'll anchor the popup. Must expose a
+     * {Object} Object to which we'll anchor the popup. Must expose a 
      *     'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>).
      */
     anchor: null,
 
-    /**
+    /** 
     * Constructor: OpenLayers.Popup.Anchored
-    *
+    * 
     * Parameters:
     * id - {String}
     * lonlat - {<OpenLayers.LonLat>}
     * contentSize - {<OpenLayers.Size>}
     * contentHTML - {String}
-    * anchor - {Object} Object which must expose a 'size' <OpenLayers.Size>
+    * anchor - {Object} Object which must expose a 'size' <OpenLayers.Size> 
     *     and 'offset' <OpenLayers.Pixel> (generally an <OpenLayers.Icon>).
     * closeBox - {Boolean}
     * closeBoxCallback - {Function} Function to be called on closeBox click.
@@ -6758,7 +7349,7 @@
         ];
         OpenLayers.Popup.prototype.initialize.apply(this, newArguments);
 
-        this.anchor = (anchor != null) ? anchor
+        this.anchor = (anchor != null) ? anchor 
                                        : { size: new OpenLayers.Size(0,0),
                                            offset: new OpenLayers.Pixel(0,0)};
     },
@@ -6769,13 +7360,13 @@
     destroy: function() {
         this.anchor = null;
         this.relativePosition = null;
-
-        OpenLayers.Popup.prototype.destroy.apply(this, arguments);
+        
+        OpenLayers.Popup.prototype.destroy.apply(this, arguments);        
     },
 
     /**
      * APIMethod: show
-     * Overridden from Popup since user might hide popup and then show() it
+     * Overridden from Popup since user might hide popup and then show() it 
      *     in a new location (meaning we might want to update the relative
      *     position on the show)
      */
@@ -6787,27 +7378,27 @@
     /**
      * Method: moveTo
      * Since the popup is moving to a new px, it might need also to be moved
-     *     relative to where the marker is. We first calculate the new
-     *     relativePosition, and then we calculate the new px where we will
-     *     put the popup, based on the new relative position.
-     *
-     *     If the relativePosition has changed, we must also call
-     *     updateRelativePosition() to make any visual changes to the popup
+     *     relative to where the marker is. We first calculate the new 
+     *     relativePosition, and then we calculate the new px where we will 
+     *     put the popup, based on the new relative position. 
+     * 
+     *     If the relativePosition has changed, we must also call 
+     *     updateRelativePosition() to make any visual changes to the popup 
      *     which are associated with putting it in a new relativePosition.
-     *
+     * 
      * Parameters:
      * px - {<OpenLayers.Pixel>}
      */
     moveTo: function(px) {
         var oldRelativePosition = this.relativePosition;
         this.relativePosition = this.calculateRelativePosition(px);
-
+        
         var newPx = this.calculateNewPx(px);
-
-        var newArguments = new Array(newPx);
+        
+        var newArguments = new Array(newPx);        
         OpenLayers.Popup.prototype.moveTo.apply(this, newArguments);
-
-        //if this move has caused the popup to change its relative position,
+        
+        //if this move has caused the popup to change its relative position, 
         // we need to make the appropriate cosmetic changes.
         if (this.relativePosition != oldRelativePosition) {
             this.updateRelativePosition();
@@ -6816,76 +7407,76 @@
 
     /**
      * APIMethod: setSize
-     *
+     * 
      * Parameters:
-     * contentSize - {<OpenLayers.Size>} the new size for the popup's
+     * contentSize - {<OpenLayers.Size>} the new size for the popup's 
      *     contents div (in pixels).
      */
-    setSize:function(contentSize) {
+    setSize:function(contentSize) { 
         OpenLayers.Popup.prototype.setSize.apply(this, arguments);
 
         if ((this.lonlat) && (this.map)) {
             var px = this.map.getLayerPxFromLonLat(this.lonlat);
             this.moveTo(px);
         }
-    },
-
-    /**
+    },  
+    
+    /** 
      * Method: calculateRelativePosition
-     *
+     * 
      * Parameters:
      * px - {<OpenLayers.Pixel>}
-     *
+     * 
      * Returns:
      * {String} The relative position ("br" "tr" "tl" "bl") at which the popup
      *     should be placed.
      */
     calculateRelativePosition:function(px) {
-        var lonlat = this.map.getLonLatFromLayerPx(px);
-
+        var lonlat = this.map.getLonLatFromLayerPx(px);        
+        
         var extent = this.map.getExtent();
         var quadrant = extent.determineQuadrant(lonlat);
-
+        
         return OpenLayers.Bounds.oppositeQuadrant(quadrant);
-    },
+    }, 
 
     /**
      * Method: updateRelativePosition
-     * The popup has been moved to a new relative location, so we may want to
-     *     make some cosmetic adjustments to it.
-     *
-     *     Note that in the classic Anchored popup, there is nothing to do
+     * The popup has been moved to a new relative location, so we may want to 
+     *     make some cosmetic adjustments to it. 
+     * 
+     *     Note that in the classic Anchored popup, there is nothing to do 
      *     here, since the popup looks exactly the same in all four positions.
-     *     Subclasses such as the AnchoredBubble and Framed, however, will
+     *     Subclasses such as the AnchoredBubble and Framed, however, will 
      *     want to do something special here.
      */
     updateRelativePosition: function() {
         //to be overridden by subclasses
     },
 
-    /**
+    /** 
      * Method: calculateNewPx
-     *
+     * 
      * Parameters:
      * px - {<OpenLayers.Pixel>}
-     *
+     * 
      * Returns:
      * {<OpenLayers.Pixel>} The the new px position of the popup on the screen
      *     relative to the passed-in px.
      */
     calculateNewPx:function(px) {
         var newPx = px.offset(this.anchor.offset);
-
+        
         //use contentSize if size is not already set
         var size = this.size || this.contentSize;
 
         var top = (this.relativePosition.charAt(0) == 't');
-        newPx.y += (top) ? -size.h : this.anchor.size.h;
-
+        newPx.y += (top) ? -(size.h + this.anchor.size.h) : this.anchor.size.h;
+        
         var left = (this.relativePosition.charAt(1) == 'l');
-        newPx.x += (left) ? -size.w : this.anchor.size.w;
+        newPx.x += (left) ? -(size.w + this.anchor.size.w) : this.anchor.size.w;
 
-        return newPx;
+        return newPx;   
     },
 
     CLASS_NAME: "OpenLayers.Popup.Anchored"
@@ -6894,8 +7485,9 @@
     OpenLayers/Renderer/Canvas.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -6903,9 +7495,9 @@
  */
 
 /**
- * Class: OpenLayers.Renderer.Canvas
+ * Class: OpenLayers.Renderer.Canvas 
  * A renderer based on the 2D 'canvas' drawing element.element
- *
+ * 
  * Inherits:
  *  - <OpenLayers.Renderer>
  */
@@ -6915,27 +7507,19 @@
      * Property: canvas
      * {Canvas} The canvas context object.
      */
-    canvas: null,
-
+    canvas: null, 
+    
     /**
      * Property: features
      * {Object} Internal object of feature/style pairs for use in redrawing the layer.
      */
-    features: null,
-
+    features: null, 
+   
     /**
-     * Property: geometryMap
-     * {Object} Geometry -> Feature lookup table. Used by eraseGeometry to
-     *     lookup features to remove from our internal table (this.features)
-     *     when erasing geoms.
-     */
-    geometryMap: null,
-
-    /**
      * Constructor: OpenLayers.Renderer.Canvas
      *
      * Parameters:
-     * containerID - {<String>}
+     * containerID - {<String>} 
      */
     initialize: function(containerID) {
         OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
@@ -6943,49 +7527,49 @@
         this.container.appendChild(this.root);
         this.canvas = this.root.getContext("2d");
         this.features = {};
-        this.geometryMap = {};
     },
-
-    /**
+    
+    /** 
      * Method: eraseGeometry
      * Erase a geometry from the renderer. Because the Canvas renderer has
      *     'memory' of the features that it has drawn, we have to remove the
-     *     feature so it doesn't redraw.
-     *
+     *     feature so it doesn't redraw.   
+     * 
      * Parameters:
      * geometry - {<OpenLayers.Geometry>}
+     * featureId - {String}
      */
-    eraseGeometry: function(geometry) {
-        this.eraseFeatures(this.features[this.geometryMap[geometry.id]][0]);
+    eraseGeometry: function(geometry, featureId) {
+        this.eraseFeatures(this.features[featureId][0]);
     },
 
     /**
      * APIMethod: supported
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the browser supports the renderer class
      */
     supported: function() {
         var canvas = document.createElement("canvas");
         return !!canvas.getContext;
-    },
-
+    },    
+    
     /**
      * Method: setExtent
      * Set the visible part of the layer.
      *
-     * Resolution has probably changed, so we nullify the resolution
-     * cache (this.resolution), then redraw.
+     * Resolution has probably changed, so we nullify the resolution 
+     * cache (this.resolution), then redraw. 
      *
      * Parameters:
-     * extent - {<OpenLayers.Bounds>}
+     * extent - {<OpenLayers.Bounds>} 
      */
     setExtent: function(extent) {
         this.extent = extent.clone();
         this.resolution = null;
         this.redraw();
     },
-
+    
     /**
      * Method: setSize
      * Sets the size of the drawing surface.
@@ -6993,7 +7577,7 @@
      * Once the size is updated, redraw the canvas.
      *
      * Parameters:
-     * size - {<OpenLayers.Size>}
+     * size - {<OpenLayers.Size>} 
      */
     setSize: function(size) {
         this.size = size.clone();
@@ -7003,43 +7587,33 @@
         this.root.height = size.h;
         this.resolution = null;
     },
-
+    
     /**
      * Method: drawFeature
      * Draw the feature. Stores the feature in the features list,
-     * then redraws the layer.
+     * then redraws the layer. 
      *
      * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>}
-     * style - {<Object>}
+     * feature - {<OpenLayers.Feature.Vector>} 
+     * style - {<Object>} 
      */
     drawFeature: function(feature, style) {
-        if(style == null) {
-            style = feature.style;
-        }
-        style = OpenLayers.Util.extend({
-          'fillColor': '#000000',
-          'strokeColor': '#000000',
-          'strokeWidth': 2,
-          'fillOpacity': 1,
-          'strokeOpacity': 1
-        }, style);
-        this.features[feature.id] = [feature, style];
-        if (feature.geometry) {
-            this.geometryMap[feature.geometry.id] = feature.id;
-        }
+        style = style || feature.style;
+        style = this.applyDefaultSymbolizer(style);  
+        
+        this.features[feature.id] = [feature, style]; 
         this.redraw();
     },
 
 
-    /**
+    /** 
      * Method: drawGeometry
      * Used when looping (in redraw) over the features; draws
-     * the canvas.
+     * the canvas. 
      *
      * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * style - {Object}
+     * geometry - {<OpenLayers.Geometry>} 
+     * style - {Object} 
      */
     drawGeometry: function(geometry, style) {
         var className = geometry.CLASS_NAME;
@@ -7051,7 +7625,7 @@
                 this.drawGeometry(geometry.components[i], style);
             }
             return;
-        };
+        }
         switch (geometry.CLASS_NAME) {
             case "OpenLayers.Geometry.Point":
                 this.drawPoint(geometry, style);
@@ -7072,18 +7646,17 @@
 
     /**
      * Method: drawExternalGraphic
-     * Called to draw External graphics.
-     *
-     * Parameters:
+     * Called to draw External graphics. 
+     * 
+     * Parameters: 
      * geometry - {<OpenLayers.Geometry>}
      * style    - {Object}
-     */
+     */ 
     drawExternalGraphic: function(pt, style) {
        var img = new Image();
-       img.src = style.externalGraphic;
-
+       
        if(style.graphicTitle) {
-           img.title=style.graphicTitle;
+           img.title=style.graphicTitle;           
        }
 
        var width = style.graphicWidth || style.graphicHeight;
@@ -7094,19 +7667,21 @@
            style.graphicXOffset : -(0.5 * width);
        var yOffset = (style.graphicYOffset != undefined) ?
            style.graphicYOffset : -(0.5 * height);
-       var opacity = style.graphicOpacity || style.fillOpacity;
-
-       var context = { img: img,
-                       x: (pt[0]+xOffset),
-                       y: (pt[1]+yOffset),
-                       width: width,
-                       height: height,
+       
+       var context = { img: img, 
+                       x: (pt[0]+xOffset), 
+                       y: (pt[1]+yOffset), 
+                       width: width, 
+                       height: height, 
+                       opacity: style.graphicOpacity || style.fillOpacity,
                        canvas: this.canvas };
 
        img.onload = OpenLayers.Function.bind( function() {
-           this.canvas.drawImage(this.img, this.x,
+           this.canvas.globalAlpha = this.opacity;
+           this.canvas.drawImage(this.img, this.x, 
                                  this.y, this.width, this.height);
        }, context);
+       img.src = style.externalGraphic;
     },
 
     /**
@@ -7118,10 +7693,10 @@
      * style - {Object} Symbolizer hash
      */
     setCanvasStyle: function(type, style) {
-        if (type == "fill") {
+        if (type == "fill") {     
             this.canvas.globalAlpha = style['fillOpacity'];
             this.canvas.fillStyle = style['fillColor'];
-        } else if (type == "stroke") {
+        } else if (type == "stroke") {  
             this.canvas.globalAlpha = style['strokeOpacity'];
             this.canvas.strokeStyle = style['strokeColor'];
             this.canvas.lineWidth = style['strokeWidth'];
@@ -7134,29 +7709,29 @@
     /**
      * Method: drawPoint
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * geometry - {<OpenLayers.Geometry>}
      * style    - {Object}
-     */
+     */ 
     drawPoint: function(geometry, style) {
         if(style.graphic !== false) {
             var pt = this.getLocalXY(geometry);
-
+            
             if (style.externalGraphic) {
                 this.drawExternalGraphic(pt, style);
             } else {
                 if(style.fill !== false) {
                     this.setCanvasStyle("fill", style);
                     this.canvas.beginPath();
-                    this.canvas.arc(pt[0], pt[1], 6, 0, Math.PI*2, true);
+                    this.canvas.arc(pt[0], pt[1], style.pointRadius, 0, Math.PI*2, true);
                     this.canvas.fill();
                 }
-
+                
                 if(style.stroke !== false) {
                     this.setCanvasStyle("stroke", style);
                     this.canvas.beginPath();
-                    this.canvas.arc(pt[0], pt[1], 6, 0, Math.PI*2, true);
+                    this.canvas.arc(pt[0], pt[1], style.pointRadius, 0, Math.PI*2, true);
                     this.canvas.stroke();
                     this.setCanvasStyle("reset");
                 }
@@ -7167,11 +7742,11 @@
     /**
      * Method: drawLineString
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * geometry - {<OpenLayers.Geometry>}
      * style    - {Object}
-     */
+     */ 
     drawLineString: function(geometry, style) {
         if(style.stroke !== false) {
             this.setCanvasStyle("stroke", style);
@@ -7185,16 +7760,16 @@
             this.canvas.stroke();
         }
         this.setCanvasStyle("reset");
-    },
-
+    },    
+    
     /**
      * Method: drawLinearRing
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * geometry - {<OpenLayers.Geometry>}
      * style    - {Object}
-     */
+     */ 
     drawLinearRing: function(geometry, style) {
         if(style.fill !== false) {
             this.setCanvasStyle("fill", style);
@@ -7207,9 +7782,8 @@
             }
             this.canvas.fill();
         }
-
+        
         if(style.stroke !== false) {
-            var oldWidth = this.canvas.lineWidth;
             this.setCanvasStyle("stroke", style);
             this.canvas.beginPath();
             var start = this.getLocalXY(geometry.components[0]);
@@ -7221,29 +7795,29 @@
             this.canvas.stroke();
         }
         this.setCanvasStyle("reset");
-    },
-
+    },    
+    
     /**
      * Method: drawPolygon
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * geometry - {<OpenLayers.Geometry>}
      * style    - {Object}
-     */
+     */ 
     drawPolygon: function(geometry, style) {
         this.drawLinearRing(geometry.components[0], style);
         for (var i = 1; i < geometry.components.length; i++) {
             this.drawLinearRing(geometry.components[i], {
-                fillOpacity: 0,
-                strokeWidth: 0,
-                strokeOpacity: 0,
-                strokeColor: '#000000',
+                fillOpacity: 0, 
+                strokeWidth: 0, 
+                strokeOpacity: 0, 
+                strokeColor: '#000000', 
                 fillColor: '#000000'}
-            ); // inner rings are 'empty'
+            ); // inner rings are 'empty'  
         }
     },
-
+    
     /**
      * Method: drawText
      * This method is only called by the renderer itself.
@@ -7258,16 +7832,16 @@
             labelAlign: "cm"
         }, style);
         var pt = this.getLocalXY(location);
-
+        
         this.setCanvasStyle("reset");
         this.canvas.fillStyle = style.fontColor;
-        this.canvas.globalAlpha = 1;
+        this.canvas.globalAlpha = style.fontOpacity || 1.0;
         var fontStyle = style.fontWeight + " " + style.fontSize + " " + style.fontFamily;
         if (this.canvas.fillText) {
             // HTML5
             var labelAlign =
                 OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]] ||
-                "middle";
+                "center";
             this.canvas.font = fontStyle;
             this.canvas.textAlign = labelAlign;
             this.canvas.fillText(style.label, pt[0], pt[1]);
@@ -7287,7 +7861,7 @@
                     pt[0] -= len / 2;
             }
             this.canvas.translate(pt[0], pt[1]);
-
+            
             this.canvas.mozDrawText(style.label);
             this.canvas.translate(-1*pt[0], -1*pt[1]);
         }
@@ -7298,7 +7872,7 @@
      * Method: getLocalXY
      * transform geographic xy into pixel xy
      *
-     * Parameters:
+     * Parameters: 
      * point - {<OpenLayers.Geometry.Point>}
      */
     getLocalXY: function(point) {
@@ -7312,18 +7886,18 @@
     /**
      * Method: clear
      * Clear all vectors from the renderer.
-     * virtual function.
-     */
+     */    
     clear: function() {
         this.canvas.clearRect(0, 0, this.root.width, this.root.height);
+        this.features = {};
     },
 
     /**
      * Method: getFeatureIdFromEvent
-     * Returns a feature id from an event on the renderer.
-     *
+     * Returns a feature id from an event on the renderer.  
+     * 
      * Parameters:
-     * evt - {<OpenLayers.Event>}
+     * evt - {<OpenLayers.Event>} 
      *
      * Returns:
      * {String} A feature id or null.
@@ -7331,9 +7905,9 @@
     getFeatureIdFromEvent: function(evt) {
         var loc = this.map.getLonLatFromPixel(evt.xy);
         var resolution = this.getResolution();
-        var bounds = new OpenLayers.Bounds(loc.lon - resolution * 5,
-                                           loc.lat - resolution * 5,
-                                           loc.lon + resolution * 5,
+        var bounds = new OpenLayers.Bounds(loc.lon - resolution * 5, 
+                                           loc.lat - resolution * 5, 
+                                           loc.lon + resolution * 5, 
                                            loc.lat + resolution * 5);
         var geom = bounds.toGeometry();
         for (var feat in this.features) {
@@ -7341,17 +7915,17 @@
             if (this.features[feat][0].geometry.intersects(geom)) {
                 return feat;
             }
-        }
+        }   
         return null;
     },
-
+    
     /**
-     * Method: eraseFeatures
+     * Method: eraseFeatures 
      * This is called by the layer to erase features; removes the feature from
      *     the list, then redraws the layer.
-     *
+     * 
      * Parameters:
-     * features - {Array(<OpenLayers.Feature.Vector>)}
+     * features - {Array(<OpenLayers.Feature.Vector>)} 
      */
     eraseFeatures: function(features) {
         if(!(features instanceof Array)) {
@@ -7373,7 +7947,7 @@
      */
     redraw: function() {
         if (!this.locked) {
-            this.clear();
+            this.canvas.clearRect(0, 0, this.root.width, this.root.height);
             var labelMap = [];
             var feature, style;
             for (var id in this.features) {
@@ -7387,11 +7961,11 @@
                 }
             }
             var item;
-            for (var i=0; len=labelMap.length, i<len; ++i) {
+            for (var i=0, len=labelMap.length; i<len; ++i) {
                 item = labelMap[i];
                 this.drawText(item[0].geometry.getCentroid(), item[1]);
             }
-        }
+        }    
     },
 
     CLASS_NAME: "OpenLayers.Renderer.Canvas"
@@ -7409,8 +7983,9 @@
     OpenLayers/Renderer/Elements.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -7420,33 +7995,33 @@
 /**
  * Class: OpenLayers.ElementsIndexer
  * This class takes care of figuring out which order elements should be
- *     placed in the DOM based on given indexing methods.
+ *     placed in the DOM based on given indexing methods. 
  */
 OpenLayers.ElementsIndexer = OpenLayers.Class({
-
+   
     /**
      * Property: maxZIndex
      * {Integer} This is the largest-most z-index value for a node
      *     contained within the indexer.
      */
     maxZIndex: null,
-
+    
     /**
      * Property: order
      * {Array<String>} This is an array of node id's stored in the
      *     order that they should show up on screen. Id's higher up in the
      *     array (higher array index) represent nodes with higher z-indeces.
      */
-    order: null,
-
+    order: null, 
+    
     /**
      * Property: indices
      * {Object} This is a hash that maps node ids to their z-index value
-     *     stored in the indexer. This is done to make finding a nodes z-index
+     *     stored in the indexer. This is done to make finding a nodes z-index 
      *     value O(1).
      */
     indices: null,
-
+    
     /**
      * Property: compare
      * {Function} This is the function used to determine placement of
@@ -7454,34 +8029,34 @@
      *     the Z_ORDER_DRAWING_ORDER comparison method.
      */
     compare: null,
-
+    
     /**
      * APIMethod: initialize
-     * Create a new indexer with
-     *
+     * Create a new indexer with 
+     * 
      * Parameters:
      * yOrdering - {Boolean} Whether to use y-ordering.
      */
     initialize: function(yOrdering) {
 
-        this.compare = yOrdering ?
+        this.compare = yOrdering ? 
             OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER :
             OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;
-
+            
         this.order = [];
         this.indices = {};
         this.maxZIndex = 0;
     },
-
+    
     /**
      * APIMethod: insert
-     * Insert a new node into the indexer. In order to find the correct
-     *     positioning for the node to be inserted, this method uses a binary
-     *     search. This makes inserting O(log(n)).
-     *
+     * Insert a new node into the indexer. In order to find the correct 
+     *     positioning for the node to be inserted, this method uses a binary 
+     *     search. This makes inserting O(log(n)). 
+     * 
      * Parameters:
      * newNode - {DOMElement} The new node to be inserted.
-     *
+     * 
      * Returns
      * {DOMElement} the node before which we should insert our newNode, or
      *     null if newNode can just be appended.
@@ -7492,40 +8067,40 @@
         if (this.exists(newNode)) {
             this.remove(newNode);
         }
-
+        
         var nodeId = newNode.id;
+        
+        this.determineZIndex(newNode);       
 
-        this.determineZIndex(newNode);
-
         var leftIndex = -1;
         var rightIndex = this.order.length;
         var middle;
 
         while (rightIndex - leftIndex > 1) {
             middle = parseInt((leftIndex + rightIndex) / 2);
-
+            
             var placement = this.compare(this, newNode,
                 OpenLayers.Util.getElement(this.order[middle]));
-
+            
             if (placement > 0) {
                 leftIndex = middle;
             } else {
                 rightIndex = middle;
-            }
+            } 
         }
-
+        
         this.order.splice(rightIndex, 0, nodeId);
         this.indices[nodeId] = this.getZIndex(newNode);
-
+        
         // If the new node should be before another in the index
         // order, return the node before which we have to insert the new one;
         // else, return null to indicate that the new node can be appended.
-    return this.getNextElement(rightIndex);
+        return this.getNextElement(rightIndex);
     },
-
+    
     /**
      * APIMethod: remove
-     *
+     * 
      * Parameters:
      * node - {DOMElement} The node to be removed.
      */
@@ -7537,8 +8112,8 @@
             // from the indeces hash.
             this.order.splice(arrayIndex, 1);
             delete this.indices[nodeId];
-
-            // Reset the maxium z-index based on the last item in the
+            
+            // Reset the maxium z-index based on the last item in the 
             // order array.
             if (this.order.length > 0) {
                 var lastId = this.order[this.order.length - 1];
@@ -7548,7 +8123,7 @@
             }
         }
     },
-
+    
     /**
      * APIMethod: clear
      */
@@ -7557,7 +8132,7 @@
         this.indices = {};
         this.maxZIndex = 0;
     },
-
+    
     /**
      * APIMethod: exists
      *
@@ -7574,29 +8149,29 @@
     /**
      * APIMethod: getZIndex
      * Get the z-index value for the current node from the node data itself.
-     *
+     * 
      * Parameters:
      * node - {DOMElement} The node whose z-index to get.
-     *
+     * 
      * Returns:
-     * {Integer} The z-index value for the specified node (from the node
+     * {Integer} The z-index value for the specified node (from the node 
      *     data itself).
      */
     getZIndex: function(node) {
-        return node._style.graphicZIndex;
+        return node._style.graphicZIndex;  
     },
-
+    
     /**
      * Method: determineZIndex
-     * Determine the z-index for the current node if there isn't one,
+     * Determine the z-index for the current node if there isn't one, 
      *     and set the maximum value if we've found a new maximum.
-     *
+     * 
      * Parameters:
-     * node - {DOMElement}
+     * node - {DOMElement} 
      */
     determineZIndex: function(node) {
         var zIndex = node._style.graphicZIndex;
-
+        
         // Everything must have a zIndex. If none is specified,
         // this means the user *must* (hint: assumption) want this
         // node to succomb to drawing order. To enforce drawing order
@@ -7604,7 +8179,7 @@
         // greater than any currently in the indexer.
         if (zIndex == null) {
             zIndex = this.maxZIndex;
-            node._style.graphicZIndex = zIndex;
+            node._style.graphicZIndex = zIndex; 
         } else if (zIndex > this.maxZIndex) {
             this.maxZIndex = zIndex;
         }
@@ -7613,50 +8188,50 @@
     /**
      * APIMethod: getNextElement
      * Get the next element in the order stack.
-     *
+     * 
      * Parameters:
      * index - {Integer} The index of the current node in this.order.
-     *
+     * 
      * Returns:
      * {DOMElement} the node following the index passed in, or
      *     null.
      */
     getNextElement: function(index) {
         var nextIndex = index + 1;
-        if (nextIndex < this.order.length){
+        if (nextIndex < this.order.length) {
             var nextElement = OpenLayers.Util.getElement(this.order[nextIndex]);
-            if (nextElement == undefined){
-              nextElement = this.getNextElement(nextIndex);
+            if (nextElement == undefined) {
+                nextElement = this.getNextElement(nextIndex);
             }
             return nextElement;
         } else {
             return null;
-        }
+        } 
     },
-
+    
     CLASS_NAME: "OpenLayers.ElementsIndexer"
 });
 
 /**
  * Namespace: OpenLayers.ElementsIndexer.IndexingMethods
- * These are the compare methods for figuring out where a new node should be
- *     placed within the indexer. These methods are very similar to general
- *     sorting methods in that they return -1, 0, and 1 to specify the
+ * These are the compare methods for figuring out where a new node should be 
+ *     placed within the indexer. These methods are very similar to general 
+ *     sorting methods in that they return -1, 0, and 1 to specify the 
  *     direction in which new nodes fall in the ordering.
  */
 OpenLayers.ElementsIndexer.IndexingMethods = {
-
+    
     /**
      * Method: Z_ORDER
      * This compare method is used by other comparison methods.
      *     It can be used individually for ordering, but is not recommended,
      *     because it doesn't subscribe to drawing order.
-     *
+     * 
      * Parameters:
      * indexer - {<OpenLayers.ElementsIndexer>}
      * newNode - {DOMElement}
      * nextNode - {DOMElement}
-     *
+     * 
      * Returns:
      * {Integer}
      */
@@ -7666,93 +8241,90 @@
         var returnVal = 0;
         if (nextNode) {
             var nextZIndex = indexer.getZIndex(nextNode);
-            returnVal = newZIndex - nextZIndex;
+            returnVal = newZIndex - nextZIndex; 
         }
-
+        
         return returnVal;
     },
 
     /**
      * APIMethod: Z_ORDER_DRAWING_ORDER
      * This method orders nodes by their z-index, but does so in a way
-     *     that, if there are other nodes with the same z-index, the newest
-     *     drawn will be the front most within that z-index. This is the
+     *     that, if there are other nodes with the same z-index, the newest 
+     *     drawn will be the front most within that z-index. This is the 
      *     default indexing method.
-     *
+     * 
      * Parameters:
      * indexer - {<OpenLayers.ElementsIndexer>}
      * newNode - {DOMElement}
      * nextNode - {DOMElement}
-     *
+     * 
      * Returns:
      * {Integer}
      */
     Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) {
         var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(
-            indexer,
-            newNode,
+            indexer, 
+            newNode, 
             nextNode
         );
-
+        
         // Make Z_ORDER subscribe to drawing order by pushing it above
         // all of the other nodes with the same z-index.
         if (nextNode && returnVal == 0) {
             returnVal = 1;
         }
-
+        
         return returnVal;
     },
 
     /**
      * APIMethod: Z_ORDER_Y_ORDER
      * This one should really be called Z_ORDER_Y_ORDER_DRAWING_ORDER, as it
-     *     best describes which ordering methods have precedence (though, the
-     *     name would be too long). This method orders nodes by their z-index,
-     *     but does so in a way that, if there are other nodes with the same
-     *     z-index, the nodes with the lower y position will be "closer" than
-     *     those with a higher y position. If two nodes have the exact same y
-     *     position, however, then this method will revert to using drawing
+     *     best describes which ordering methods have precedence (though, the 
+     *     name would be too long). This method orders nodes by their z-index, 
+     *     but does so in a way that, if there are other nodes with the same 
+     *     z-index, the nodes with the lower y position will be "closer" than 
+     *     those with a higher y position. If two nodes have the exact same y 
+     *     position, however, then this method will revert to using drawing  
      *     order to decide placement.
-     *
+     * 
      * Parameters:
      * indexer - {<OpenLayers.ElementsIndexer>}
      * newNode - {DOMElement}
      * nextNode - {DOMElement}
-     *
+     * 
      * Returns:
      * {Integer}
      */
     Z_ORDER_Y_ORDER: function(indexer, newNode, nextNode) {
         var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(
-            indexer,
-            newNode,
+            indexer, 
+            newNode, 
             nextNode
         );
-
-        if (nextNode && returnVal == 0) {
-            var newLat = newNode._geometry.getBounds().bottom;
-            var nextLat = nextNode._geometry.getBounds().bottom;
-
-            var result = nextLat - newLat;
-            returnVal = (result ==0) ? 1 : result;
+        
+        if (nextNode && returnVal === 0) {            
+            var result = nextNode._boundsBottom - newNode._boundsBottom;
+            returnVal = (result === 0) ? 1 : result;
         }
-
-        return returnVal;
+        
+        return returnVal;       
     }
 };
 
 /**
  * Class: OpenLayers.Renderer.Elements
- * This is another virtual class in that it should never be instantiated by
- *  itself as a Renderer. It exists because there is *tons* of shared
+ * This is another virtual class in that it should never be instantiated by 
+ *  itself as a Renderer. It exists because there is *tons* of shared 
  *  functionality between different vector libraries which use nodes/elements
- *  as a base for rendering vectors.
- *
- * The highlevel bits of code that are implemented here are the adding and
- *  removing of geometries, which is essentially the same for any
+ *  as a base for rendering vectors. 
+ * 
+ * The highlevel bits of code that are implemented here are the adding and 
+ *  removing of geometries, which is essentially the same for any 
  *  element-based renderer. The details of creating each node and drawing the
- *  paths are of course different, but the machinery is the same.
- *
+ *  paths are of course different, but the machinery is the same. 
+ * 
  * Inherits:
  *  - <OpenLayers.Renderer>
  */
@@ -7763,13 +8335,13 @@
      * {DOMElement}
      */
     rendererRoot: null,
-
+    
     /**
      * Property: root
      * {DOMElement}
      */
     root: null,
-
+    
     /**
      * Property: vectorRoot
      * {DOMElement}
@@ -7785,44 +8357,32 @@
     /**
      * Property: xmlns
      * {String}
-     */
+     */    
     xmlns: null,
-
+    
     /**
      * Property: Indexer
-     * {<OpenLayers.ElementIndexer>} An instance of OpenLayers.ElementsIndexer
+     * {<OpenLayers.ElementIndexer>} An instance of OpenLayers.ElementsIndexer 
      *     created upon initialization if the zIndexing or yOrdering options
      *     passed to this renderer's constructor are set to true.
      */
-    indexer: null,
-
+    indexer: null, 
+    
     /**
      * Constant: BACKGROUND_ID_SUFFIX
      * {String}
      */
     BACKGROUND_ID_SUFFIX: "_background",
-
+    
     /**
      * Constant: BACKGROUND_ID_SUFFIX
      * {String}
      */
     LABEL_ID_SUFFIX: "_label",
-
+    
     /**
-     * Property: minimumSymbolizer
-     * {Object}
-     */
-    minimumSymbolizer: {
-        strokeLinecap: "round",
-        strokeOpacity: 1,
-        strokeDashstyle: "solid",
-        fillOpacity: 1,
-        pointRadius: 0
-    },
-
-    /**
      * Constructor: OpenLayers.Renderer.Elements
-     *
+     * 
      * Parameters:
      * containerID - {String}
      * options - {Object} options for this renderer. Supported options are:
@@ -7837,24 +8397,24 @@
         this.root = this.createRoot("_root");
         this.vectorRoot = this.createRoot("_vroot");
         this.textRoot = this.createRoot("_troot");
-
+        
         this.root.appendChild(this.vectorRoot);
         this.root.appendChild(this.textRoot);
-
+        
         this.rendererRoot.appendChild(this.root);
         this.container.appendChild(this.rendererRoot);
-
+        
         if(options && (options.zIndexing || options.yOrdering)) {
             this.indexer = new OpenLayers.ElementsIndexer(options.yOrdering);
         }
     },
-
+    
     /**
      * Method: destroy
      */
     destroy: function() {
 
-        this.clear();
+        this.clear(); 
 
         this.rendererRoot = null;
         this.root = null;
@@ -7862,20 +8422,23 @@
 
         OpenLayers.Renderer.prototype.destroy.apply(this, arguments);
     },
-
+    
     /**
      * Method: clear
      * Remove all the elements from the root
-     */
+     */    
     clear: function() {
-        if (this.vectorRoot) {
-            while (this.vectorRoot.childNodes.length > 0) {
-                this.vectorRoot.removeChild(this.vectorRoot.firstChild);
+        var child;
+        var root = this.vectorRoot;
+        if (root) {
+            while (child = root.firstChild) {
+                root.removeChild(child);
             }
         }
-        if (this.textRoot) {
-            while (this.textRoot.childNodes.length > 0) {
-                this.textRoot.removeChild(this.textRoot.firstChild);
+        root = this.textRoot;
+        if (root) {
+            while (child = root.firstChild) {
+                root.removeChild(child);
             }
         }
         if (this.indexer) {
@@ -7883,26 +8446,26 @@
         }
     },
 
-    /**
+    /** 
      * Method: getNodeType
      * This function is in charge of asking the specific renderer which type
      *     of node to create for the given geometry and style. All geometries
      *     in an Elements-based renderer consist of one node and some
      *     attributes. We have the nodeFactory() function which creates a node
      *     for us, but it takes a 'type' as input, and that is precisely what
-     *     this function tells us.
-     *
+     *     this function tells us.  
+     *  
      * Parameters:
      * geometry - {<OpenLayers.Geometry>}
      * style - {Object}
-     *
+     * 
      * Returns:
      * {String} The corresponding node type for the specified geometry
      */
     getNodeType: function(geometry, style) { },
 
-    /**
-     * Method: drawGeometry
+    /** 
+     * Method: drawGeometry 
      * Draw the geometry, creating new nodes, setting paths, setting style,
      *     setting featureId on the node.  This method should only be called
      *     by the renderer itself.
@@ -7911,7 +8474,7 @@
      * geometry - {<OpenLayers.Geometry>}
      * style - {Object}
      * featureId - {String}
-     *
+     * 
      * Returns:
      * {Boolean} true if the geometry has been drawn completely; null if
      *     incomplete; false otherwise
@@ -7951,27 +8514,28 @@
         }
         return rendered;
     },
-
+    
     /**
      * Method: redrawNode
-     *
+     * 
      * Parameters:
      * id - {String}
      * geometry - {<OpenLayers.Geometry>}
      * style - {Object}
      * featureId - {String}
-     *
+     * 
      * Returns:
      * {Boolean} true if the complete geometry could be drawn, null if parts of
      *     the geometry could not be drawn, false otherwise
      */
     redrawNode: function(id, geometry, style, featureId) {
+        style = this.applyDefaultSymbolizer(style);
         // Get the node if it's already on the map.
         var node = this.nodeFactory(id, this.getNodeType(geometry, style));
-
+        
         // Set the data for the node, then draw it.
         node._featureId = featureId;
-        node._geometry = geometry;
+        node._boundsBottom = geometry.getBounds().bottom;
         node._geometryClass = geometry.CLASS_NAME;
         node._style = style;
 
@@ -7979,9 +8543,9 @@
         if(drawResult === false) {
             return false;
         }
-
+         
         node = drawResult.node;
-
+        
         // Insert the node into the indexer so it can show us where to
         // place it. Note that this operation is O(log(n)). If there's a
         // performance problem (when dragging, for instance) this is
@@ -7996,39 +8560,39 @@
         } else {
             // if there's no indexer, simply append the node to root,
             // but only if the node is a new one
-            if (node.parentNode !== this.vectorRoot){
+            if (node.parentNode !== this.vectorRoot){ 
                 this.vectorRoot.appendChild(node);
             }
         }
-
+        
         this.postDraw(node);
-
+        
         return drawResult.complete;
     },
-
+    
     /**
      * Method: redrawBackgroundNode
      * Redraws the node using special 'background' style properties. Basically
-     *     just calls redrawNode(), but instead of directly using the
-     *     'externalGraphic', 'graphicXOffset', 'graphicYOffset', and
-     *     'graphicZIndex' properties directly from the specified 'style'
-     *     parameter, we create a new style object and set those properties
-     *     from the corresponding 'background'-prefixed properties from
+     *     just calls redrawNode(), but instead of directly using the 
+     *     'externalGraphic', 'graphicXOffset', 'graphicYOffset', and 
+     *     'graphicZIndex' properties directly from the specified 'style' 
+     *     parameter, we create a new style object and set those properties 
+     *     from the corresponding 'background'-prefixed properties from 
      *     specified 'style' parameter.
-     *
+     * 
      * Parameters:
      * id - {String}
      * geometry - {<OpenLayers.Geometry>}
      * style - {Object}
      * featureId - {String}
-     *
+     * 
      * Returns:
      * {Boolean} true if the complete geometry could be drawn, null if parts of
      *     the geometry could not be drawn, false otherwise
      */
     redrawBackgroundNode: function(id, geometry, style, featureId) {
         var backgroundStyle = OpenLayers.Util.extend({}, style);
-
+        
         // Set regular style attributes to apply to the background styles.
         backgroundStyle.externalGraphic = backgroundStyle.backgroundGraphic;
         backgroundStyle.graphicXOffset = backgroundStyle.backgroundXOffset;
@@ -8036,17 +8600,17 @@
         backgroundStyle.graphicZIndex = backgroundStyle.backgroundGraphicZIndex;
         backgroundStyle.graphicWidth = backgroundStyle.backgroundWidth || backgroundStyle.graphicWidth;
         backgroundStyle.graphicHeight = backgroundStyle.backgroundHeight || backgroundStyle.graphicHeight;
-
+        
         // Erase background styles.
         backgroundStyle.backgroundGraphic = null;
         backgroundStyle.backgroundXOffset = null;
         backgroundStyle.backgroundYOffset = null;
         backgroundStyle.backgroundGraphicZIndex = null;
-
+        
         return this.redrawNode(
-            id + this.BACKGROUND_ID_SUFFIX,
-            geometry,
-            backgroundStyle,
+            id + this.BACKGROUND_ID_SUFFIX, 
+            geometry, 
+            backgroundStyle, 
             null
         );
     },
@@ -8061,7 +8625,7 @@
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
      * style - {Object}
-     *
+     * 
      * Returns:
      * {Object} a hash with properties "node" (the drawn node) and "complete"
      *     (null if parts of the geometry could not be drawn, false if nothing
@@ -8069,7 +8633,6 @@
      */
     drawGeometryNode: function(node, geometry, style) {
         style = style || node._style;
-        OpenLayers.Util.applyDefaults(style, this.minimumSymbolizer);
 
         var options = {
             'isFilled': style.fill === undefined ?
@@ -8108,8 +8671,7 @@
                 break;
         }
 
-        node._style = style;
-        node._options = options;
+        node._options = options; 
 
         //set style
         //TBD simplify this
@@ -8122,129 +8684,129 @@
             return false;
         }
     },
-
+    
     /**
      * Method: postDraw
      * Things that have do be done after the geometry node is appended
      *     to its parent node. To be overridden by subclasses.
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
      */
     postDraw: function(node) {},
-
+    
     /**
      * Method: drawPoint
-     * Virtual function for drawing Point Geometry.
+     * Virtual function for drawing Point Geometry. 
      *     Should be implemented by subclasses.
      *     This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or false if the renderer could not draw the point
-     */
+     */ 
     drawPoint: function(node, geometry) {},
 
     /**
      * Method: drawLineString
-     * Virtual function for drawing LineString Geometry.
+     * Virtual function for drawing LineString Geometry. 
      *     Should be implemented by subclasses.
      *     This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or null if the renderer could not draw all components of
      *     the linestring, or false if nothing could be drawn
-     */
+     */ 
     drawLineString: function(node, geometry) {},
 
     /**
      * Method: drawLinearRing
-     * Virtual function for drawing LinearRing Geometry.
+     * Virtual function for drawing LinearRing Geometry. 
      *     Should be implemented by subclasses.
      *     This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or null if the renderer could not draw all components
      *     of the linear ring, or false if nothing could be drawn
-     */
+     */ 
     drawLinearRing: function(node, geometry) {},
 
     /**
      * Method: drawPolygon
-     * Virtual function for drawing Polygon Geometry.
+     * Virtual function for drawing Polygon Geometry. 
      *    Should be implemented by subclasses.
      *    This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or null if the renderer could not draw all components
      *     of the polygon, or false if nothing could be drawn
-     */
+     */ 
     drawPolygon: function(node, geometry) {},
 
     /**
      * Method: drawRectangle
-     * Virtual function for drawing Rectangle Geometry.
+     * Virtual function for drawing Rectangle Geometry. 
      *     Should be implemented by subclasses.
      *     This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or false if the renderer could not draw the rectangle
-     */
+     */ 
     drawRectangle: function(node, geometry) {},
 
     /**
      * Method: drawCircle
-     * Virtual function for drawing Circle Geometry.
+     * Virtual function for drawing Circle Geometry. 
      *     Should be implemented by subclasses.
      *     This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or false if the renderer could not draw the circle
-     */
+     */ 
     drawCircle: function(node, geometry) {},
 
     /**
      * Method: drawSurface
-     * Virtual function for drawing Surface Geometry.
+     * Virtual function for drawing Surface Geometry. 
      *     Should be implemented by subclasses.
      *     This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or false if the renderer could not draw the surface
-     */
+     */ 
     drawSurface: function(node, geometry) {},
 
     /**
      * Method: removeText
      * Removes a label
-     *
+     * 
      * Parameters:
      * featureId - {String}
      */
@@ -8257,12 +8819,12 @@
 
     /**
      * Method: getFeatureIdFromEvent
-     *
+     * 
      * Parameters:
      * evt - {Object} An <OpenLayers.Event> object
      *
      * Returns:
-     * {<OpenLayers.Geometry>} A geometry from an event that
+     * {<OpenLayers.Geometry>} A geometry from an event that 
      *     happened on a layer.
      */
     getFeatureIdFromEvent: function(evt) {
@@ -8273,25 +8835,26 @@
         return featureId;
     },
 
-    /**
+    /** 
      * Method: eraseGeometry
-     * Erase a geometry from the renderer. In the case of a multi-geometry,
-     *     we cycle through and recurse on ourselves. Otherwise, we look for a
+     * Erase a geometry from the renderer. In the case of a multi-geometry, 
+     *     we cycle through and recurse on ourselves. Otherwise, we look for a 
      *     node with the geometry.id, destroy its geometry, and remove it from
      *     the DOM.
-     *
+     * 
      * Parameters:
      * geometry - {<OpenLayers.Geometry>}
+     * featureId - {String}
      */
-    eraseGeometry: function(geometry) {
+    eraseGeometry: function(geometry, featureId) {
         if ((geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPoint") ||
             (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiLineString") ||
             (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPolygon") ||
             (geometry.CLASS_NAME == "OpenLayers.Geometry.Collection")) {
             for (var i=0, len=geometry.components.length; i<len; i++) {
-                this.eraseGeometry(geometry.components[i]);
+                this.eraseGeometry(geometry.components[i], featureId);
             }
-        } else {
+        } else {    
             var element = OpenLayers.Util.getElement(geometry.id);
             if (element && element.parentNode) {
                 if (element.geometry) {
@@ -8303,7 +8866,7 @@
                 if (this.indexer) {
                     this.indexer.remove(element);
                 }
-
+                
                 if (element._style.backgroundGraphic) {
                     var backgroundId = geometry.id + this.BACKGROUND_ID_SUFFIX;
                     var bElem = OpenLayers.Util.getElement(backgroundId);
@@ -8317,17 +8880,17 @@
         }
     },
 
-    /**
+    /** 
      * Method: nodeFactory
      * Create new node of the specified type, with the (optional) specified id.
-     *
+     * 
      * If node already exists with same ID and a different type, we remove it
      *     and then call ourselves again to recreate it.
-     *
+     * 
      * Parameters:
      * id - {String}
      * type - {String} type Kind of node to draw.
-     *
+     * 
      * Returns:
      * {DOMElement} A new node of the given type and id.
      */
@@ -8343,27 +8906,27 @@
         }
         return node;
     },
-
-    /**
+    
+    /** 
      * Method: nodeTypeCompare
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
      * type - {String} Kind of node
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the specified node is of the specified type
      *     This function must be overridden by subclasses.
      */
     nodeTypeCompare: function(node, type) {},
-
-    /**
+    
+    /** 
      * Method: createNode
-     *
+     * 
      * Parameters:
      * type - {String} Kind of node to draw.
      * id - {String} Id for node.
-     *
+     * 
      * Returns:
      * {DOMElement} A new node of the given type and id.
      *     This function must be overridden by subclasses.
@@ -8373,7 +8936,7 @@
     /**
      * Method: moveRoot
      * moves this renderer's root to a different renderer.
-     *
+     * 
      * Parameters:
      * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
      */
@@ -8385,27 +8948,27 @@
         root.parentNode.removeChild(root);
         renderer.rendererRoot.appendChild(root);
     },
-
+    
     /**
      * Method: getRenderLayerId
      * Gets the layer that this renderer's output appears on. If moveRoot was
      * used, this will be different from the id of the layer containing the
      * features rendered by this renderer.
-     *
+     * 
      * Returns:
      * {String} the id of the output layer.
      */
     getRenderLayerId: function() {
         return this.root.parentNode.parentNode.id;
     },
-
+    
     /**
      * Method: isComplexSymbol
      * Determines if a symbol cannot be rendered using drawCircle
-     *
+     * 
      * Parameters:
      * graphicName - {String}
-     *
+     * 
      * Returns
      * {Boolean} true if the symbol is complex, false if not
      */
@@ -8434,8 +8997,9 @@
     OpenLayers/Strategy/Fixed.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -8450,12 +9014,12 @@
  *  - <OpenLayers.Strategy>
  */
 OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, {
-
+    
     /**
      * APIProperty: preload
      * {Boolean} Load data before layer made visible. Enabling this may result
      *   in considerable overhead if your application loads many data layers
-     *   that are not visible by default. Default is true.
+     *   that are not visible by default. Default is false.
      */
     preload: false,
 
@@ -8505,11 +9069,11 @@
         }
         return false;
     },
-
+    
     /**
      * Method: deactivate
      * Deactivate the strategy.  Undo what is done in <activate>.
-     *
+     * 
      * Returns:
      * {Boolean} The strategy was successfully deactivated.
      */
@@ -8536,6 +9100,7 @@
         this.layer.events.triggerEvent("loadstart");
         this.layer.protocol.read(OpenLayers.Util.applyDefaults({
             callback: this.merge,
+            filter: this.layer.filter,
             scope: this
         }, options));
         this.layer.events.un({
@@ -8571,11 +9136,422 @@
     CLASS_NAME: "OpenLayers.Strategy.Fixed"
 });
 /* ======================================================================
+    OpenLayers/Symbolizer/Line.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Line
+ * A symbolizer used to render line features.
+ */
+OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, {
+
+    /**
+     * APIProperty: strokeColor
+     * {String} Color for line stroke.  This is a RGB hex value (e.g. "#ff0000"
+     *     for red).
+     */
+    strokeColor: null,
+    
+    /**
+     * APIProperty: strokeOpacity
+     * {Number} Stroke opacity (0-1).
+     */
+    strokeOpacity: null,
+    
+    /**
+     * APIProperty: strokeWidth
+     * {Number} Pixel stroke width.
+     */
+    strokeWidth: null,
+    
+    /**
+     * APIProperty: strokeLinecap
+     * {String} Stroke cap type ("butt", "round", or "square").
+     */
+    strokeLinecap: null,
+    
+    /**
+     * Property: strokeDashstyle
+     * {String} Stroke dash style according to the SLD spec. Note that the
+     *     OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot",
+     *     "longdash", "longdashdot", or "solid") will not work in SLD, but
+     *     most SLD patterns will render correctly in OpenLayers.
+     */
+    strokeDashstyle: null,
+
+    /**
+     * Constructor: OpenLayers.Symbolizer.Line
+     * Create a symbolizer for rendering lines.
+     *
+     * Parameters:
+     * config - {Object} An object containing properties to be set on the 
+     *     symbolizer.  Any documented symbolizer property can be set at 
+     *     construction.
+     *
+     * Returns:
+     * A new line symbolizer.
+     */
+    initialize: function(config) {
+        OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+    },
+    
+    CLASS_NAME: "OpenLayers.Symbolizer.Line"
+    
+});
+
+/* ======================================================================
+    OpenLayers/Symbolizer/Point.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Point
+ * A symbolizer used to render point features.
+ */
+OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, {
+    
+    /**
+     * APIProperty: strokeColor
+     * {String} Color for line stroke.  This is a RGB hex value (e.g. "#ff0000"
+     *     for red).
+     */
+    strokeColor: null,
+    
+    /**
+     * APIProperty: strokeOpacity
+     * {Number} Stroke opacity (0-1).
+     */
+    strokeOpacity: null,
+    
+    /**
+     * APIProperty: strokeWidth
+     * {Number} Pixel stroke width.
+     */
+    strokeWidth: null,
+    
+    /**
+     * APIProperty: strokeLinecap
+     * {String} Stroke cap type ("butt", "round", or "square").
+     */
+    strokeLinecap: null,
+    
+    /**
+     * Property: strokeDashstyle
+     * {String} Stroke dash style according to the SLD spec. Note that the
+     *     OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot",
+     *     "longdash", "longdashdot", or "solid") will not work in SLD, but
+     *     most SLD patterns will render correctly in OpenLayers.
+     */
+    strokeDashstyle: null,
+
+    /**
+     * APIProperty: fillColor
+     * {String} RGB hex fill color (e.g. "#ff0000" for red).
+     */
+    fillColor: null,
+    
+    /**
+     * APIProperty: fillOpacity
+     * {Number} Fill opacity (0-1).
+     */
+    fillOpacity: null, 
+
+    /**
+     * APIProperty: pointRadius
+     * {Number} Pixel point radius.
+     */
+    pointRadius: null,
+
+    /**
+     * APIProperty: externalGraphic
+     * {String} Url to an external graphic that will be used for rendering 
+     *     points.
+     */
+    externalGraphic: null,
+    
+    /**
+     * APIProperty: graphicWidth
+     * {Number} Pixel width for sizing an external graphic.
+     */
+    graphicWidth: null,
+    
+    /**
+     * APIProperty: graphicHeight
+     * {Number} Pixel height for sizing an external graphic.
+     */
+    graphicHeight: null,
+    
+    /**
+     * APIProperty: graphicOpacity
+     * {Number} Opacity (0-1) for an external graphic.
+     */
+    graphicOpacity: null,
+    
+    /**
+     * APIProperty: graphicXOffset
+     * {Number} Pixel offset along the positive x axis for displacing an 
+     *     external graphic.
+     */
+    graphicXOffset: null,
+    
+    /**
+     * APIProperty: graphicYOffset
+     * {Number} Pixel offset along the positive y axis for displacing an 
+     *     external graphic.
+     */
+    graphicYOffset: null,
+
+    /**
+     * APIProperty: rotation
+     * {Number} The rotation of a graphic in the clockwise direction about its 
+     *     center point (or any point off center as specified by 
+     *     <graphicXOffset> and <graphicYOffset>).
+     */
+    rotation: null,
+    
+    /**
+     * APIProperty: graphicName
+     * {String} Named graphic to use when rendering points.  Supported values 
+     *     include "circle", "square", "star", "x", "cross", and "triangle".
+     */
+    graphicName: null,
+    
+    /**
+     * Constructor: OpenLayers.Symbolizer.Point
+     * Create a symbolizer for rendering points.
+     *
+     * Parameters:
+     * config - {Object} An object containing properties to be set on the 
+     *     symbolizer.  Any documented symbolizer property can be set at 
+     *     construction.
+     *
+     * Returns:
+     * A new point symbolizer.
+     */
+    initialize: function(config) {
+        OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+    },
+    
+    CLASS_NAME: "OpenLayers.Symbolizer.Point"
+    
+});
+
+/* ======================================================================
+    OpenLayers/Symbolizer/Polygon.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Polygon
+ * A symbolizer used to render line features.
+ */
+OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, {
+    
+    /**
+     * APIProperty: strokeColor
+     * {String} Color for line stroke.  This is a RGB hex value (e.g. "#ff0000"
+     *     for red).
+     */
+    strokeColor: null,
+    
+    /**
+     * APIProperty: strokeOpacity
+     * {Number} Stroke opacity (0-1).
+     */
+    strokeOpacity: null,
+    
+    /**
+     * APIProperty: strokeWidth
+     * {Number} Pixel stroke width.
+     */
+    strokeWidth: null,
+    
+    /**
+     * APIProperty: strokeLinecap
+     * {String} Stroke cap type ("butt", "round", or "square").
+     */
+    strokeLinecap: null,
+    
+    /**
+     * Property: strokeDashstyle
+     * {String} Stroke dash style according to the SLD spec. Note that the
+     *     OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot",
+     *     "longdash", "longdashdot", or "solid") will not work in SLD, but
+     *     most SLD patterns will render correctly in OpenLayers.
+     */
+    strokeDashstyle: null,
+
+    /**
+     * APIProperty: fillColor
+     * {String} RGB hex fill color (e.g. "#ff0000" for red).
+     */
+    fillColor: null,
+    
+    /**
+     * APIProperty: fillOpacity
+     * {Number} Fill opacity (0-1).
+     */
+    fillOpacity: null, 
+
+    /**
+     * Constructor: OpenLayers.Symbolizer.Polygon
+     * Create a symbolizer for rendering polygons.
+     *
+     * Parameters:
+     * config - {Object} An object containing properties to be set on the 
+     *     symbolizer.  Any documented symbolizer property can be set at 
+     *     construction.
+     *
+     * Returns:
+     * A new polygon symbolizer.
+     */
+    initialize: function(config) {
+        OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+    },
+    
+    CLASS_NAME: "OpenLayers.Symbolizer.Polygon"
+    
+});
+
+/* ======================================================================
+    OpenLayers/Symbolizer/Raster.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Raster
+ * A symbolizer used to render raster images.
+ */
+OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, {
+    
+    /**
+     * Constructor: OpenLayers.Symbolizer.Raster
+     * Create a symbolizer for rendering rasters.
+     *
+     * Parameters:
+     * config - {Object} An object containing properties to be set on the 
+     *     symbolizer.  Any documented symbolizer property can be set at 
+     *     construction.
+     *
+     * Returns:
+     * A new raster symbolizer.
+     */
+    initialize: function(config) {
+        OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+    },
+    
+    CLASS_NAME: "OpenLayers.Symbolizer.Raster"
+    
+});
+/* ======================================================================
+    OpenLayers/Symbolizer/Text.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Text
+ * A symbolizer used to render text labels for features.
+ */
+OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, {
+    
+    /** 
+     * APIProperty: label
+     * {String} The text for the label.
+     */
+    label: null,
+    
+    /** 
+     * APIProperty: fontFamily
+     * {String} The font family for the label.
+     */
+    fontFamily: null,
+
+    /** 
+     * APIProperty: fontSize
+     * {String} The font size for the label.
+     */
+    fontSize: null,
+
+    /** 
+     * APIProperty: fontWeight
+     * {String} The font weight for the label.
+     */
+    fontWeight: null,
+    
+    /**
+     * Property: fontStyle
+     * {String} The font style for the label.
+     */
+    fontStyle: null,
+
+    /**
+     * Constructor: OpenLayers.Symbolizer.Text
+     * Create a symbolizer for rendering text labels.
+     *
+     * Parameters:
+     * config - {Object} An object containing properties to be set on the 
+     *     symbolizer.  Any documented symbolizer property can be set at 
+     *     construction.
+     *
+     * Returns:
+     * A new text symbolizer.
+     */
+    initialize: function(config) {
+        OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+    },
+    
+    CLASS_NAME: "OpenLayers.Symbolizer.Text"
+    
+});
+
+/* ======================================================================
     OpenLayers/Tween.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -8586,38 +9562,38 @@
  * Namespace: OpenLayers.Tween
  */
 OpenLayers.Tween = OpenLayers.Class({
-
+    
     /**
      * Constant: INTERVAL
      * {int} Interval in milliseconds between 2 steps
      */
     INTERVAL: 10,
-
+    
     /**
      * APIProperty: easing
      * {<OpenLayers.Easing>(Function)} Easing equation used for the animation
      *     Defaultly set to OpenLayers.Easing.Expo.easeOut
      */
     easing: null,
-
+    
     /**
      * APIProperty: begin
      * {Object} Values to start the animation with
      */
     begin: null,
-
+    
     /**
      * APIProperty: finish
      * {Object} Values to finish the animation with
      */
     finish: null,
-
+    
     /**
      * APIProperty: duration
      * {int} duration of the tween (number of steps)
      */
     duration: null,
-
+    
     /**
      * APIProperty: callbacks
      * {Object} An object with start, eachStep and done properties whose values
@@ -8625,40 +9601,40 @@
      *     current computed value as argument.
      */
     callbacks: null,
-
+    
     /**
      * Property: time
      * {int} Step counter
      */
     time: null,
-
+    
     /**
      * Property: interval
      * {int} Interval id returned by window.setInterval
      */
     interval: null,
-
+    
     /**
      * Property: playing
      * {Boolean} Tells if the easing is currently playing
      */
     playing: false,
-
-    /**
+    
+    /** 
      * Constructor: OpenLayers.Tween
      * Creates a Tween.
      *
      * Parameters:
      * easing - {<OpenLayers.Easing>(Function)} easing function method to use
-     */
+     */ 
     initialize: function(easing) {
         this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
     },
-
+    
     /**
      * APIMethod: start
      * Plays the Tween, and calls the callback method on each step
-     *
+     * 
      * Parameters:
      * begin - {Object} values to start the animation with
      * finish - {Object} values to finish the animation with
@@ -8682,7 +9658,7 @@
         this.interval = window.setInterval(
             OpenLayers.Function.bind(this.play, this), this.INTERVAL);
     },
-
+    
     /**
      * APIMethod: stop
      * Stops the Tween, and calls the done callback
@@ -8692,7 +9668,7 @@
         if (!this.playing) {
             return;
         }
-
+        
         if (this.callbacks && this.callbacks.done) {
             this.callbacks.done.call(this, this.finish);
         }
@@ -8700,7 +9676,7 @@
         this.interval = null;
         this.playing = false;
     },
-
+    
     /**
      * Method: play
      * Calls the appropriate easing method
@@ -8713,26 +9689,21 @@
             if (b == null || f == null || isNaN(b) || isNaN(f)) {
                 OpenLayers.Console.error('invalid value for Tween');
             }
-
+            
             var c = f - b;
             value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
         }
         this.time++;
-
+        
         if (this.callbacks && this.callbacks.eachStep) {
             this.callbacks.eachStep.call(this, value);
         }
-
+        
         if (this.time > this.duration) {
-            if (this.callbacks && this.callbacks.done) {
-                this.callbacks.done.call(this, this.finish);
-                this.playing = false;
-            }
-            window.clearInterval(this.interval);
-            this.interval = null;
+            this.stop();
         }
     },
-
+    
     /**
      * Create empty functions for all easing methods.
      */
@@ -8741,7 +9712,7 @@
 
 /**
  * Namespace: OpenLayers.Easing
- *
+ * 
  * Credits:
  *      Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
  */
@@ -8756,10 +9727,10 @@
  * Namespace: OpenLayers.Easing.Linear
  */
 OpenLayers.Easing.Linear = {
-
+    
     /**
      * Function: easeIn
-     *
+     * 
      * Parameters:
      * t - {Float} time
      * b - {Float} beginning position
@@ -8769,10 +9740,10 @@
     easeIn: function(t, b, c, d) {
         return c*t/d + b;
     },
-
+    
     /**
      * Function: easeOut
-     *
+     * 
      * Parameters:
      * t - {Float} time
      * b - {Float} beginning position
@@ -8782,10 +9753,10 @@
     easeOut: function(t, b, c, d) {
         return c*t/d + b;
     },
-
+    
     /**
      * Function: easeInOut
-     *
+     * 
      * Parameters:
      * t - {Float} time
      * b - {Float} beginning position
@@ -8803,10 +9774,10 @@
  * Namespace: OpenLayers.Easing.Expo
  */
 OpenLayers.Easing.Expo = {
-
+    
     /**
      * Function: easeIn
-     *
+     * 
      * Parameters:
      * t - {Float} time
      * b - {Float} beginning position
@@ -8816,10 +9787,10 @@
     easeIn: function(t, b, c, d) {
         return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
     },
-
+    
     /**
      * Function: easeOut
-     *
+     * 
      * Parameters:
      * t - {Float} time
      * b - {Float} beginning position
@@ -8829,10 +9800,10 @@
     easeOut: function(t, b, c, d) {
         return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
     },
-
+    
     /**
      * Function: easeInOut
-     *
+     * 
      * Parameters:
      * t - {Float} time
      * b - {Float} beginning position
@@ -8853,10 +9824,10 @@
  * Namespace: OpenLayers.Easing.Quad
  */
 OpenLayers.Easing.Quad = {
-
+    
     /**
      * Function: easeIn
-     *
+     * 
      * Parameters:
      * t - {Float} time
      * b - {Float} beginning position
@@ -8866,10 +9837,10 @@
     easeIn: function(t, b, c, d) {
         return c*(t/=d)*t + b;
     },
-
+    
     /**
      * Function: easeOut
-     *
+     * 
      * Parameters:
      * t - {Float} time
      * b - {Float} beginning position
@@ -8879,10 +9850,10 @@
     easeOut: function(t, b, c, d) {
         return -c *(t/=d)*(t-2) + b;
     },
-
+    
     /**
      * Function: easeInOut
-     *
+     * 
      * Parameters:
      * t - {Float} time
      * b - {Float} beginning position
@@ -8900,8 +9871,9 @@
     OpenLayers/Control/ArgParser.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -8911,11 +9883,11 @@
 
 /**
  * Class: OpenLayers.Control.ArgParser
- * The ArgParser control adds location bar querystring parsing functionality
+ * The ArgParser control adds location bar querystring parsing functionality 
  * to an OpenLayers Map.
- * When added to a Map control, on a page load/refresh, the Map will
- * automatically take the href string and parse it for lon, lat, zoom, and
- * layers information.
+ * When added to a Map control, on a page load/refresh, the Map will 
+ * automatically take the href string and parse it for lon, lat, zoom, and 
+ * layers information. 
  *
  * Inherits from:
  *  - <OpenLayers.Control>
@@ -8927,7 +9899,7 @@
      * {<OpenLayers.LonLat>}
      */
     center: null,
-
+    
     /**
      * Parameter: zoom
      * {int}
@@ -8935,14 +9907,14 @@
     zoom: null,
 
     /**
-     * Parameter: layers
+     * Parameter: layers 
      * {Array(<OpenLayers.Layer>)}
      */
     layers: null,
-
-    /**
+    
+    /** 
      * APIProperty: displayProjection
-     * {<OpenLayers.Projection>} Requires proj4js support.
+     * {<OpenLayers.Projection>} Requires proj4js support. 
      *     Projection used when reading the coordinates from the URL. This will
      *
      *     reproject the map coordinates from the URL into the map's
@@ -8951,9 +9923,9 @@
      *     If you are using this functionality, be aware that any permalink
      *     which is added to the map will determine the coordinate type which
      *     is read from the URL, which means you should not add permalinks with
-     *     different displayProjections to the same map.
+     *     different displayProjections to the same map. 
      */
-    displayProjection: null,
+    displayProjection: null, 
 
     /**
      * Constructor: OpenLayers.Control.ArgParser
@@ -8967,10 +9939,10 @@
 
     /**
      * Method: setMap
-     * Set the map property for the control.
-     *
+     * Set the map property for the control. 
+     * 
      * Parameters:
-     * map - {<OpenLayers.Map>}
+     * map - {<OpenLayers.Map>} 
      */
     setMap: function(map) {
         OpenLayers.Control.prototype.setMap.apply(this, arguments);
@@ -8980,14 +9952,14 @@
             var control = this.map.controls[i];
             if ( (control != this) &&
                  (control.CLASS_NAME == "OpenLayers.Control.ArgParser") ) {
-
-                // If a second argparser is added to the map, then we
+                
+                // If a second argparser is added to the map, then we 
                 // override the displayProjection to be the one added to the
-                // map.
+                // map. 
                 if (control.displayProjection != this.displayProjection) {
                     this.displayProjection = control.displayProjection;
-                }
-
+                }    
+                
                 break;
             }
         }
@@ -8997,9 +9969,9 @@
             // Be careful to set layer first, to not trigger unnecessary layer loads
             if (args.layers) {
                 this.layers = args.layers;
-
-                // when we add a new layer, set its visibility
-                this.map.events.register('addlayer', this,
+    
+                // when we add a new layer, set its visibility 
+                this.map.events.register('addlayer', this, 
                                          this.configureLayers);
                 this.configureLayers();
             }
@@ -9009,51 +9981,51 @@
                 if (args.zoom) {
                     this.zoom = parseInt(args.zoom);
                 }
-
+    
                 // when we add a new baselayer to see when we can set the center
-                this.map.events.register('changebaselayer', this,
+                this.map.events.register('changebaselayer', this, 
                                          this.setCenter);
                 this.setCenter();
             }
         }
     },
-
-    /**
+   
+    /** 
      * Method: setCenter
      * As soon as a baseLayer has been loaded, we center and zoom
      *   ...and remove the handler.
      */
     setCenter: function() {
-
+        
         if (this.map.baseLayer) {
             //dont need to listen for this one anymore
-            this.map.events.unregister('changebaselayer', this,
+            this.map.events.unregister('changebaselayer', this, 
                                        this.setCenter);
-
+            
             if (this.displayProjection) {
-                this.center.transform(this.displayProjection,
-                                      this.map.getProjectionObject());
-            }
+                this.center.transform(this.displayProjection, 
+                                      this.map.getProjectionObject()); 
+            }      
 
             this.map.setCenter(this.center, this.zoom);
         }
     },
 
-    /**
+    /** 
      * Method: configureLayers
-     * As soon as all the layers are loaded, cycle through them and
-     *   hide or show them.
+     * As soon as all the layers are loaded, cycle through them and 
+     *   hide or show them. 
      */
     configureLayers: function() {
 
-        if (this.layers.length == this.map.layers.length) {
+        if (this.layers.length == this.map.layers.length) { 
             this.map.events.unregister('addlayer', this, this.configureLayers);
 
             for(var i=0, len=this.layers.length; i<len; i++) {
-
+                
                 var layer = this.map.layers[i];
                 var c = this.layers.charAt(i);
-
+                
                 if (c == "B") {
                     this.map.setBaseLayer(layer);
                 } else if ( (c == "T") || (c == "F") ) {
@@ -9061,7 +10033,7 @@
                 }
             }
         }
-    },
+    },     
 
     CLASS_NAME: "OpenLayers.Control.ArgParser"
 });
@@ -9069,8 +10041,9 @@
     OpenLayers/Control/PanZoom.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -9089,38 +10062,38 @@
  */
 OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, {
 
-    /**
+    /** 
      * APIProperty: slideFactor
-     * {Integer} Number of pixels by which we'll pan the map in any direction
+     * {Integer} Number of pixels by which we'll pan the map in any direction 
      *     on clicking the arrow buttons.  If you want to pan by some ratio
      *     of the map dimensions, use <slideRatio> instead.
      */
     slideFactor: 50,
 
-    /**
+    /** 
      * APIProperty: slideRatio
-     * {Number} The fraction of map width/height by which we'll pan the map
+     * {Number} The fraction of map width/height by which we'll pan the map            
      *     on clicking the arrow buttons.  Default is null.  If set, will
      *     override <slideFactor>. E.g. if slideRatio is .5, then the Pan Up
-     *     button will pan up half the map height.
+     *     button will pan up half the map height. 
      */
     slideRatio: null,
 
-    /**
+    /** 
      * Property: buttons
-     * {Array(DOMElement)} Array of Button Divs
+     * {Array(DOMElement)} Array of Button Divs 
      */
     buttons: null,
 
-    /**
+    /** 
      * Property: position
-     * {<OpenLayers.Pixel>}
+     * {<OpenLayers.Pixel>} 
      */
     position: null,
 
     /**
      * Constructor: OpenLayers.Control.PanZoom
-     *
+     * 
      * Parameters:
      * options - {Object}
      */
@@ -9144,8 +10117,8 @@
      * Method: draw
      *
      * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     *
+     * px - {<OpenLayers.Pixel>} 
+     * 
      * Returns:
      * {DOMElement} A reference to the container div for the PanZoom control.
      */
@@ -9164,26 +10137,26 @@
         px.y = centered.y+sz.h;
         this._addButton("panleft", "west-mini.png", px, sz);
         this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz);
-        this._addButton("pandown", "south-mini.png",
+        this._addButton("pandown", "south-mini.png", 
                         centered.add(0, sz.h*2), sz);
-        this._addButton("zoomin", "zoom-plus-mini.png",
+        this._addButton("zoomin", "zoom-plus-mini.png", 
                         centered.add(0, sz.h*3+5), sz);
-        this._addButton("zoomworld", "zoom-world-mini.png",
+        this._addButton("zoomworld", "zoom-world-mini.png", 
                         centered.add(0, sz.h*4+5), sz);
-        this._addButton("zoomout", "zoom-minus-mini.png",
+        this._addButton("zoomout", "zoom-minus-mini.png", 
                         centered.add(0, sz.h*5+5), sz);
         return this.div;
     },
-
+    
     /**
      * Method: _addButton
-     *
+     * 
      * Parameters:
-     * id - {String}
-     * img - {String}
-     * xy - {<OpenLayers.Pixel>}
-     * sz - {<OpenLayers.Size>}
-     *
+     * id - {String} 
+     * img - {String} 
+     * xy - {<OpenLayers.Pixel>} 
+     * sz - {<OpenLayers.Size>} 
+     * 
      * Returns:
      * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the
      *     image of the button, and has all the proper event handlers set.
@@ -9191,21 +10164,21 @@
     _addButton:function(id, img, xy, sz) {
         var imgLocation = OpenLayers.Util.getImagesLocation() + img;
         var btn = OpenLayers.Util.createAlphaImageDiv(
-                                    this.id + "_" + id,
+                                    this.id + "_" + id, 
                                     xy, sz, imgLocation, "absolute");
 
         //we want to add the outer div
         this.div.appendChild(btn);
 
-        OpenLayers.Event.observe(btn, "mousedown",
+        OpenLayers.Event.observe(btn, "mousedown", 
             OpenLayers.Function.bindAsEventListener(this.buttonDown, btn));
-        OpenLayers.Event.observe(btn, "dblclick",
+        OpenLayers.Event.observe(btn, "dblclick", 
             OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
-        OpenLayers.Event.observe(btn, "click",
+        OpenLayers.Event.observe(btn, "click", 
             OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
         btn.action = id;
         btn.map = this.map;
-
+    
         if(!this.slideRatio){
             var slideFactorPixels = this.slideFactor;
             var getSlideFactor = function() {
@@ -9224,20 +10197,21 @@
         this.buttons.push(btn);
         return btn;
     },
-
+    
     /**
      * Method: _removeButton
-     *
+     * 
      * Parameters:
      * btn - {Object}
      */
     _removeButton: function(btn) {
         OpenLayers.Event.stopObservingElement(btn);
         btn.map = null;
+        btn.getSlideFactor = null;
         this.div.removeChild(btn);
         OpenLayers.Util.removeItem(this.buttons, btn);
     },
-
+    
     /**
      * Method: removeButtons
      */
@@ -9246,12 +10220,12 @@
             this._removeButton(this.buttons[i]);
         }
     },
-
+    
     /**
      * Method: doubleClick
      *
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      *
      * Returns:
      * {Boolean}
@@ -9260,12 +10234,12 @@
         OpenLayers.Event.stop(evt);
         return false;
     },
-
+    
     /**
      * Method: buttonDown
      *
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     buttonDown: function (evt) {
         if (!OpenLayers.Event.isLeftClick(evt)) {
@@ -9273,26 +10247,26 @@
         }
 
         switch (this.action) {
-            case "panup":
+            case "panup": 
                 this.map.pan(0, -this.getSlideFactor("h"));
                 break;
-            case "pandown":
+            case "pandown": 
                 this.map.pan(0, this.getSlideFactor("h"));
                 break;
-            case "panleft":
+            case "panleft": 
                 this.map.pan(-this.getSlideFactor("w"), 0);
                 break;
-            case "panright":
+            case "panright": 
                 this.map.pan(this.getSlideFactor("w"), 0);
                 break;
-            case "zoomin":
-                this.map.zoomIn();
+            case "zoomin": 
+                this.map.zoomIn(); 
                 break;
-            case "zoomout":
-                this.map.zoomOut();
+            case "zoomout": 
+                this.map.zoomOut(); 
                 break;
-            case "zoomworld":
-                this.map.zoomToMaxExtent();
+            case "zoomworld": 
+                this.map.zoomToMaxExtent(); 
                 break;
         }
 
@@ -9317,9 +10291,10 @@
     OpenLayers/Control/ScaleLine.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
 
 /**
  * @requires OpenLayers/Control.js
@@ -9327,13 +10302,13 @@
 
 /**
  * Class: OpenLayers.Control.ScaleLine
- * The ScaleLine displays a small line indicator representing the current
+ * The ScaleLine displays a small line indicator representing the current 
  * map scale on the map. By default it is drawn in the lower left corner of
  * the map.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Control>
- *
+ *  
  * Is a very close copy of:
  *  - <OpenLayers.Control.Scale>
  */
@@ -9350,7 +10325,7 @@
      * {String} Units for zoomed out on top bar.  Default is km.
      */
     topOutUnits: "km",
-
+    
     /**
      * Property: topInUnits
      * {String} Units for zoomed in on top bar.  Default is m.
@@ -9368,7 +10343,7 @@
      * {String} Units for zoomed in on bottom bar.  Default is ft.
      */
     bottomInUnits: "ft",
-
+    
     /**
      * Property: eTop
      * {DOMElement}
@@ -9380,31 +10355,37 @@
      * {DOMElement}
      */
     eBottom:null,
+    
+    /**
+     * APIProperty: geodesic
+     * {Boolean} Use geodesic measurement. Default is false. The recommended
+     * setting for maps in EPSG:4326 is false, and true EPSG:900913. If set to
+     * true, the scale will be calculated based on the horizontal size of the
+     * pixel in the center of the map viewport.
+     */
+    geodesic: false,
 
     /**
      * Constructor: OpenLayers.Control.ScaleLine
      * Create a new scale line control.
-     *
+     * 
      * Parameters:
      * options - {Object} An optional object whose properties will be used
      *     to extend the control.
      */
     initialize: function(options) {
-        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);     
     },
 
     /**
      * Method: draw
-     *
+     * 
      * Returns:
      * {DOMElement}
      */
     draw: function() {
         OpenLayers.Control.prototype.draw.apply(this, arguments);
         if (!this.eTop) {
-            this.div.style.display = "block";
-            this.div.style.position = "absolute";
-
             // stick in the top bar
             this.eTop = document.createElement("div");
             this.eTop.className = this.displayClass + "Top";
@@ -9431,14 +10412,14 @@
         return this.div;
     },
 
-    /**
+    /** 
      * Method: getBarLen
      * Given a number, round it down to the nearest 1,2,5 times a power of 10.
      * That seems a fairly useful set of number groups to use.
-     *
+     * 
      * Parameters:
      * maxLen - {float}  the number we're rounding down from
-     *
+     * 
      * Returns:
      * {Float} the rounded number (less than or equal to maxLen)
      */
@@ -9446,7 +10427,7 @@
         // nearest power of 10 lower than maxLen
         var digits = parseInt(Math.log(maxLen) / Math.log(10));
         var pow10 = Math.pow(10, digits);
-
+        
         // ok, find first character
         var firstChar = parseInt(maxLen / pow10);
 
@@ -9479,8 +10460,16 @@
 
         // convert maxWidth to map units
         var maxSizeData = this.maxWidth * res * inches[curMapUnits];
+        var geodesicRatio = 1;
+        if(this.geodesic === true) {
+            var maxSizeGeodesic = (this.map.getGeodesicPixelSize().w ||
+                0.000001) * this.maxWidth;
+            var maxSizeKilometers = maxSizeData / inches["km"];
+            geodesicRatio = maxSizeGeodesic / maxSizeKilometers;
+            maxSizeData *= geodesicRatio;
+        }
 
-        // decide whether to use large or small scale units
+        // decide whether to use large or small scale units     
         var topUnits;
         var bottomUnits;
         if(maxSizeData > 100000) {
@@ -9504,24 +10493,24 @@
         bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits];
 
         // and to pixel units
-        var topPx = topMax / res;
-        var bottomPx = bottomMax / res;
-
+        var topPx = topMax / res / geodesicRatio;
+        var bottomPx = bottomMax / res / geodesicRatio;
+        
         // now set the pixel widths
         // and the values inside them
-
+        
         if (this.eBottom.style.visibility == "visible"){
-            this.eBottom.style.width = Math.round(bottomPx) + "px";
+            this.eBottom.style.width = Math.round(bottomPx) + "px"; 
             this.eBottom.innerHTML = bottomRounded + " " + bottomUnits ;
         }
-
+            
         if (this.eTop.style.visibility == "visible"){
             this.eTop.style.width = Math.round(topPx) + "px";
             this.eTop.innerHTML = topRounded + " " + topUnits;
         }
+        
+    }, 
 
-    },
-
     CLASS_NAME: "OpenLayers.Control.ScaleLine"
 });
 
@@ -9529,8 +10518,9 @@
     OpenLayers/Events.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -9544,64 +10534,64 @@
  */
 OpenLayers.Event = {
 
-    /**
-     * Property: observers
+    /** 
+     * Property: observers 
      * {Object} A hashtable cache of the event observers. Keyed by
-     * element._eventCacheID
+     * element._eventCacheID 
      */
     observers: false,
-
-    /**
-     * Constant: KEY_BACKSPACE
-     * {int}
+    
+    /** 
+     * Constant: KEY_BACKSPACE 
+     * {int} 
      */
     KEY_BACKSPACE: 8,
 
-    /**
-     * Constant: KEY_TAB
-     * {int}
+    /** 
+     * Constant: KEY_TAB 
+     * {int} 
      */
     KEY_TAB: 9,
 
-    /**
-     * Constant: KEY_RETURN
-     * {int}
+    /** 
+     * Constant: KEY_RETURN 
+     * {int} 
      */
     KEY_RETURN: 13,
 
-    /**
-     * Constant: KEY_ESC
-     * {int}
+    /** 
+     * Constant: KEY_ESC 
+     * {int} 
      */
     KEY_ESC: 27,
 
-    /**
-     * Constant: KEY_LEFT
-     * {int}
+    /** 
+     * Constant: KEY_LEFT 
+     * {int} 
      */
     KEY_LEFT: 37,
 
-    /**
-     * Constant: KEY_UP
-     * {int}
+    /** 
+     * Constant: KEY_UP 
+     * {int} 
      */
     KEY_UP: 38,
 
-    /**
-     * Constant: KEY_RIGHT
-     * {int}
+    /** 
+     * Constant: KEY_RIGHT 
+     * {int} 
      */
     KEY_RIGHT: 39,
 
-    /**
-     * Constant: KEY_DOWN
-     * {int}
+    /** 
+     * Constant: KEY_DOWN 
+     * {int} 
      */
     KEY_DOWN: 40,
 
-    /**
-     * Constant: KEY_DELETE
-     * {int}
+    /** 
+     * Constant: KEY_DELETE 
+     * {int} 
      */
     KEY_DELETE: 46,
 
@@ -9609,12 +10599,12 @@
     /**
      * Method: element
      * Cross browser event element detection.
-     *
+     * 
      * Parameters:
-     * event - {Event}
-     *
+     * event - {Event} 
+     * 
      * Returns:
-     * {DOMElement} The element that caused the event
+     * {DOMElement} The element that caused the event 
      */
     element: function(event) {
         return event.target || event.srcElement;
@@ -9622,11 +10612,11 @@
 
     /**
      * Method: isLeftClick
-     * Determine whether event was caused by a left click.
+     * Determine whether event was caused by a left click. 
      *
      * Parameters:
-     * event - {Event}
-     *
+     * event - {Event} 
+     * 
      * Returns:
      * {Boolean}
      */
@@ -9637,11 +10627,11 @@
 
     /**
      * Method: isRightClick
-     * Determine whether event was caused by a right mouse click.
+     * Determine whether event was caused by a right mouse click. 
      *
      * Parameters:
-     * event - {Event}
-     *
+     * event - {Event} 
+     * 
      * Returns:
      * {Boolean}
      */
@@ -9649,29 +10639,29 @@
         return (((event.which) && (event.which == 3)) ||
                 ((event.button) && (event.button == 2)));
     },
-
+     
     /**
      * Method: stop
-     * Stops an event from propagating.
+     * Stops an event from propagating. 
      *
-     * Parameters:
-     * event - {Event}
-     * allowDefault - {Boolean} If true, we stop the event chain but
-     *                               still allow the default browser
-     *                               behaviour (text selection, radio-button
+     * Parameters: 
+     * event - {Event} 
+     * allowDefault - {Boolean} If true, we stop the event chain but 
+     *                               still allow the default browser 
+     *                               behaviour (text selection, radio-button 
      *                               clicking, etc)
      *                               Default false
      */
     stop: function(event, allowDefault) {
-
-        if (!allowDefault) {
+        
+        if (!allowDefault) { 
             if (event.preventDefault) {
                 event.preventDefault();
             } else {
                 event.returnValue = false;
             }
         }
-
+                
         if (event.stopPropagation) {
             event.stopPropagation();
         } else {
@@ -9679,13 +10669,13 @@
         }
     },
 
-    /**
+    /** 
      * Method: findElement
-     *
+     * 
      * Parameters:
-     * event - {Event}
-     * tagName - {String}
-     *
+     * event - {Event} 
+     * tagName - {String} 
+     * 
      * Returns:
      * {DOMElement} The first node with the given tagName, starting from the
      * node the event was triggered on and traversing the DOM upwards
@@ -9699,14 +10689,14 @@
         return element;
     },
 
-    /**
+    /** 
      * Method: observe
-     *
+     * 
      * Parameters:
-     * elementParam - {DOMElement || String}
-     * name - {String}
-     * observer - {function}
-     * useCapture - {Boolean}
+     * elementParam - {DOMElement || String} 
+     * name - {String} 
+     * observer - {function} 
+     * useCapture - {Boolean} 
      */
     observe: function(elementParam, name, observer, useCapture) {
         var element = OpenLayers.Util.getElement(elementParam);
@@ -9755,14 +10745,14 @@
         }
     },
 
-    /**
+    /** 
      * Method: stopObservingElement
-     * Given the id of an element to stop observing, cycle through the
-     *   element's cached observers, calling stopObserving on each one,
+     * Given the id of an element to stop observing, cycle through the 
+     *   element's cached observers, calling stopObserving on each one, 
      *   skipping those entries which can no longer be removed.
-     *
+     * 
      * parameters:
-     * elementParam - {DOMElement || String}
+     * elementParam - {DOMElement || String} 
      */
     stopObservingElement: function(elementParam) {
         var element = OpenLayers.Util.getElement(elementParam);
@@ -9775,8 +10765,8 @@
      * Method: _removeElementObservers
      *
      * Parameters:
-     * elementObservers - {Array(Object)} Array of (element, name,
-     *                                         observer, usecapture) objects,
+     * elementObservers - {Array(Object)} Array of (element, name, 
+     *                                         observer, usecapture) objects, 
      *                                         taken directly from hashtable
      */
     _removeElementObservers: function(elementObservers) {
@@ -9794,24 +10784,24 @@
 
     /**
      * Method: stopObserving
-     *
+     * 
      * Parameters:
-     * elementParam - {DOMElement || String}
-     * name - {String}
-     * observer - {function}
-     * useCapture - {Boolean}
-     *
+     * elementParam - {DOMElement || String} 
+     * name - {String} 
+     * observer - {function} 
+     * useCapture - {Boolean} 
+     *  
      * Returns:
      * {Boolean} Whether or not the event observer was removed
      */
     stopObserving: function(elementParam, name, observer, useCapture) {
         useCapture = useCapture || false;
-
+    
         var element = OpenLayers.Util.getElement(elementParam);
         var cacheID = element._eventCacheID;
 
         if (name == 'keypress') {
-            if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) ||
+            if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) || 
                  element.detachEvent) {
               name = 'keydown';
             }
@@ -9821,27 +10811,27 @@
         var foundEntry = false;
         var elementObservers = OpenLayers.Event.observers[cacheID];
         if (elementObservers) {
-
+    
             // find the specific event type in the element's list
             var i=0;
             while(!foundEntry && i < elementObservers.length) {
                 var cacheEntry = elementObservers[i];
-
+    
                 if ((cacheEntry.name == name) &&
                     (cacheEntry.observer == observer) &&
                     (cacheEntry.useCapture == useCapture)) {
-
+    
                     elementObservers.splice(i, 1);
                     if (elementObservers.length == 0) {
                         delete OpenLayers.Event.observers[cacheID];
                     }
                     foundEntry = true;
-                    break;
+                    break; 
                 }
-                i++;
+                i++;           
             }
         }
-
+    
         //actually remove the event listener from browser
         if (foundEntry) {
             if (element.removeEventListener) {
@@ -9852,11 +10842,11 @@
         }
         return foundEntry;
     },
-
-    /**
+    
+    /** 
      * Method: unloadCache
      * Cycle through all the element entries in the events cache and call
-     *   stopObservingElement on each.
+     *   stopObservingElement on each. 
      */
     unloadCache: function() {
         // check for OpenLayers.Event before checking for observers, because
@@ -9865,7 +10855,7 @@
         if (OpenLayers.Event && OpenLayers.Event.observers) {
             for (var cacheID in OpenLayers.Event.observers) {
                 var elementObservers = OpenLayers.Event.observers[cacheID];
-                OpenLayers.Event._removeElementObservers.apply(this,
+                OpenLayers.Event._removeElementObservers.apply(this, 
                                                            [elementObservers]);
             }
             OpenLayers.Event.observers = false;
@@ -9891,65 +10881,65 @@
  */
 OpenLayers.Events = OpenLayers.Class({
 
-    /**
+    /** 
      * Constant: BROWSER_EVENTS
-     * {Array(String)} supported events
+     * {Array(String)} supported events 
      */
     BROWSER_EVENTS: [
         "mouseover", "mouseout",
-        "mousedown", "mouseup", "mousemove",
+        "mousedown", "mouseup", "mousemove", 
         "click", "dblclick", "rightclick", "dblrightclick",
         "resize", "focus", "blur"
     ],
 
-    /**
-     * Property: listeners
-     * {Object} Hashtable of Array(Function): events listener functions
+    /** 
+     * Property: listeners 
+     * {Object} Hashtable of Array(Function): events listener functions  
      */
     listeners: null,
 
-    /**
-     * Property: object
-     * {Object}  the code object issuing application events
+    /** 
+     * Property: object 
+     * {Object}  the code object issuing application events 
      */
     object: null,
 
-    /**
-     * Property: element
-     * {DOMElement}  the DOM element receiving browser events
+    /** 
+     * Property: element 
+     * {DOMElement}  the DOM element receiving browser events 
      */
     element: null,
 
-    /**
-     * Property: eventTypes
-     * {Array(String)}  list of support application events
+    /** 
+     * Property: eventTypes 
+     * {Array(String)}  list of support application events 
      */
     eventTypes: null,
 
-    /**
-     * Property: eventHandler
-     * {Function}  bound event handler attached to elements
+    /** 
+     * Property: eventHandler 
+     * {Function}  bound event handler attached to elements 
      */
     eventHandler: null,
 
-    /**
-     * APIProperty: fallThrough
-     * {Boolean}
+    /** 
+     * APIProperty: fallThrough 
+     * {Boolean} 
      */
     fallThrough: null,
 
-    /**
+    /** 
      * APIProperty: includeXY
      * {Boolean} Should the .xy property automatically be created for browser
      *    mouse events? In general, this should be false. If it is true, then
-     *    mouse events will automatically generate a '.xy' property on the
+     *    mouse events will automatically generate a '.xy' property on the 
      *    event object that is passed. (Prior to OpenLayers 2.7, this was true
      *    by default.) Otherwise, you can call the getMousePosition on the
      *    relevant events handler on the object available via the 'evt.object'
      *    property of the evt object. So, for most events, you can call:
-     *    function named(evt) {
-     *        this.xy = this.object.events.getMousePosition(evt)
-     *    }
+     *    function named(evt) { 
+     *        this.xy = this.object.events.getMousePosition(evt) 
+     *    } 
      *
      *    This option typically defaults to false for performance reasons:
      *    when creating an events object whose primary purpose is to manage
@@ -9959,12 +10949,12 @@
      *    This option is also used to control whether the events object caches
      *    offsets. If this is false, it will not: the reason for this is that
      *    it is only expected to be called many times if the includeXY property
-     *    is set to true. If you set this to true, you are expected to clear
+     *    is set to true. If you set this to true, you are expected to clear 
      *    the offset cache manually (using this.clearMouseCache()) if:
      *        the border of the element changes
      *        the location of the element in the page changes
     */
-    includeXY: false,
+    includeXY: false,      
 
     /**
      * Method: clearMouseListener
@@ -9981,7 +10971,7 @@
      * Parameters:
      * object - {Object} The js object to which this Events object  is being
      * added element - {DOMElement} A dom element to respond to browser events
-     * eventTypes - {Array(String)} Array of custom application events
+     * eventTypes - {Array(String)} Array of custom application events 
      * fallThrough - {Boolean} Allow events to fall through after these have
      *                         been handled?
      * options - {Object} Options for the events object.
@@ -9997,13 +10987,13 @@
         this.eventHandler = OpenLayers.Function.bindAsEventListener(
             this.handleBrowserEvent, this
         );
-
+        
         // to be used with observe and stopObserving
         this.clearMouseListener = OpenLayers.Function.bind(
             this.clearMouseCache, this
         );
 
-        // if eventTypes is specified, create a listeners list for each
+        // if eventTypes is specified, create a listeners list for each 
         // custom application event.
         this.eventTypes = [];
         if (eventTypes != null) {
@@ -10011,8 +11001,8 @@
                 this.addEventType(eventTypes[i]);
             }
         }
-
-        // if a dom element is specified, add a listeners list
+        
+        // if a dom element is specified, add a listeners list 
         // for browser events on the element and register them
         if (element != null) {
             this.attachToElement(element);
@@ -10044,7 +11034,7 @@
      * APIMethod: addEventType
      * Add a new event type to this events object.
      * If the event type has already been added, do nothing.
-     *
+     * 
      * Parameters:
      * eventName - {String}
      */
@@ -10069,28 +11059,41 @@
         for (var i=0, len=this.BROWSER_EVENTS.length; i<len; i++) {
             var eventType = this.BROWSER_EVENTS[i];
 
-            // every browser event has a corresponding application event
+            // every browser event has a corresponding application event 
             // (whether it's listened for or not).
             this.addEventType(eventType);
-
+            
             // use Prototype to register the event cross-browser
             OpenLayers.Event.observe(element, eventType, this.eventHandler);
         }
         // disable dragstart in IE so that mousedown/move/up works normally
         OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
     },
-
+    
     /**
-     * Method: on
+     * APIMethod: on
      * Convenience method for registering listeners with a common scope.
+     *     Internally, this method calls <register> as shown in the examples
+     *     below.
      *
      * Example use:
      * (code)
+     * // register a single listener for the "loadstart" event
+     * events.on({"loadstart", loadStartListener});
+     *
+     * // this is equivalent to the following
+     * events.register("loadstart", undefined, loadStartListener);
+     *
+     * // register multiple listeners to be called with the same `this` object
      * events.on({
      *     "loadstart": loadStartListener,
      *     "loadend": loadEndListener,
      *     scope: object
      * });
+     *
+     * // this is equivalent to the following
+     * events.register("loadstart", object, loadStartListener);
+     * events.register("loadstart", object, loadEndListener);
      * (end)
      */
     on: function(object) {
@@ -10106,31 +11109,31 @@
      * Register an event on the events object.
      *
      * When the event is triggered, the 'func' function will be called, in the
-     * context of 'obj'. Imagine we were to register an event, specifying an
-     * OpenLayers.Bounds Object as 'obj'. When the event is triggered, the
+     * context of 'obj'. Imagine we were to register an event, specifying an 
+     * OpenLayers.Bounds Object as 'obj'. When the event is triggered, the 
      * context in the callback function will be our Bounds object. This means
-     * that within our callback function, we can access the properties and
-     * methods of the Bounds object through the "this" variable. So our
-     * callback could execute something like:
+     * that within our callback function, we can access the properties and 
+     * methods of the Bounds object through the "this" variable. So our 
+     * callback could execute something like: 
      * :    leftStr = "Left: " + this.left;
-     *
+     *   
      *                   or
-     *
+     *  
      * :    centerStr = "Center: " + this.getCenterLonLat();
      *
      * Parameters:
      * type - {String} Name of the event to register
      * obj - {Object} The object to bind the context to for the callback#.
-     *                     If no object is specified, default is the Events's
+     *                     If no object is specified, default is the Events's 
      *                     'object' property.
-     * func - {Function} The callback function. If no callback is
+     * func - {Function} The callback function. If no callback is 
      *                        specified, this function does nothing.
-     *
-     *
+     * 
+     * 
      */
     register: function (type, obj, func) {
 
-        if ( (func != null) &&
+        if ( (func != null) && 
              (OpenLayers.Util.indexOf(this.eventTypes, type) != -1) ) {
 
             if (obj == null)  {
@@ -10145,17 +11148,17 @@
      * APIMethod: registerPriority
      * Same as register() but adds the new listener to the *front* of the
      *     events queue instead of to the end.
-     *
-     *     TODO: get rid of this in 3.0 - Decide whether listeners should be
+     *    
+     *     TODO: get rid of this in 3.0 - Decide whether listeners should be 
      *     called in the order they were registered or in reverse order.
      *
      *
      * Parameters:
      * type - {String} Name of the event to register
      * obj - {Object} The object to bind the context to for the callback#.
-     *                If no object is specified, default is the Events's
+     *                If no object is specified, default is the Events's 
      *                'object' property.
-     * func - {Function} The callback function. If no callback is
+     * func - {Function} The callback function. If no callback is 
      *                   specified, this function does nothing.
      */
     registerPriority: function (type, obj, func) {
@@ -10170,18 +11173,31 @@
             }
         }
     },
-
+    
     /**
-     * Method: un
+     * APIMethod: un
      * Convenience method for unregistering listeners with a common scope.
+     *     Internally, this method calls <unregister> as shown in the examples
+     *     below.
      *
      * Example use:
      * (code)
+     * // unregister a single listener for the "loadstart" event
+     * events.un({"loadstart", loadStartListener});
+     *
+     * // this is equivalent to the following
+     * events.unregister("loadstart", undefined, loadStartListener);
+     *
+     * // unregister multiple listeners with the same `this` object
      * events.un({
      *     "loadstart": loadStartListener,
      *     "loadend": loadEndListener,
      *     scope: object
      * });
+     *
+     * // this is equivalent to the following
+     * events.unregister("loadstart", object, loadStartListener);
+     * events.unregister("loadstart", object, loadEndListener);
      * (end)
      */
     un: function(object) {
@@ -10196,9 +11212,9 @@
      * APIMethod: unregister
      *
      * Parameters:
-     * type - {String}
+     * type - {String} 
      * obj - {Object} If none specified, defaults to this.object
-     * func - {Function}
+     * func - {Function} 
      */
     unregister: function (type, obj, func) {
         if (obj == null)  {
@@ -10215,13 +11231,13 @@
         }
     },
 
-    /**
+    /** 
      * Method: remove
      * Remove all listeners for a given event type. If type is not registered,
      *     does nothing.
      *
      * Parameters:
-     * type - {String}
+     * type - {String} 
      */
     remove: function(type) {
         if (this.listeners[type] != null) {
@@ -10231,10 +11247,10 @@
 
     /**
      * APIMethod: triggerEvent
-     * Trigger a specified registered event.
-     *
+     * Trigger a specified registered event.  
+     * 
      * Parameters:
-     * type - {String}
+     * type - {String} 
      * evt - {Event}
      *
      * Returns:
@@ -10258,7 +11274,7 @@
         if(!evt.type) {
             evt.type = type;
         }
-
+    
         // execute all callbacks registered for specified type
         // get a clone of the listeners array to
         // allow for splicing during callbacks
@@ -10274,7 +11290,7 @@
             }
         }
         // don't fall through to other DOM elements
-        if (!this.fallThrough) {
+        if (!this.fallThrough) {           
             OpenLayers.Event.stop(evt, true);
         }
         return continueChain;
@@ -10282,38 +11298,38 @@
 
     /**
      * Method: handleBrowserEvent
-     * Basically just a wrapper to the triggerEvent() function, but takes
-     *     care to set a property 'xy' on the event with the current mouse
+     * Basically just a wrapper to the triggerEvent() function, but takes 
+     *     care to set a property 'xy' on the event with the current mouse 
      *     position.
      *
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     handleBrowserEvent: function (evt) {
         if (this.includeXY) {
             evt.xy = this.getMousePosition(evt);
-        }
+        } 
         this.triggerEvent(evt.type, evt);
     },
 
     /**
      * APIMethod: clearMouseCache
-     * Clear cached data about the mouse position. This should be called any
-     *     time the element that events are registered on changes position
+     * Clear cached data about the mouse position. This should be called any 
+     *     time the element that events are registered on changes position 
      *     within the page.
      */
-    clearMouseCache: function() {
+    clearMouseCache: function() { 
         this.element.scrolls = null;
         this.element.lefttop = null;
         this.element.offsets = null;
-    },
+    },      
 
     /**
      * Method: getMousePosition
-     *
+     * 
      * Parameters:
-     * evt - {Event}
-     *
+     * evt - {Event} 
+     * 
      * Returns:
      * {<OpenLayers.Pixel>} The current xy coordinate of the mouse, adjusted
      *                      for offsets
@@ -10325,7 +11341,7 @@
             OpenLayers.Event.observe(window, "scroll", this.clearMouseListener);
             this.element.hasScrollEvent = true;
         }
-
+        
         if (!this.element.scrolls) {
             this.element.scrolls = [
                 (document.documentElement.scrollLeft
@@ -10341,7 +11357,7 @@
                 (document.documentElement.clientTop  || 0)
             ];
         }
-
+        
         if (!this.element.offsets) {
             this.element.offsets = OpenLayers.Util.pagePosition(this.element);
             this.element.offsets[0] += this.element.scrolls[0];
@@ -10349,10 +11365,10 @@
         }
         return new OpenLayers.Pixel(
             (evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]
-                         - this.element.lefttop[0],
+                         - this.element.lefttop[0], 
             (evt.clientY + this.element.scrolls[1]) - this.element.offsets[1]
                          - this.element.lefttop[1]
-        );
+        ); 
     },
 
     CLASS_NAME: "OpenLayers.Events"
@@ -10361,8 +11377,9 @@
     OpenLayers/Format.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -10376,13 +11393,13 @@
  *     of OpenLayers.Format are expected to have read and write methods.
  */
 OpenLayers.Format = OpenLayers.Class({
-
+    
     /**
      * Property: options
      * {Object} A reference to options passed to the constructor.
      */
     options: null,
-
+    
     /**
      * APIProperty: externalProjection
      * {<OpenLayers.Projection>} When passed a externalProjection and
@@ -10390,7 +11407,7 @@
      *     reads or writes. The externalProjection is the projection used by
      *     the content which is passed into read or which comes out of write.
      *     In order to reproject, a projection transformation function for the
-     *     specified projections must be available. This support may be
+     *     specified projections must be available. This support may be 
      *     provided via proj4js or via a custom transformation function. See
      *     {<OpenLayers.Projection.addTransform>} for more information on
      *     custom transformations.
@@ -10444,7 +11461,7 @@
         OpenLayers.Util.extend(this, options);
         this.options = options;
     },
-
+    
     /**
      * APIMethod: destroy
      * Clean up.
@@ -10455,8 +11472,8 @@
     /**
      * Method: read
      * Read data from a string, and return an object whose type depends on the
-     * subclass.
-     *
+     * subclass. 
+     * 
      * Parameters:
      * data - {string} Data to read/parse.
      *
@@ -10466,10 +11483,10 @@
     read: function(data) {
         OpenLayers.Console.userError(OpenLayers.i18n("readNotImplemented"));
     },
-
+    
     /**
      * Method: write
-     * Accept an object, and return a string.
+     * Accept an object, and return a string. 
      *
      * Parameters:
      * object - {Object} Object to be serialized
@@ -10482,15 +11499,11 @@
     },
 
     CLASS_NAME: "OpenLayers.Format"
-});
+});     
 /* ======================================================================
     OpenLayers/Lang/en.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
 /**
  * @requires OpenLayers/Lang.js
  */
@@ -10570,6 +11583,13 @@
         "target='_blank'>click here</a>",
 
     'scale': "Scale = 1 : ${scaleDenom}",
+    
+    //labels for the graticule control
+    'W': 'W',
+    'E': 'E',
+    'N': 'N',
+    'S': 'S',
+    'graticule': 'Graticule',
 
     // console message
     'layerAlreadyAdded':
@@ -10579,7 +11599,7 @@
     'reprojectDeprecated':
         "You are using the 'reproject' option " +
         "on the ${layerName} layer. This option is deprecated: " +
-        "its use was designed to support displaying data over commercial " +
+        "its use was designed to support displaying data over commercial " + 
         "basemaps, but that functionality should now be achieved by using " +
         "Spherical Mercator support. More information is available from " +
         "http://trac.openlayers.org/wiki/SphericalMercator.",
@@ -10605,17 +11625,20 @@
     'pagePositionFailed':
         "OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",
 
-    'end': '',
+    // console message
+    'filterEvaluateNotImplemented': "evaluate is not implemented for this filter type.",
 
-    // console message
-    'filterEvaluateNotImplemented': "evaluate is not implemented for this filter type."
+    // **** end ****
+    'end': ''
+    
 };
 /* ======================================================================
     OpenLayers/Popup/AnchoredBubble.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -10625,36 +11648,36 @@
 
 /**
  * Class: OpenLayers.Popup.AnchoredBubble
- *
- * Inherits from:
+ * 
+ * Inherits from: 
  *  - <OpenLayers.Popup.Anchored>
  */
-OpenLayers.Popup.AnchoredBubble =
+OpenLayers.Popup.AnchoredBubble = 
   OpenLayers.Class(OpenLayers.Popup.Anchored, {
 
     /**
      * Property: rounded
      * {Boolean} Has the popup been rounded yet?
      */
-    rounded: false,
-
-    /**
+    rounded: false, 
+    
+    /** 
      * Constructor: OpenLayers.Popup.AnchoredBubble
-     *
+     * 
      * Parameters:
      * id - {String}
      * lonlat - {<OpenLayers.LonLat>}
      * contentSize - {<OpenLayers.Size>}
      * contentHTML - {String}
-     * anchor - {Object} Object to which we'll anchor the popup. Must expose
-     *     a 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>)
+     * anchor - {Object} Object to which we'll anchor the popup. Must expose 
+     *     a 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>) 
      *     (Note that this is generally an <OpenLayers.Icon>).
      * closeBox - {Boolean}
      * closeBoxCallback - {Function} Function to be called on closeBox click.
      */
     initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox,
                         closeBoxCallback) {
-
+        
         this.padding = new OpenLayers.Bounds(
             0, OpenLayers.Popup.AnchoredBubble.CORNER_SIZE,
             0, OpenLayers.Popup.AnchoredBubble.CORNER_SIZE
@@ -10662,23 +11685,23 @@
         OpenLayers.Popup.Anchored.prototype.initialize.apply(this, arguments);
     },
 
-    /**
+    /** 
      * Method: draw
-     *
+     * 
      * Parameters:
      * px - {<OpenLayers.Pixel>}
-     *
+     * 
      * Returns:
      * {DOMElement} Reference to a div that contains the drawn popup.
      */
     draw: function(px) {
-
+        
         OpenLayers.Popup.Anchored.prototype.draw.apply(this, arguments);
 
         this.setContentHTML();
-
-        //set the popup color and opacity
-        this.setBackgroundColor();
+        
+        //set the popup color and opacity           
+        this.setBackgroundColor(); 
         this.setOpacity();
 
         return this.div;
@@ -10695,71 +11718,71 @@
 
     /**
      * APIMethod: setSize
-     *
+     * 
      * Parameters:
-     * contentSize - {<OpenLayers.Size>} the new size for the popup's
+     * contentSize - {<OpenLayers.Size>} the new size for the popup's 
      *     contents div (in pixels).
      */
-    setSize:function(contentSize) {
+    setSize:function(contentSize) { 
         OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments);
 
         this.setRicoCorners();
-    },
+    },  
 
     /**
      * APIMethod: setBackgroundColor
-     *
+     * 
      * Parameters:
      * color - {String}
      */
-    setBackgroundColor:function(color) {
+    setBackgroundColor:function(color) { 
         if (color != undefined) {
-            this.backgroundColor = color;
+            this.backgroundColor = color; 
         }
-
+        
         if (this.div != null) {
             if (this.contentDiv != null) {
                 this.div.style.background = "transparent";
-                OpenLayers.Rico.Corner.changeColor(this.groupDiv,
+                OpenLayers.Rico.Corner.changeColor(this.groupDiv, 
                                                    this.backgroundColor);
             }
         }
-    },
-
+    },  
+    
     /**
      * APIMethod: setOpacity
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * opacity - {float}
      */
-    setOpacity:function(opacity) {
+    setOpacity:function(opacity) { 
         OpenLayers.Popup.Anchored.prototype.setOpacity.call(this, opacity);
-
+        
         if (this.div != null) {
             if (this.groupDiv != null) {
-                OpenLayers.Rico.Corner.changeOpacity(this.groupDiv,
+                OpenLayers.Rico.Corner.changeOpacity(this.groupDiv, 
                                                      this.opacity);
             }
         }
-    },
-
-    /**
+    },  
+ 
+    /** 
      * Method: setBorder
      * Always sets border to 0. Bubble Popups can not have a border.
-     *
+     * 
      * Parameters:
      * border - {Integer}
      */
-    setBorder:function(border) {
+    setBorder:function(border) { 
         this.border = 0;
-    },
-
-    /**
+    },      
+ 
+    /** 
      * Method: setRicoCorners
      * Update RICO corners according to the popup's current relative postion.
      */
     setRicoCorners:function() {
-
+    
         var corners = this.getCornersToRound(this.relativePosition);
         var options = {corners: corners,
                          color: this.backgroundColor,
@@ -10772,14 +11795,14 @@
         } else {
             OpenLayers.Rico.Corner.reRound(this.groupDiv, options);
             //set the popup color and opacity
-            this.setBackgroundColor();
+            this.setBackgroundColor(); 
             this.setOpacity();
         }
     },
 
-    /**
+    /** 
      * Method: getCornersToRound
-     *
+     *  
      * Returns:
      * {String} The proper corners string ("tr tl bl br") for rico to round.
      */
@@ -10787,7 +11810,7 @@
 
         var corners = ['tl', 'tr', 'bl', 'br'];
 
-        //we want to round all the corners _except_ the opposite one.
+        //we want to round all the corners _except_ the opposite one. 
         var corner = OpenLayers.Bounds.oppositeQuadrant(this.relativePosition);
         OpenLayers.Util.removeItem(corners, corner);
 
@@ -10807,9 +11830,10 @@
     OpenLayers/Projection.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
 
 /**
  * @requires OpenLayers/Util.js
@@ -10818,7 +11842,7 @@
 /**
  * Class: OpenLayers.Projection
  * Class for coordinate transforms between coordinate systems.
- *     Depends on the proj4js library. If proj4js is not available,
+ *     Depends on the proj4js library. If proj4js is not available, 
  *     then this is just an empty stub.
  */
 OpenLayers.Projection = OpenLayers.Class({
@@ -10828,7 +11852,7 @@
      * {Object} Proj4js.Proj instance.
      */
     proj: null,
-
+    
     /**
      * Property: projCode
      * {String}
@@ -10837,8 +11861,8 @@
 
     /**
      * Constructor: OpenLayers.Projection
-     * This class offers several methods for interacting with a wrapped
-     *     pro4js projection object.
+     * This class offers several methods for interacting with a wrapped 
+     *     pro4js projection object. 
      *
      * Parameters:
      * projCode - {String} A string identifying the Well Known Identifier for
@@ -10856,7 +11880,7 @@
             this.proj = new Proj4js.Proj(projCode);
         }
     },
-
+    
     /**
      * APIMethod: getCode
      * Get the string SRS code.
@@ -10867,10 +11891,10 @@
     getCode: function() {
         return this.proj ? this.proj.srsCode : this.projCode;
     },
-
+   
     /**
      * APIMethod: getUnits
-     * Get the units string for the projection -- returns null if
+     * Get the units string for the projection -- returns null if 
      *     proj4js is not available.
      *
      * Returns:
@@ -10904,7 +11928,7 @@
             return this.getCode() == projection.getCode();
         } else {
             return false;
-        }
+        }    
     },
 
     /* Method: destroy
@@ -10914,21 +11938,21 @@
         delete this.proj;
         delete this.projCode;
     },
+    
+    CLASS_NAME: "OpenLayers.Projection" 
+});     
 
-    CLASS_NAME: "OpenLayers.Projection"
-});
-
 /**
  * Property: transforms
  * Transforms is an object, with from properties, each of which may
- * have a to property. This allows you to define projections without
+ * have a to property. This allows you to define projections without 
  * requiring support for proj4js to be included.
  *
  * This object has keys which correspond to a 'source' projection object.  The
  * keys should be strings, corresponding to the projection.getCode() value.
  * Each source projection object should have a set of destination projection
- * keys included in the object.
- *
+ * keys included in the object. 
+ * 
  * Each value in the destination object should be a transformation function,
  * where the function is expected to be passed an object with a .x and a .y
  * property.  The function should return the object, with the .x and .y
@@ -10964,7 +11988,7 @@
  * APIMethod: transform
  * Transform a point coordinate from one projection to another.  Note that
  *     the input point is transformed in place.
- *
+ * 
  * Parameters:
  * point - {{OpenLayers.Geometry.Point> | Object} An object with x and y
  *     properties representing coordinates in those dimensions.
@@ -10977,10 +12001,10 @@
 OpenLayers.Projection.transform = function(point, source, dest) {
     if (source.proj && dest.proj) {
         point = Proj4js.transform(source.proj, dest.proj, point);
-    } else if (source && dest &&
-               OpenLayers.Projection.transforms[source.getCode()] &&
+    } else if (source && dest && 
+               OpenLayers.Projection.transforms[source.getCode()] && 
                OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]) {
-        OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point);
+        OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point); 
     }
     return point;
 };
@@ -10988,8 +12012,9 @@
     OpenLayers/Renderer/SVG.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -10998,18 +12023,18 @@
 
 /**
  * Class: OpenLayers.Renderer.SVG
- *
+ * 
  * Inherits:
  *  - <OpenLayers.Renderer.Elements>
  */
 OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
 
-    /**
+    /** 
      * Property: xmlns
      * {String}
      */
     xmlns: "http://www.w3.org/2000/svg",
-
+    
     /**
      * Property: xlinkns
      * {String}
@@ -11018,8 +12043,8 @@
 
     /**
      * Constant: MAX_PIXEL
-     * {Integer} Firefox has a limitation where values larger or smaller than
-     *           about 15000 in an SVG document lock the browser up. This
+     * {Integer} Firefox has a limitation where values larger or smaller than  
+     *           about 15000 in an SVG document lock the browser up. This 
      *           works around it.
      */
     MAX_PIXEL: 15000,
@@ -11029,13 +12054,15 @@
      * {Object} Hash with "x" and "y" properties
      */
     translationParameters: null,
-
+    
     /**
-     * Property: symbolSize
-     * {Object} Cache for symbol sizes according to their svg coordinate space
+     * Property: symbolMetrics
+     * {Object} Cache for symbol metrics according to their svg coordinate
+     *     space. This is an object keyed by the symbol's id, and values are
+     *     an array of [width, centerX, centerY].
      */
-    symbolSize: {},
-
+    symbolMetrics: null,
+    
     /**
      * Property: isGecko
      * {Boolean}
@@ -11043,19 +12070,30 @@
     isGecko: null,
 
     /**
+     * Property: supportUse
+     * {Boolean} true if defs/use is supported - known to not work as expected
+     * at least in some applewebkit/5* builds.
+     * See https://bugs.webkit.org/show_bug.cgi?id=33322
+     */
+    supportUse: null,
+
+    /**
      * Constructor: OpenLayers.Renderer.SVG
-     *
+     * 
      * Parameters:
      * containerID - {String}
      */
     initialize: function(containerID) {
-        if (!this.supported()) {
-            return;
+        if (!this.supported()) { 
+            return; 
         }
-        OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
+        OpenLayers.Renderer.Elements.prototype.initialize.apply(this, 
                                                                 arguments);
         this.translationParameters = {x: 0, y: 0};
+        this.supportUse = (navigator.userAgent.toLowerCase().indexOf("applewebkit/5") == -1);
         this.isGecko = (navigator.userAgent.toLowerCase().indexOf("gecko/") != -1);
+        
+        this.symbolMetrics = {};
     },
 
     /**
@@ -11064,20 +12102,20 @@
     destroy: function() {
         OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments);
     },
-
+    
     /**
      * APIMethod: supported
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the browser supports the SVG renderer
      */
     supported: function() {
         var svgFeature = "http://www.w3.org/TR/SVG11/feature#";
-        return (document.implementation &&
-           (document.implementation.hasFeature("org.w3c.svg", "1.0") ||
-            document.implementation.hasFeature(svgFeature + "SVG", "1.1") ||
+        return (document.implementation && 
+           (document.implementation.hasFeature("org.w3c.svg", "1.0") || 
+            document.implementation.hasFeature(svgFeature + "SVG", "1.1") || 
             document.implementation.hasFeature(svgFeature + "BasicStructure", "1.1") ));
-    },
+    },    
 
     /**
      * Method: inValidRange
@@ -11088,11 +12126,11 @@
      * y      - {Integer}
      * xyOnly - {Boolean} whether or not to just check for x and y, which means
      *     to not take the current translation parameters into account if true.
-     *
+     * 
      * Returns:
-     * {Boolean} Whether or not the 'x' and 'y' coordinates are in the
+     * {Boolean} Whether or not the 'x' and 'y' coordinates are in the  
      *           valid range.
-     */
+     */ 
     inValidRange: function(x, y, xyOnly) {
         var left = x + (xyOnly ? 0 : this.translationParameters.x);
         var top = y + (xyOnly ? 0 : this.translationParameters.y);
@@ -11102,20 +12140,20 @@
 
     /**
      * Method: setExtent
-     *
+     * 
      * Parameters:
      * extent - {<OpenLayers.Bounds>}
      * resolutionChanged - {Boolean}
-     *
+     * 
      * Returns:
      * {Boolean} true to notify the layer that the new extent does not exceed
      *     the coordinate range, and the features will not need to be redrawn.
      *     False otherwise.
      */
     setExtent: function(extent, resolutionChanged) {
-        OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
+        OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, 
                                                                arguments);
-
+        
         var resolution = this.getResolution();
         var left = -extent.left / resolution;
         var top = extent.top / resolution;
@@ -11140,15 +12178,15 @@
             return inRange;
         }
     },
-
+    
     /**
      * Method: translate
      * Transforms the SVG coordinate system
-     *
+     * 
      * Parameters:
      * x - {Float}
      * y - {Float}
-     *
+     * 
      * Returns:
      * {Boolean} true if the translation parameters are in the valid coordinates
      *     range, false otherwise.
@@ -11170,24 +12208,24 @@
     /**
      * Method: setSize
      * Sets the size of the drawing surface.
-     *
+     * 
      * Parameters:
      * size - {<OpenLayers.Size>} The size of the drawing surface
      */
     setSize: function(size) {
         OpenLayers.Renderer.prototype.setSize.apply(this, arguments);
-
+        
         this.rendererRoot.setAttributeNS(null, "width", this.size.w);
         this.rendererRoot.setAttributeNS(null, "height", this.size.h);
     },
 
-    /**
-     * Method: getNodeType
-     *
+    /** 
+     * Method: getNodeType 
+     * 
      * Parameters:
      * geometry - {<OpenLayers.Geometry>}
      * style - {Object}
-     *
+     * 
      * Returns:
      * {String} The corresponding node type for the specified geometry
      */
@@ -11198,7 +12236,7 @@
                 if (style.externalGraphic) {
                     nodeType = "image";
                 } else if (this.isComplexSymbol(style.graphicName)) {
-                    nodeType = "use";
+                    nodeType = this.supportUse === false ? "svg" : "use";
                 } else {
                     nodeType = "circle";
                 }
@@ -11223,17 +12261,17 @@
         return nodeType;
     },
 
-    /**
+    /** 
      * Method: setStyle
      * Use to set all the style attributes to a SVG node.
-     *
+     * 
      * Takes care to adjust stroke width and point radius to be
      * resolution-relative
      *
      * Parameters:
      * node - {SVGDomElement} An SVG element to decorate
      * style - {Object}
-     * options - {Object} Currently supported options include
+     * options - {Object} Currently supported options include 
      *                              'isFilled' {Boolean} and
      *                              'isStroked' {Boolean}
      */
@@ -11249,7 +12287,7 @@
                 node.style.visibility = "hidden";
             } else if (style.externalGraphic) {
                 pos = this.getPosition(node);
-
+                
                 if (style.graphicTitle) {
                     node.setAttributeNS(null, "title", style.graphicTitle);
                 }
@@ -11266,7 +12304,7 @@
                     style.graphicYOffset : -(0.5 * height);
 
                 var opacity = style.graphicOpacity || style.fillOpacity;
-
+                
                 node.setAttributeNS(null, "x", (pos.x + xOffset).toFixed());
                 node.setAttributeNS(null, "y", (pos.y + yOffset).toFixed());
                 node.setAttributeNS(null, "width", width);
@@ -11278,10 +12316,9 @@
                 var offset = style.pointRadius * 3;
                 var size = offset * 2;
                 var id = this.importSymbol(style.graphicName);
-                var href = "#" + id;
                 pos = this.getPosition(node);
-                widthFactor = this.symbolSize[id] / size;
-
+                widthFactor = this.symbolMetrics[id][0] * 3 / size;
+                
                 // remove the node from the dom before we modify it. This
                 // prevents various rendering issues in Safari and FF
                 var parent = node.parentNode;
@@ -11289,13 +12326,23 @@
                 if(parent) {
                     parent.removeChild(node);
                 }
-
-                node.setAttributeNS(this.xlinkns, "href", href);
+                
+                if(this.supportUse === false) {
+                    // workaround for webkit versions that cannot do defs/use
+                    // (see https://bugs.webkit.org/show_bug.cgi?id=33322):
+                    // copy the symbol instead of referencing it
+                    var src = document.getElementById(id);
+                    node.firstChild && node.removeChild(node.firstChild);
+                    node.appendChild(src.firstChild.cloneNode(true));
+                    node.setAttributeNS(null, "viewBox", src.getAttributeNS(null, "viewBox"));
+                } else {
+                    node.setAttributeNS(this.xlinkns, "href", "#" + id);
+                }
                 node.setAttributeNS(null, "width", size);
                 node.setAttributeNS(null, "height", size);
                 node.setAttributeNS(null, "x", pos.x - offset);
                 node.setAttributeNS(null, "y", pos.y - offset);
-
+                
                 // now that the node has all its new properties, insert it
                 // back into the dom where it was
                 if(nextSibling) {
@@ -11307,13 +12354,23 @@
                 node.setAttributeNS(null, "r", style.pointRadius);
             }
 
-            if (typeof style.rotation != "undefined" && pos) {
-                var rotation = OpenLayers.String.format(
-                    "rotate(${0} ${1} ${2})", [style.rotation, pos.x, pos.y]);
-                node.setAttributeNS(null, "transform", rotation);
+            var rotation = style.rotation;
+            if ((rotation !== undefined || node._rotation !== undefined) && pos) {
+                node._rotation = rotation;
+                rotation |= 0;
+                if(node.nodeName !== "svg") {
+                    node.setAttributeNS(null, "transform",
+                        "rotate(" + rotation + " " + pos.x + " " +
+                        pos.y + ")");
+                } else {
+                     var metrics = this.symbolMetrics[id];
+                     node.firstChild.setAttributeNS(null, "transform",
+                     "rotate(" + style.rotation + " " + metrics[1] +
+                         " " +  metrics[2] + ")");
+                }
             }
         }
-
+        
         if (options.isFilled) {
             node.setAttributeNS(null, "fill", style.fillColor);
             node.setAttributeNS(null, "fill-opacity", style.fillOpacity);
@@ -11325,41 +12382,41 @@
             node.setAttributeNS(null, "stroke", style.strokeColor);
             node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity);
             node.setAttributeNS(null, "stroke-width", style.strokeWidth * widthFactor);
-            node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap);
+            node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap || "round");
             // Hard-coded linejoin for now, to make it look the same as in VML.
             // There is no strokeLinejoin property yet for symbolizers.
             node.setAttributeNS(null, "stroke-linejoin", "round");
-            node.setAttributeNS(null, "stroke-dasharray", this.dashStyle(style,
-                widthFactor));
+            style.strokeDashstyle && node.setAttributeNS(null,
+                "stroke-dasharray", this.dashStyle(style, widthFactor));
         } else {
             node.setAttributeNS(null, "stroke", "none");
         }
-
+        
         if (style.pointerEvents) {
             node.setAttributeNS(null, "pointer-events", style.pointerEvents);
         }
-
+                
         if (style.cursor != null) {
             node.setAttributeNS(null, "cursor", style.cursor);
         }
-
+        
         return node;
     },
 
-    /**
+    /** 
      * Method: dashStyle
-     *
+     * 
      * Parameters:
      * style - {Object}
      * widthFactor - {Number}
-     *
+     * 
      * Returns:
      * {String} A SVG compliant 'stroke-dasharray' value
      */
     dashStyle: function(style, widthFactor) {
         var w = style.strokeWidth * widthFactor;
-
-        switch (style.strokeDashstyle) {
+        var str = style.strokeDashstyle;
+        switch (str) {
             case 'solid':
                 return 'none';
             case 'dot':
@@ -11373,17 +12430,17 @@
             case 'longdashdot':
                 return [8 * w, 4 * w, 1, 4 * w].join();
             default:
-                return style.strokeDashstyle.replace(/ /g, ",");
+                return OpenLayers.String.trim(str).replace(/\s+/g, ",");
         }
     },
-
-    /**
+    
+    /** 
      * Method: createNode
-     *
+     * 
      * Parameters:
      * type - {String} Kind of node to draw
      * id - {String} Id for node
-     *
+     * 
      * Returns:
      * {DOMElement} A new node of the given type and id
      */
@@ -11392,26 +12449,26 @@
         if (id) {
             node.setAttributeNS(null, "id", id);
         }
-        return node;
+        return node;    
     },
-
-    /**
+    
+    /** 
      * Method: nodeTypeCompare
-     *
+     * 
      * Parameters:
      * node - {SVGDomElement} An SVG element
      * type - {String} Kind of node
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the specified node is of the specified type
      */
     nodeTypeCompare: function(node, type) {
         return (type == node.nodeName);
     },
-
+   
     /**
      * Method: createRenderRoot
-     *
+     * 
      * Returns:
      * {DOMElement} The specific render engine's root element
      */
@@ -11421,10 +12478,10 @@
 
     /**
      * Method: createRoot
-     *
+     * 
      * Parameter:
      * suffix - {String} suffix to append to the id
-     *
+     * 
      * Returns:
      * {DOMElement}
      */
@@ -11453,14 +12510,14 @@
     /**
      * Method: drawPoint
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or false if the renderer could not draw the point
-     */
+     */ 
     drawPoint: function(node, geometry) {
         return this.drawCircle(node, geometry, 1);
     },
@@ -11468,12 +12525,12 @@
     /**
      * Method: drawCircle
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
      * radius - {Float}
-     *
+     * 
      * Returns:
      * {DOMElement} or false if the renderer could not draw the circle
      */
@@ -11482,73 +12539,73 @@
         var x = (geometry.x / resolution + this.left);
         var y = (this.top - geometry.y / resolution);
 
-        if (this.inValidRange(x, y)) {
+        if (this.inValidRange(x, y)) { 
             node.setAttributeNS(null, "cx", x);
             node.setAttributeNS(null, "cy", y);
             node.setAttributeNS(null, "r", radius);
             return node;
         } else {
             return false;
-        }
-
+        }    
+            
     },
-
+    
     /**
      * Method: drawLineString
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or null if the renderer could not draw all components of
      *     the linestring, or false if nothing could be drawn
-     */
+     */ 
     drawLineString: function(node, geometry) {
         var componentsResult = this.getComponentsString(geometry.components);
         if (componentsResult.path) {
             node.setAttributeNS(null, "points", componentsResult.path);
-            return (componentsResult.complete ? node : null);
+            return (componentsResult.complete ? node : null);  
         } else {
             return false;
         }
     },
-
+    
     /**
      * Method: drawLinearRing
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or null if the renderer could not draw all components
      *     of the linear ring, or false if nothing could be drawn
-     */
+     */ 
     drawLinearRing: function(node, geometry) {
         var componentsResult = this.getComponentsString(geometry.components);
         if (componentsResult.path) {
             node.setAttributeNS(null, "points", componentsResult.path);
-            return (componentsResult.complete ? node : null);
+            return (componentsResult.complete ? node : null);  
         } else {
             return false;
         }
     },
-
+    
     /**
      * Method: drawPolygon
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or null if the renderer could not draw all components
      *     of the polygon, or false if nothing could be drawn
-     */
+     */ 
     drawPolygon: function(node, geometry) {
         var d = "";
         var draw = true;
@@ -11573,26 +12630,26 @@
             return complete ? node : null;
         } else {
             return false;
-        }
+        }    
     },
-
+    
     /**
      * Method: drawRectangle
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or false if the renderer could not draw the rectangle
-     */
+     */ 
     drawRectangle: function(node, geometry) {
         var resolution = this.getResolution();
         var x = (geometry.x / resolution + this.left);
         var y = (this.top - geometry.y / resolution);
 
-        if (this.inValidRange(x, y)) {
+        if (this.inValidRange(x, y)) { 
             node.setAttributeNS(null, "x", x);
             node.setAttributeNS(null, "y", y);
             node.setAttributeNS(null, "width", geometry.width / resolution);
@@ -11602,18 +12659,18 @@
             return false;
         }
     },
-
+    
     /**
      * Method: drawSurface
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or false if the renderer could not draw the surface
-     */
+     */ 
     drawSurface: function(node, geometry) {
 
         // create the svg path string representation
@@ -11640,34 +12697,36 @@
             return node;
         } else {
             return false;
-        }
+        }    
     },
-
+    
     /**
      * Method: drawText
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * featureId - {String}
      * style -
      * location - {<OpenLayers.Geometry.Point>}
      */
     drawText: function(featureId, style, location) {
         var resolution = this.getResolution();
-
+        
         var x = (location.x / resolution + this.left);
         var y = (location.y / resolution - this.top);
-
+        
         var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "text");
         var tspan = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan", "tspan");
 
         label.setAttributeNS(null, "x", x);
         label.setAttributeNS(null, "y", -y);
-        label.setAttributeNS(null, "pointer-events", "none");
-
+        
         if (style.fontColor) {
             label.setAttributeNS(null, "fill", style.fontColor);
         }
+        if (style.fontOpacity) {
+            label.setAttributeNS(null, "opacity", style.fontOpacity);
+        }
         if (style.fontFamily) {
             label.setAttributeNS(null, "font-family", style.fontFamily);
         }
@@ -11677,6 +12736,15 @@
         if (style.fontWeight) {
             label.setAttributeNS(null, "font-weight", style.fontWeight);
         }
+        if(style.labelSelect === true) {
+            label.setAttributeNS(null, "pointer-events", "visible");
+            label._featureId = featureId;
+            tspan._featureId = featureId;
+            tspan._geometry = location;
+            tspan._geometryClass = location.CLASS_NAME;
+        } else {
+            label.setAttributeNS(null, "pointer-events", "none");
+        }
         var align = style.labelAlign || "cm";
         label.setAttributeNS(null, "text-anchor",
             OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] || "middle");
@@ -11690,20 +12758,20 @@
         }
 
         tspan.textContent = style.label;
-
+        
         if(!label.parentNode) {
             label.appendChild(tspan);
             this.textRoot.appendChild(label);
-        }
+        }   
     },
-
-    /**
+    
+    /** 
      * Method: getComponentString
-     *
+     * 
      * Parameters:
      * components - {Array(<OpenLayers.Geometry.Point>)} Array of points
      * separator - {String} character between coordinate pairs. Defaults to ","
-     *
+     * 
      * Returns:
      * {Object} hash with properties "path" (the string created from the
      *     components and "complete" (false if the renderer was unable to
@@ -11714,7 +12782,7 @@
         var complete = true;
         var len = components.length;
         var strings = [];
-        var str, component, j;
+        var str, component;
         for(var i=0; i<len; i++) {
             component = components[i];
             renderCmp.push(component);
@@ -11747,13 +12815,13 @@
             complete: complete
         };
     },
-
+    
     /**
      * Method: clipLine
      * Given two points (one inside the valid range, and one outside),
      * clips the line betweeen the two points so that the new points are both
      * inside the valid range.
-     *
+     * 
      * Parameters:
      * badComponent - {<OpenLayers.Geometry.Point>)} original geometry of the
      *     invalid point
@@ -11789,12 +12857,12 @@
         return x2 + "," + y2;
     },
 
-    /**
+    /** 
      * Method: getShortString
-     *
+     * 
      * Parameters:
      * point - {<OpenLayers.Geometry.Point>}
-     *
+     * 
      * Returns:
      * {String} or false if point is outside the valid range
      */
@@ -11803,20 +12871,20 @@
         var x = (point.x / resolution + this.left);
         var y = (this.top - point.y / resolution);
 
-        if (this.inValidRange(x, y)) {
+        if (this.inValidRange(x, y)) { 
             return x + "," + y;
         } else {
             return false;
         }
     },
-
+    
     /**
      * Method: getPosition
      * Finds the position of an svg node.
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
-     *
+     * 
      * Returns:
      * {Object} hash with x and y properties, representing the coordinates
      *     within the svg coordinate system
@@ -11831,29 +12899,28 @@
     /**
      * Method: importSymbol
      * add a new symbol definition from the rendererer's symbol hash
-     *
+     * 
      * Parameters:
      * graphicName - {String} name of the symbol to import
-     *
+     * 
      * Returns:
      * {String} - id of the imported symbol
-     */
+     */      
     importSymbol: function (graphicName)  {
         if (!this.defs) {
             // create svg defs tag
             this.defs = this.createDefs();
         }
         var id = this.container.id + "-" + graphicName;
-
+        
         // check if symbol already exists in the defs
         if (document.getElementById(id) != null) {
             return id;
         }
-
+        
         var symbol = OpenLayers.Renderer.symbol[graphicName];
         if (!symbol) {
             throw new Error(graphicName + ' is not a valid symbol name');
-            return;
         }
 
         var symbolNode = this.nodeFactory(id, "symbol");
@@ -11862,7 +12929,7 @@
         var symbolExtent = new OpenLayers.Bounds(
                                     Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
 
-        var points = "";
+        var points = [];
         var x,y;
         for (var i=0; i<symbol.length; i=i+2) {
             x = symbol[i];
@@ -11871,11 +12938,11 @@
             symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
             symbolExtent.right = Math.max(symbolExtent.right, x);
             symbolExtent.top = Math.max(symbolExtent.top, y);
-            points += " " + x + "," + y;
+            points.push(x, ",", y);
         }
-
-        node.setAttributeNS(null, "points", points);
-
+        
+        node.setAttributeNS(null, "points", points.join(" "));
+        
         var width = symbolExtent.getWidth();
         var height = symbolExtent.getHeight();
         // create a viewBox three times as large as the symbol itself,
@@ -11883,11 +12950,35 @@
         var viewBox = [symbolExtent.left - width,
                         symbolExtent.bottom - height, width * 3, height * 3];
         symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" "));
-        this.symbolSize[id] = Math.max(width, height) * 3;
-
+        this.symbolMetrics[id] = [
+            Math.max(width, height),
+            symbolExtent.getCenterLonLat().lon,
+            symbolExtent.getCenterLonLat().lat
+        ];
+        
         this.defs.appendChild(symbolNode);
         return symbolNode.id;
     },
+    
+    /**
+     * Method: getFeatureIdFromEvent
+     * 
+     * Parameters:
+     * evt - {Object} An <OpenLayers.Event> object
+     *
+     * Returns:
+     * {<OpenLayers.Geometry>} A geometry from an event that 
+     *     happened on a layer.
+     */
+    getFeatureIdFromEvent: function(evt) {
+        var featureId = OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this, arguments);
+        if(this.supportUse === false && !featureId) {
+            var target = evt.target;
+            featureId = target.parentNode && target != this.rendererRoot &&
+                target.parentNode._featureId;
+        }
+        return featureId;
+    },
 
     CLASS_NAME: "OpenLayers.Renderer.SVG"
 });
@@ -11914,14 +13005,15 @@
     // bottom to the top of the baseline, so -35% moves the text to
     // the center of the baseline.
     "t": "-70%",
-    "b": "0"
+    "b": "0"    
 };
 /* ======================================================================
     OpenLayers/Renderer/VML.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -11932,9 +13024,9 @@
  * Class: OpenLayers.Renderer.VML
  * Render vector features in browsers with VML capability.  Construct a new
  * VML renderer with the <OpenLayers.Renderer.VML> constructor.
- *
- * Note that for all calculations in this class, we use toFixed() to round a
- * float value to an integer. This is done because it seems that VML doesn't
+ * 
+ * Note that for all calculations in this class, we use (num | 0) to truncate a 
+ * float value to an integer. This is done because it seems that VML doesn't 
  * support float values.
  *
  * Inherits from:
@@ -11947,7 +13039,7 @@
      * {String} XML Namespace URN
      */
     xmlns: "urn:schemas-microsoft-com:vml",
-
+    
     /**
      * Property: symbolCache
      * {DOMElement} node holding symbols. This hash is keyed by symbol name,
@@ -11960,7 +13052,7 @@
      * {Object} Hash with "x" and "y" properties
      */
     offset: null,
-
+    
     /**
      * Constructor: OpenLayers.Renderer.VML
      * Create a new VML renderer.
@@ -11969,23 +13061,22 @@
      * containerID - {String} The id for the element that contains the renderer
      */
     initialize: function(containerID) {
-        if (!this.supported()) {
-            return;
+        if (!this.supported()) { 
+            return; 
         }
         if (!document.namespaces.olv) {
             document.namespaces.add("olv", this.xmlns);
             var style = document.createStyleSheet();
-            var shapes = ['shape','rect', 'oval', 'fill', 'stroke', 'imagedata', 'group','textbox'];
+            var shapes = ['shape','rect', 'oval', 'fill', 'stroke', 'imagedata', 'group','textbox']; 
             for (var i = 0, len = shapes.length; i < len; i++) {
 
                 style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " +
                               "position: absolute; display: inline-block;");
-            }
+            }                  
         }
-
-        OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
+        
+        OpenLayers.Renderer.Elements.prototype.initialize.apply(this, 
                                                                 arguments);
-        this.offset = {x: 0, y: 0};
     },
 
     /**
@@ -12005,7 +13096,7 @@
      */
     supported: function() {
         return !!(document.namespaces);
-    },
+    },    
 
     /**
      * Method: setExtent
@@ -12014,19 +13105,19 @@
      * Parameters:
      * extent - {<OpenLayers.Bounds>}
      * resolutionChanged - {Boolean}
-     *
+     * 
      * Returns:
      * {Boolean} true to notify the layer that the new extent does not exceed
      *     the coordinate range, and the features will not need to be redrawn.
      */
     setExtent: function(extent, resolutionChanged) {
-        OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
+        OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, 
                                                                arguments);
         var resolution = this.getResolution();
-
-        var left = extent.left/resolution;
-        var top = extent.top/resolution - this.size.h;
-        if (resolutionChanged) {
+    
+        var left = (extent.left/resolution) | 0;
+        var top = (extent.top/resolution - this.size.h) | 0;
+        if (resolutionChanged || !this.offset) {
             this.offset = {x: left, y: top};
             left = 0;
             top = 0;
@@ -12035,7 +13126,7 @@
             top = top - this.offset.y;
         }
 
-
+        
         var org = left + " " + top;
         this.root.coordorigin = org;
         var roots = [this.root, this.vectorRoot, this.textRoot];
@@ -12045,12 +13136,12 @@
 
             var size = this.size.w + " " + this.size.h;
             root.coordsize = size;
-
+            
         }
-        // flip the VML display Y axis upside down so it
+        // flip the VML display Y axis upside down so it 
         // matches the display Y axis of the map
         this.root.style.flip = "y";
-
+        
         return true;
     },
 
@@ -12064,7 +13155,7 @@
      */
     setSize: function(size) {
         OpenLayers.Renderer.prototype.setSize.apply(this, arguments);
-
+        
         // setting width and height on all roots to avoid flicker which we
         // would get with 100% width and height on child roots
         var roots = [
@@ -12129,7 +13220,7 @@
      * Parameters:
      * node - {DOMElement} An VML element to decorate
      * style - {Object}
-     * options - {Object} Currently supported options include
+     * options - {Object} Currently supported options include 
      *                              'isFilled' {Boolean} and
      *                              'isStroked' {Boolean}
      * geometry - {<OpenLayers.Geometry>}
@@ -12137,13 +13228,13 @@
     setStyle: function(node, style, options, geometry) {
         style = style  || node._style;
         options = options || node._options;
-        var widthFactor = 1;
+        var fillColor = style.fillColor;
 
-        if (node._geometryClass == "OpenLayers.Geometry.Point") {
+        if (node._geometryClass === "OpenLayers.Geometry.Point") {
             if (style.externalGraphic) {
                 if (style.graphicTitle) {
                     node.title=style.graphicTitle;
-                }
+                } 
                 var width = style.graphicWidth || style.graphicHeight;
                 var height = style.graphicHeight || style.graphicWidth;
                 width = width ? width : style.pointRadius*2;
@@ -12154,22 +13245,22 @@
                     style.graphicXOffset : -(0.5 * width);
                 var yOffset = (style.graphicYOffset != undefined) ?
                     style.graphicYOffset : -(0.5 * height);
-
-                node.style.left = ((geometry.x/resolution - this.offset.x)+xOffset).toFixed();
-                node.style.top = ((geometry.y/resolution - this.offset.y)-(yOffset+height)).toFixed();
+                
+                node.style.left = (((geometry.x/resolution - this.offset.x)+xOffset) | 0) + "px";
+                node.style.top = (((geometry.y/resolution - this.offset.y)-(yOffset+height)) | 0) + "px";
                 node.style.width = width + "px";
                 node.style.height = height + "px";
                 node.style.flip = "y";
-
-                // modify style/options for fill and stroke styling below
-                style.fillColor = "none";
+                
+                // modify fillColor and options for stroke styling below
+                fillColor = "none";
                 options.isStroked = false;
             } else if (this.isComplexSymbol(style.graphicName)) {
                 var cache = this.importSymbol(style.graphicName);
                 node.path = cache.path;
                 node.coordorigin = cache.left + "," + cache.bottom;
                 var size = cache.size;
-                node.coordsize = size + "," + size;
+                node.coordsize = size + "," + size;        
                 this.drawCircle(node, geometry, style.pointRadius);
                 node.style.flip = "y";
             } else {
@@ -12177,11 +13268,11 @@
             }
         }
 
-        // fill
-        if (options.isFilled) {
-            node.fillcolor = style.fillColor;
-        } else {
-            node.filled = "false";
+        // fill 
+        if (options.isFilled) { 
+            node.fillcolor = fillColor; 
+        } else { 
+            node.filled = "false"; 
         }
         var fills = node.getElementsByTagName("fill");
         var fill = (fills.length == 0) ? null : fills[0];
@@ -12195,20 +13286,20 @@
             }
             fill.opacity = style.fillOpacity;
 
-            if (node._geometryClass == "OpenLayers.Geometry.Point" &&
+            if (node._geometryClass === "OpenLayers.Geometry.Point" &&
                     style.externalGraphic) {
 
                 // override fillOpacity
                 if (style.graphicOpacity) {
                     fill.opacity = style.graphicOpacity;
                 }
-
+                
                 fill.src = style.externalGraphic;
                 fill.type = "frame";
-
+                
                 if (!(style.graphicWidth && style.graphicHeight)) {
                   fill.aspect = "atmost";
-                }
+                }                
             }
             if (fill.parentNode != node) {
                 node.appendChild(fill);
@@ -12216,42 +13307,45 @@
         }
 
         // additional rendering for rotated graphics or symbols
-        if (typeof style.rotation != "undefined") {
+        var rotation = style.rotation;
+        if ((rotation !== undefined || node._rotation !== undefined)) {
+            node._rotation = rotation;
             if (style.externalGraphic) {
-                this.graphicRotate(node, xOffset, yOffset);
+                this.graphicRotate(node, xOffset, yOffset, style);
                 // make the fill fully transparent, because we now have
                 // the graphic as imagedata element. We cannot just remove
                 // the fill, because this is part of the hack described
                 // in graphicRotate
                 fill.opacity = 0;
-            } else {
-                node.style.rotation = style.rotation;
+            } else if(node._geometryClass === "OpenLayers.Geometry.Point") {
+                node.style.rotation = rotation || 0;
             }
         }
 
-        // stroke
-        if (options.isStroked) {
-            node.strokecolor = style.strokeColor;
-            node.strokeweight = style.strokeWidth + "px";
-        } else {
-            node.stroked = false;
-        }
+        // stroke 
         var strokes = node.getElementsByTagName("stroke");
         var stroke = (strokes.length == 0) ? null : strokes[0];
         if (!options.isStroked) {
+            node.stroked = false;
             if (stroke) {
-                node.removeChild(stroke);
+                stroke.on = false;
             }
         } else {
             if (!stroke) {
                 stroke = this.createNode('olv:stroke', node.id + "_stroke");
                 node.appendChild(stroke);
             }
+            stroke.on = true;
+            stroke.color = style.strokeColor; 
+            stroke.weight = style.strokeWidth + "px"; 
             stroke.opacity = style.strokeOpacity;
-            stroke.endcap = !style.strokeLinecap || style.strokeLinecap == 'butt' ? 'flat' : style.strokeLinecap;
-            stroke.dashstyle = this.dashStyle(style);
+            stroke.endcap = style.strokeLinecap == 'butt' ? 'flat' :
+                (style.strokeLinecap || 'round');
+            if (style.strokeDashstyle) {
+                stroke.dashstyle = this.dashStyle(style);
+            }
         }
-
+        
         if (style.cursor != "inherit" && style.cursor != null) {
             node.style.cursor = style.cursor;
         }
@@ -12271,16 +13365,17 @@
      * insertion point of the rotated image, because DXImageTransform.Matrix
      * does the rotation without the ability to specify a rotation center
      * point.
-     *
+     * 
      * Parameters:
      * node    - {DOMElement}
      * xOffset - {Number} rotation center relative to image, x coordinate
      * yOffset - {Number} rotation center relative to image, y coordinate
+     * style   - {Object}
      */
-    graphicRotate: function(node, xOffset, yOffset) {
+    graphicRotate: function(node, xOffset, yOffset, style) {
         var style = style || node._style;
-        var options = node._options;
-
+        var rotation = style.rotation || 0;
+        
         var aspectRatio, size;
         if (!(style.graphicWidth && style.graphicHeight)) {
             // load the image to determine its size
@@ -12289,29 +13384,29 @@
                 if(img.readyState == "complete" ||
                         img.readyState == "interactive") {
                     aspectRatio = img.width / img.height;
-                    size = Math.max(style.pointRadius * 2,
+                    size = Math.max(style.pointRadius * 2, 
                         style.graphicWidth || 0,
                         style.graphicHeight || 0);
                     xOffset = xOffset * aspectRatio;
                     style.graphicWidth = size * aspectRatio;
                     style.graphicHeight = size;
-                    this.graphicRotate(node, xOffset, yOffset);
+                    this.graphicRotate(node, xOffset, yOffset, style);
                 }
             }, this);
             img.src = style.externalGraphic;
-
+            
             // will be called again by the onreadystate handler
             return;
         } else {
             size = Math.max(style.graphicWidth, style.graphicHeight);
             aspectRatio = style.graphicWidth / style.graphicHeight;
         }
-
+        
         var width = Math.round(style.graphicWidth || size * aspectRatio);
         var height = Math.round(style.graphicHeight || size);
         node.style.width = width + "px";
         node.style.height = height + "px";
-
+        
         // Three steps are required to remove artefacts for images with
         // transparent backgrounds (resulting from using DXImageTransform
         // filters on svg objects), while preserving awareness for browser
@@ -12330,12 +13425,12 @@
         image.style.height = height + "px";
         image.src = style.externalGraphic;
         image.style.filter =
-            "progid:DXImageTransform.Microsoft.AlphaImageLoader(" +
+            "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + 
             "src='', sizingMethod='scale')";
 
-        var rotation = style.rotation * Math.PI / 180;
-        var sintheta = Math.sin(rotation);
-        var costheta = Math.cos(rotation);
+        var rot = rotation * Math.PI / 180;
+        var sintheta = Math.sin(rot);
+        var costheta = Math.cos(rot);
 
         // do the rotation on the image
         var filter =
@@ -12346,8 +13441,8 @@
         // set the opacity (needed for the imagedata)
         var opacity = style.graphicOpacity || style.fillOpacity;
         if (opacity && opacity != 1) {
-            filter +=
-                "progid:DXImageTransform.Microsoft.BasicImage(opacity=" +
+            filter += 
+                "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + 
                 opacity+")\n";
         }
         node.style.filter = filter;
@@ -12366,15 +13461,19 @@
 
     /**
      * Method: postDraw
-     * Some versions of Internet Explorer seem to be unable to set fillcolor
-     * and strokecolor to "none" correctly before the fill node is appended to
-     * a visible vml node. This method takes care of that and sets fillcolor
-     * and strokecolor again if needed.
-     *
+     * Does some node postprocessing to work around browser issues:
+     * - Some versions of Internet Explorer seem to be unable to set fillcolor
+     *   and strokecolor to "none" correctly before the fill node is appended
+     *   to a visible vml node. This method takes care of that and sets
+     *   fillcolor and strokecolor again if needed.
+     * - In some cases, a node won't become visible after being drawn. Setting
+     *   style.visibility to "visible" works around that.
+     * 
      * Parameters:
      * node - {DOMElement}
      */
     postDraw: function(node) {
+        node.style.visibility = "visible";
         var fillColor = node._style.fillColor;
         var strokeColor = node._style.strokeColor;
         if (fillColor == "none" &&
@@ -12390,9 +13489,9 @@
 
     /**
      * Method: setNodeDimension
-     * Get the geometry's bounds, convert it to our vml coordinate system,
+     * Get the geometry's bounds, convert it to our vml coordinate system, 
      * then set the node's position, size, and local coordinate system.
-     *
+     *   
      * Parameters:
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
@@ -12402,30 +13501,30 @@
         var bbox = geometry.getBounds();
         if(bbox) {
             var resolution = this.getResolution();
-
-            var scaledBox =
-                new OpenLayers.Bounds((bbox.left/resolution - this.offset.x).toFixed(),
-                                      (bbox.bottom/resolution - this.offset.y).toFixed(),
-                                      (bbox.right/resolution - this.offset.x).toFixed(),
-                                      (bbox.top/resolution - this.offset.y).toFixed());
-
+        
+            var scaledBox = 
+                new OpenLayers.Bounds((bbox.left/resolution - this.offset.x) | 0,
+                                      (bbox.bottom/resolution - this.offset.y) | 0,
+                                      (bbox.right/resolution - this.offset.x) | 0,
+                                      (bbox.top/resolution - this.offset.y) | 0);
+            
             // Set the internal coordinate system to draw the path
             node.style.left = scaledBox.left + "px";
             node.style.top = scaledBox.top + "px";
             node.style.width = scaledBox.getWidth() + "px";
             node.style.height = scaledBox.getHeight() + "px";
-
+    
             node.coordorigin = scaledBox.left + " " + scaledBox.top;
             node.coordsize = scaledBox.getWidth()+ " " + scaledBox.getHeight();
         }
     },
-
-    /**
+    
+    /** 
      * Method: dashStyle
-     *
+     * 
      * Parameters:
      * style - {Object}
-     *
+     * 
      * Returns:
      * {String} A VML compliant 'stroke-dasharray' value
      */
@@ -12471,15 +13570,15 @@
         if (id) {
             node.id = id;
         }
-
+        
         // IE hack to make elements unselectable, to prevent 'blue flash'
         // while dragging vectors; #1410
         node.unselectable = 'on';
-        node.onselectstart = function() { return(false); };
-
-        return node;
+        node.onselectstart = OpenLayers.Function.False;
+        
+        return node;    
     },
-
+    
     /**
      * Method: nodeTypeCompare
      * Determine whether a node is of a given type
@@ -12524,7 +13623,7 @@
     /**
      * Method: createRoot
      * Create the main root element
-     *
+     * 
      * Parameters:
      * suffix - {String} suffix to append to the id
      *
@@ -12534,21 +13633,21 @@
     createRoot: function(suffix) {
         return this.nodeFactory(this.container.id + suffix, "olv:group");
     },
-
+    
     /**************************************
      *                                    *
      *     GEOMETRY DRAWING FUNCTIONS     *
      *                                    *
      **************************************/
-
+    
     /**
      * Method: drawPoint
      * Render a point
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement} or false if the point could not be drawn
      */
@@ -12560,12 +13659,12 @@
      * Method: drawCircle
      * Render a circle.
      * Size and Center a circle given geometry (x,y center) and radius
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
      * radius - {float}
-     *
+     * 
      * Returns:
      * {DOMElement} or false if the circle could not ne drawn
      */
@@ -12573,11 +13672,11 @@
         if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
             var resolution = this.getResolution();
 
-            node.style.left = ((geometry.x /resolution - this.offset.x).toFixed() - radius) + "px";
-            node.style.top = ((geometry.y /resolution - this.offset.y).toFixed() - radius) + "px";
-
+            node.style.left = (((geometry.x /resolution - this.offset.x) | 0) - radius) + "px";
+            node.style.top = (((geometry.y /resolution - this.offset.y) | 0) - radius) + "px";
+    
             var diameter = radius * 2;
-
+            
             node.style.width = diameter + "px";
             node.style.height = diameter + "px";
             return node;
@@ -12589,11 +13688,11 @@
     /**
      * Method: drawLineString
      * Render a linestring.
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement}
      */
@@ -12604,11 +13703,11 @@
     /**
      * Method: drawLinearRing
      * Render a linearring
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement}
      */
@@ -12619,12 +13718,12 @@
     /**
      * Method: DrawLine
      * Render a line.
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
      * closeLine - {Boolean} Close the line? (make it a ring?)
-     *
+     * 
      * Returns:
      * {DOMElement}
      */
@@ -12639,9 +13738,9 @@
         var comp, x, y;
         for (var i = 0; i < numComponents; i++) {
             comp = geometry.components[i];
-            x = (comp.x/resolution - this.offset.x);
-            y = (comp.y/resolution - this.offset.y);
-            parts[i] = " " + x.toFixed() + "," + y.toFixed() + " l ";
+            x = (comp.x/resolution - this.offset.x) | 0;
+            y = (comp.y/resolution - this.offset.y) | 0;
+            parts[i] = " " + x + "," + y + " l ";
         }
         var end = (closeLine) ? " x e" : " e";
         node.path = "m" + parts.join("") + end;
@@ -12651,11 +13750,11 @@
     /**
      * Method: drawPolygon
      * Render a polygon
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement}
      */
@@ -12663,7 +13762,7 @@
         this.setNodeDimension(node, geometry);
 
         var resolution = this.getResolution();
-
+    
         var path = [];
         var linearRing, i, j, len, ilen, comp, x, y;
         for (j = 0, len=geometry.components.length; j<len; j++) {
@@ -12672,9 +13771,9 @@
             path.push("m");
             for (i=0, ilen=linearRing.components.length; i<ilen; i++) {
                 comp = linearRing.components[i];
-                x = comp.x / resolution - this.offset.x;
-                y = comp.y / resolution - this.offset.y;
-                path.push(" " + x.toFixed() + "," + y.toFixed());
+                x = (comp.x / resolution - this.offset.x) | 0;
+                y = (comp.y / resolution - this.offset.y) | 0;
+                path.push(" " + x + "," + y);
                 if (i==0) {
                     path.push(" l");
                 }
@@ -12689,30 +13788,30 @@
     /**
      * Method: drawRectangle
      * Render a rectangle
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement}
      */
     drawRectangle: function(node, geometry) {
         var resolution = this.getResolution();
-
-        node.style.left = (geometry.x/resolution - this.offset.x) + "px";
-        node.style.top = (geometry.y/resolution - this.offset.y) + "px";
-        node.style.width = geometry.width/resolution + "px";
-        node.style.height = geometry.height/resolution + "px";
-
+    
+        node.style.left = ((geometry.x/resolution - this.offset.x) | 0) + "px";
+        node.style.top = ((geometry.y/resolution - this.offset.y) | 0) + "px";
+        node.style.width = ((geometry.width/resolution) | 0) + "px";
+        node.style.height = ((geometry.height/resolution) | 0) + "px";
+        
         return node;
     },
-
+    
     /**
      * Method: drawText
      * This method is only called by the renderer itself.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * featureId - {String}
      * style -
      * location - {<OpenLayers.Geometry.Point>}
@@ -12720,17 +13819,20 @@
     drawText: function(featureId, style, location) {
         var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect");
         var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox");
-
+        
         var resolution = this.getResolution();
-        label.style.left = (location.x/resolution - this.offset.x).toFixed() + "px";
-        label.style.top = (location.y/resolution - this.offset.y).toFixed() + "px";
+        label.style.left = ((location.x/resolution - this.offset.x) | 0) + "px";
+        label.style.top = ((location.y/resolution - this.offset.y) | 0) + "px";
         label.style.flip = "y";
 
         textbox.innerText = style.label;
 
-        if (style.fillColor) {
+        if (style.fontColor) {
             textbox.style.color = style.fontColor;
         }
+        if (style.fontOpacity) {
+            textbox.style.filter = 'alpha(opacity=' + (style.fontOpacity * 100) + ')';
+        }
         if (style.fontFamily) {
             textbox.style.fontFamily = style.fontFamily;
         }
@@ -12740,6 +13842,12 @@
         if (style.fontWeight) {
             textbox.style.fontWeight = style.fontWeight;
         }
+        if(style.labelSelect === true) {
+            label._featureId = featureId;
+            textbox._featureId = featureId;
+            textbox._geometry = location;
+            textbox._geometryClass = location.CLASS_NAME;
+        }
         textbox.style.whiteSpace = "nowrap";
         // fun with IE: IE7 in standards compliant mode does not display any
         // text with a left inset of 0. So we set this to 1px and subtract one
@@ -12752,21 +13860,25 @@
         }
 
         var align = style.labelAlign || "cm";
+        if (align.length == 1) {
+            align += "m";
+        }
         var xshift = textbox.clientWidth *
             (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0,1)]);
         var yshift = textbox.clientHeight *
             (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1,1)]);
         label.style.left = parseInt(label.style.left)-xshift-1+"px";
         label.style.top = parseInt(label.style.top)+yshift+"px";
+        
     },
 
     /**
      * Method: drawSurface
-     *
+     * 
      * Parameters:
      * node - {DOMElement}
      * geometry - {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {DOMElement}
      */
@@ -12775,13 +13887,13 @@
         this.setNodeDimension(node, geometry);
 
         var resolution = this.getResolution();
-
+    
         var path = [];
         var comp, x, y;
         for (var i=0, len=geometry.components.length; i<len; i++) {
             comp = geometry.components[i];
-            x = comp.x / resolution - this.offset.x;
-            y = comp.y / resolution - this.offset.y;
+            x = (comp.x / resolution - this.offset.x) | 0;
+            y = (comp.y / resolution - this.offset.y) | 0;
             if ((i%3)==0 && (i/3)==0) {
                 path.push("m");
             } else if ((i%3)==1) {
@@ -12794,17 +13906,17 @@
         node.path = path.join("");
         return node;
     },
-
+    
     /**
      * Method: moveRoot
      * moves this renderer's root to a different renderer.
-     *
+     * 
      * Parameters:
      * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
      * root - {DOMElement} optional root node. To be used when this renderer
      *     holds roots from multiple layers to tell this method which one to
      *     detach
-     *
+     * 
      * Returns:
      * {Boolean} true if successful, false otherwise
      */
@@ -12817,39 +13929,38 @@
         OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments);
         layer && layer.redraw();
     },
-
+    
     /**
      * Method: importSymbol
      * add a new symbol definition from the rendererer's symbol hash
-     *
+     * 
      * Parameters:
      * graphicName - {String} name of the symbol to import
-     *
+     * 
      * Returns:
      * {Object} - hash of {DOMElement} "symbol" and {Number} "size"
-     */
+     */      
     importSymbol: function (graphicName)  {
         var id = this.container.id + "-" + graphicName;
-
+        
         // check if symbol already exists in the cache
         var cache = this.symbolCache[id];
         if (cache) {
             return cache;
         }
-
+        
         var symbol = OpenLayers.Renderer.symbol[graphicName];
         if (!symbol) {
             throw new Error(graphicName + ' is not a valid symbol name');
-            return;
         }
 
         var symbolExtent = new OpenLayers.Bounds(
                                     Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
-
+        
         var pathitems = ["m"];
         for (var i=0; i<symbol.length; i=i+2) {
-            x = symbol[i];
-            y = symbol[i+1];
+            var x = symbol[i];
+            var y = symbol[i+1];
             symbolExtent.left = Math.min(symbolExtent.left, x);
             symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
             symbolExtent.right = Math.max(symbolExtent.right, x);
@@ -12869,10 +13980,10 @@
             symbolExtent.bottom = symbolExtent.bottom - diff;
             symbolExtent.top = symbolExtent.top + diff;
         } else {
-            symbolExtent.left = symbolExtent.left - diff;
-            symbolExtent.right = symbolExtent.right + diff;
+            symbolExtent.left = symbolExtent.left + diff;
+            symbolExtent.right = symbolExtent.right - diff;
         }
-
+        
         cache = {
             path: path,
             size: symbolExtent.getWidth(), // equals getHeight() now
@@ -12880,10 +13991,10 @@
             bottom: symbolExtent.bottom
         };
         this.symbolCache[id] = cache;
-
+        
         return cache;
     },
-
+    
     CLASS_NAME: "OpenLayers.Renderer.VML"
 });
 
@@ -12903,8 +14014,9 @@
     OpenLayers/Tile.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -12914,70 +14026,70 @@
  */
 
 /*
- * Class: OpenLayers.Tile
+ * Class: OpenLayers.Tile 
  * This is a class designed to designate a single tile, however
- *     it is explicitly designed to do relatively little. Tiles store
+ *     it is explicitly designed to do relatively little. Tiles store 
  *     information about themselves -- such as the URL that they are related
- *     to, and their size - but do not add themselves to the layer div
- *     automatically, for example. Create a new tile with the
- *     <OpenLayers.Tile> constructor, or a subclass.
- *
+ *     to, and their size - but do not add themselves to the layer div 
+ *     automatically, for example. Create a new tile with the 
+ *     <OpenLayers.Tile> constructor, or a subclass. 
+ * 
  * TBD 3.0 - remove reference to url in above paragraph
- *
+ * 
  */
 OpenLayers.Tile = OpenLayers.Class({
-
-    /**
+    
+    /** 
      * Constant: EVENT_TYPES
      * {Array(String)} Supported application event types
      */
     EVENT_TYPES: [ "loadstart", "loadend", "reload", "unload"],
-
+    
     /**
      * APIProperty: events
-     * {<OpenLayers.Events>} An events object that handles all
+     * {<OpenLayers.Events>} An events object that handles all 
      *                       events on the tile.
      */
     events: null,
 
     /**
-     * Property: id
+     * Property: id 
      * {String} null
      */
     id: null,
-
-    /**
-     * Property: layer
-     * {<OpenLayers.Layer>} layer the tile is attached to
+    
+    /** 
+     * Property: layer 
+     * {<OpenLayers.Layer>} layer the tile is attached to 
      */
     layer: null,
-
+    
     /**
      * Property: url
      * {String} url of the request.
      *
-     * TBD 3.0
-     * Deprecated. The base tile class does not need an url. This should be
+     * TBD 3.0 
+     * Deprecated. The base tile class does not need an url. This should be 
      * handled in subclasses. Does not belong here.
      */
     url: null,
 
-    /**
-     * APIProperty: bounds
+    /** 
+     * APIProperty: bounds 
      * {<OpenLayers.Bounds>} null
      */
     bounds: null,
-
-    /**
-     * Property: size
+    
+    /** 
+     * Property: size 
      * {<OpenLayers.Size>} null
      */
     size: null,
-
-    /**
-     * Property: position
+    
+    /** 
+     * Property: position 
      * {<OpenLayers.Pixel>} Top Left pixel of the tile
-     */
+     */    
     position: null,
 
     /**
@@ -12985,20 +14097,20 @@
      * {Boolean} Is the tile loading?
      */
     isLoading: false,
-
+        
     /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
      *             there is no need for the base tile class to have a url.
-     *
+     * 
      * Constructor: OpenLayers.Tile
      * Constructor for a new <OpenLayers.Tile> instance.
-     *
+     * 
      * Parameters:
      * layer - {<OpenLayers.Layer>} layer that the tile will go in.
      * position - {<OpenLayers.Pixel>}
      * bounds - {<OpenLayers.Bounds>}
      * url - {<String>}
      * size - {<OpenLayers.Size>}
-     */
+     */   
     initialize: function(layer, position, bounds, url, size) {
         this.layer = layer;
         this.position = position.clone();
@@ -13008,7 +14120,7 @@
 
         //give the tile a unique id based on its BBOX.
         this.id = OpenLayers.Util.createUniqueID("Tile_");
-
+        
         this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
     },
 
@@ -13020,13 +14132,13 @@
      * still loading.
      */
     unload: function() {
-       if (this.isLoading) {
-           this.isLoading = false;
-           this.events.triggerEvent("unload");
+       if (this.isLoading) { 
+           this.isLoading = false; 
+           this.events.triggerEvent("unload"); 
        }
     },
-
-    /**
+    
+    /** 
      * APIMethod: destroy
      * Nullify references to prevent circular references and memory leaks.
      */
@@ -13035,11 +14147,11 @@
         this.bounds = null;
         this.size = null;
         this.position = null;
-
+        
         this.events.destroy();
         this.events = null;
     },
-
+    
     /**
      * Method: clone
      *
@@ -13051,27 +14163,27 @@
      */
     clone: function (obj) {
         if (obj == null) {
-            obj = new OpenLayers.Tile(this.layer,
-                                      this.position,
-                                      this.bounds,
-                                      this.url,
+            obj = new OpenLayers.Tile(this.layer, 
+                                      this.position, 
+                                      this.bounds, 
+                                      this.url, 
                                       this.size);
-        }
-
+        } 
+        
         // catch any randomly tagged-on properties
         OpenLayers.Util.applyDefaults(obj, this);
-
+        
         return obj;
     },
 
     /**
      * Method: draw
-     * Clear whatever is currently in the tile, then return whether or not
+     * Clear whatever is currently in the tile, then return whether or not 
      *     it should actually be re-drawn.
-     *
+     * 
      * Returns:
-     * {Boolean} Whether or not the tile should actually be drawn. Note that
-     *     this is not really the best way of doing things, but such is
+     * {Boolean} Whether or not the tile should actually be drawn. Note that 
+     *     this is not really the best way of doing things, but such is 
      *     the way the code has been developed. Subclasses call this and
      *     depend on the return to know if they should draw or not.
      */
@@ -13079,18 +14191,18 @@
         var maxExtent = this.layer.maxExtent;
         var withinMaxExtent = (maxExtent &&
                                this.bounds.intersectsBounds(maxExtent, false));
-
-        // The only case where we *wouldn't* want to draw the tile is if the
+ 
+        // The only case where we *wouldn't* want to draw the tile is if the 
         // tile is outside its layer's maxExtent.
         this.shouldDraw = (withinMaxExtent || this.layer.displayOutsideMaxExtent);
-
+                
         //clear tile's contents and mark as not drawn
         this.clear();
-
+        
         return this.shouldDraw;
     },
-
-    /**
+    
+    /** 
      * Method: moveTo
      * Reposition the tile.
      *
@@ -13112,83 +14224,84 @@
         }
     },
 
-    /**
+    /** 
      * Method: clear
-     * Clear the tile of any bounds/position-related data so that it can
+     * Clear the tile of any bounds/position-related data so that it can 
      *     be reused in a new location. To be implemented by subclasses.
      */
     clear: function() {
         // to be implemented by subclasses
     },
-
-    /**
+    
+    /**   
      * Method: getBoundsFromBaseLayer
-     * Take the pixel locations of the corner of the tile, and pass them to
-     *     the base layer and ask for the location of those pixels, so that
+     * Take the pixel locations of the corner of the tile, and pass them to 
+     *     the base layer and ask for the location of those pixels, so that 
      *     displaying tiles over Google works fine.
      *
      * Parameters:
      * position - {<OpenLayers.Pixel>}
      *
      * Returns:
-     * bounds - {<OpenLayers.Bounds>}
+     * bounds - {<OpenLayers.Bounds>} 
      */
     getBoundsFromBaseLayer: function(position) {
         var msg = OpenLayers.i18n('reprojectDeprecated',
                                               {'layerName':this.layer.name});
         OpenLayers.Console.warn(msg);
-        var topLeft = this.layer.map.getLonLatFromLayerPx(position);
+        var topLeft = this.layer.map.getLonLatFromLayerPx(position); 
         var bottomRightPx = position.clone();
         bottomRightPx.x += this.size.w;
         bottomRightPx.y += this.size.h;
-        var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx);
+        var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx); 
         // Handle the case where the base layer wraps around the date line.
-        // Google does this, and it breaks WMS servers to request bounds in
-        // that fashion.
+        // Google does this, and it breaks WMS servers to request bounds in 
+        // that fashion.  
         if (topLeft.lon > bottomRight.lon) {
             if (topLeft.lon < 0) {
                 topLeft.lon = -180 - (topLeft.lon+180);
             } else {
                 bottomRight.lon = 180+bottomRight.lon+180;
-            }
+            }        
         }
-        var bounds = new OpenLayers.Bounds(topLeft.lon,
-                                       bottomRight.lat,
-                                       bottomRight.lon,
-                                       topLeft.lat);
+        var bounds = new OpenLayers.Bounds(topLeft.lon, 
+                                       bottomRight.lat, 
+                                       bottomRight.lon, 
+                                       topLeft.lat);  
         return bounds;
-    },
-
-    /**
+    },        
+        
+    /** 
      * Method: showTile
      * Show the tile only if it should be drawn.
      */
-    showTile: function() {
+    showTile: function() { 
         if (this.shouldDraw) {
             this.show();
         }
     },
-
-    /**
+    
+    /** 
      * Method: show
      * Show the tile.  To be implemented by subclasses.
      */
     show: function() { },
-
-    /**
+    
+    /** 
      * Method: hide
      * Hide the tile.  To be implemented by subclasses.
      */
     hide: function() { },
-
+    
     CLASS_NAME: "OpenLayers.Tile"
 });
 /* ======================================================================
     OpenLayers/Format/XML.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -13207,7 +14320,7 @@
  *  - <OpenLayers.Format>
  */
 OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
-
+    
     /**
      * Property: namespaces
      * {Object} Mapping of namespace aliases to namespace URIs.  Properties
@@ -13216,20 +14329,20 @@
      *     <setNamespace> to add or set a namespace alias after construction.
      */
     namespaces: null,
-
+    
     /**
      * Property: namespaceAlias
      * {Object} Mapping of namespace URI to namespace alias.  This object
      *     is read-only.  Use <setNamespace> to add or set a namespace alias.
      */
     namespaceAlias: null,
-
+    
     /**
      * Property: defaultPrefix
      * {String} The default namespace alias for creating element nodes.
      */
     defaultPrefix: null,
-
+    
     /**
      * Property: readers
      * Contains public functions, grouped by namespace prefix, that will
@@ -13239,7 +14352,7 @@
      *     from the parent.
      */
     readers: {},
-
+    
     /**
      * Property: writers
      * As a compliment to the <readers> property, this structure contains public
@@ -13280,7 +14393,7 @@
             this.namespaceAlias[this.namespaces[alias]] = alias;
         }
     },
-
+    
     /**
      * APIMethod: destroy
      * Clean up.
@@ -13289,7 +14402,7 @@
         this.xmldom = null;
         OpenLayers.Format.prototype.destroy.apply(this, arguments);
     },
-
+    
     /**
      * Method: setNamespace
      * Set a namespace alias and URI for the format.
@@ -13309,7 +14422,7 @@
      *
      * Parameters:
      * text - {String} A XML string
-
+     
      * Returns:
      * {DOMElement} A DOM node
      */
@@ -13330,7 +14443,7 @@
                         xmldom = new ActiveXObject("Microsoft.XMLDOM");
                     } else {
                         xmldom = this.xmldom;
-
+                        
                     }
                     xmldom.loadXML(text);
                     return xmldom;
@@ -13361,7 +14474,7 @@
     /**
      * APIMethod: write
      * Serialize a DOM node into a XML string.
-     *
+     * 
      * Parameters:
      * node - {DOMElement} A DOM node.
      *
@@ -13400,7 +14513,7 @@
      * Parameters:
      * uri - {String} Namespace URI for the element.
      * name - {String} The qualified name of the element (prefix:localname).
-     *
+     * 
      * Returns:
      * {Element} A DOM element with namespace.
      */
@@ -13423,15 +14536,18 @@
      * Create a text node.  This node can be appended to another node with
      *     the standard node.appendChild method.  For cross-browser support,
      *     this method must be used instead of document.createTextNode.
-     *
+     * 
      * Parameters:
      * text - {String} The text of the node.
-     *
-     * Returns:
+     * 
+     * Returns: 
      * {DOMElement} A DOM text node.
      */
     createTextNode: function(text) {
         var node;
+        if (typeof text !== "string") {
+            text = String(text);
+        }
         if(this.xmldom) {
             node = this.xmldom.createTextNode(text);
         } else {
@@ -13446,12 +14562,12 @@
      *     To return all nodes in a given namespace, use '*' for the name
      *     argument.  To return all nodes of a given (local) name, regardless
      *     of namespace, use '*' for the uri argument.
-     *
+     * 
      * Parameters:
      * node - {Element} Node on which to search for other nodes.
      * uri - {String} Namespace URI.
      * name - {String} Local name of the tag (without the prefix).
-     *
+     * 
      * Returns:
      * {NodeList} A node list or array of elements.
      */
@@ -13480,12 +14596,12 @@
     /**
      * APIMethod: getAttributeNodeNS
      * Get an attribute node given the namespace URI and local name.
-     *
+     * 
      * Parameters:
      * node - {Element} Node on which to search for attribute nodes.
      * uri - {String} Namespace URI.
      * name - {String} Local name of the attribute (without the prefix).
-     *
+     * 
      * Returns:
      * {DOMElement} An attribute node or null if none found.
      */
@@ -13514,12 +14630,12 @@
     /**
      * APIMethod: getAttributeNS
      * Get an attribute value given the namespace URI and local name.
-     *
+     * 
      * Parameters:
      * node - {Element} Node on which to search for an attribute.
      * uri - {String} Namespace URI.
      * name - {String} Local name of the attribute (without the prefix).
-     *
+     * 
      * Returns:
      * {String} An attribute value or and empty string if none found.
      */
@@ -13535,7 +14651,7 @@
         }
         return attributeValue;
     },
-
+    
     /**
      * APIMethod: getChildValue
      * Get the textual value of the node if it exists, or return an
@@ -13597,7 +14713,7 @@
         }
         return value;
     },
-
+    
     /**
      * APIMethod: isSimpleContent
      * Test if the given node has only simple content (i.e. no child element
@@ -13607,7 +14723,7 @@
      * node - {DOMElement} An element node.
      *
      * Returns:
-     * {Boolean} The node has no child element nodes (nodes of type 1).
+     * {Boolean} The node has no child element nodes (nodes of type 1). 
      */
     isSimpleContent: function(node) {
         var simple = true;
@@ -13619,7 +14735,7 @@
         }
         return simple;
     },
-
+    
     /**
      * APIMethod: contentType
      * Determine the content type for a given node.
@@ -13634,7 +14750,7 @@
     contentType: function(node) {
         var simple = false,
             complex = false;
-
+            
         var type = OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;
 
         for(var child=node.firstChild; child; child=child.nextSibling) {
@@ -13651,7 +14767,7 @@
                 break;
             }
         }
-
+        
         if(complex && simple) {
             type = OpenLayers.Format.XML.CONTENT_TYPE.MIXED;
         } else if(complex) {
@@ -13666,12 +14782,12 @@
      * APIMethod: hasAttributeNS
      * Determine whether a node has a particular attribute matching the given
      *     name and namespace.
-     *
+     * 
      * Parameters:
      * node - {Element} Node on which to search for an attribute.
      * uri - {String} Namespace URI.
      * name - {String} Local name of the attribute (without the prefix).
-     *
+     * 
      * Returns:
      * {Boolean} The node has an attribute matching the name and namespace.
      */
@@ -13684,7 +14800,7 @@
         }
         return found;
     },
-
+    
     /**
      * APIMethod: setAttributeNS
      * Adds a new attribute or changes the value of an attribute with the given
@@ -13757,14 +14873,11 @@
         }
         var value = options.value;
         if(value != null) {
-            if(typeof value == "boolean") {
-                value = String(value);
-            }
             node.appendChild(this.createTextNode(value));
         }
         return node;
     },
-
+    
     /**
      * Method: setAttributes
      * Set multiple attributes given key value pairs from an object.
@@ -13806,7 +14919,7 @@
         if(!obj) {
             obj = {};
         }
-        var group = this.readers[this.namespaceAlias[node.namespaceURI]];
+        var group = this.readers[node.namespaceURI ? this.namespaceAlias[node.namespaceURI]: this.defaultPrefix];
         if(group) {
             var local = node.localName || node.nodeName.split(":").pop();
             var reader = group[local] || group["*"];
@@ -13903,7 +15016,7 @@
     getChildEl: function(node, name, uri) {
         return node && this.getThisOrNextEl(node.firstChild, name, uri);
     },
-
+    
     /**
      * APIMethod: getNextEl
      * Get the next sibling element.  Optionally get the first sibling only
@@ -13922,7 +15035,7 @@
     getNextEl: function(node, name, uri) {
         return node && this.getThisOrNextEl(node.nextSibling, name, uri);
     },
-
+    
     /**
      * Method: getThisOrNextEl
      * Return this node or the next element node.  Optionally get the first
@@ -13964,7 +15077,7 @@
         }
         return sibling || null;
     },
-
+    
     /**
      * APIMethod: lookupNamespaceURI
      * Takes a prefix and returns the namespace URI associated with it on the given
@@ -13977,11 +15090,11 @@
      *
      * For browsers that don't support the attribute.ownerElement property, this
      *     method cannot be called on attribute nodes.
-     *
+     *     
      * Parameters:
      * node - {DOMElement} The node from which to start looking.
      * prefix - {String} The prefix to lookup or null to lookup the default namespace.
-     *
+     * 
      * Returns:
      * {String} The namespace URI for the given prefix.  Returns null if the prefix
      *     cannot be found or the node is the wrong type.
@@ -14025,7 +15138,7 @@
                     case 10: // DOCUMENT_TYPE_NODE
                     case 11: // DOCUMENT_FRAGMENT_NODE
                         break outer;
-                    default:
+                    default: 
                         // TEXT_NODE (3), CDATA_SECTION_NODE (4), ENTITY_REFERENCE_NODE (5),
                         // PROCESSING_INSTRUCTION_NODE (7), COMMENT_NODE (8)
                         uri =  this.lookupNamespaceURI(node.parentNode, prefix);
@@ -14035,11 +15148,11 @@
         }
         return uri;
     },
+    
+    CLASS_NAME: "OpenLayers.Format.XML" 
 
-    CLASS_NAME: "OpenLayers.Format.XML"
+});     
 
-});
-
 OpenLayers.Format.XML.CONTENT_TYPE = {EMPTY: 0, SIMPLE: 1, COMPLEX: 2, MIXED: 3};
 
 /**
@@ -14054,11 +15167,11 @@
  *
  * For browsers that don't support the attribute.ownerElement property, this
  *     method cannot be called on attribute nodes.
- *
+ *     
  * Parameters:
  * node - {DOMElement} The node from which to start looking.
  * prefix - {String} The prefix to lookup or null to lookup the default namespace.
- *
+ * 
  * Returns:
  * {String} The namespace URI for the given prefix.  Returns null if the prefix
  *     cannot be found or the node is the wrong type.
@@ -14071,8 +15184,9 @@
     OpenLayers/Handler.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -14094,7 +15208,7 @@
  *     correspond to these abstract events - so instead of listening for
  *     individual browser events, they only listen for the abstract events
  *     defined by the handler.
- *
+ *     
  * Handlers are created by controls, which ultimately have the responsibility
  *     of making changes to the the state of the application.  Handlers
  *     themselves may make temporary changes, but in general are expected to
@@ -14107,7 +15221,7 @@
      * {String}
      */
     id: null,
-
+        
     /**
      * APIProperty: control
      * {<OpenLayers.Control>}. The control that initialized this handler.  The
@@ -14146,7 +15260,7 @@
      * {Boolean}
      */
     active: false,
-
+    
     /**
      * Property: evt
      * {Event} This property references the last event handled by the handler.
@@ -14164,7 +15278,8 @@
      * Parameters:
      * control - {<OpenLayers.Control>} The control that initialized this
      *     handler.  The control is assumed to have a valid map property; that
-     *     map is used in the handler's own setMap method.
+     *     map is used in the handler's own setMap method.  If a map property
+     *     is present in the options argument it will be used instead.
      * callbacks - {Object} An object whose properties correspond to abstracted
      *     events or sequences of browser events.  The values for these
      *     properties are functions defined by the control that get called by
@@ -14176,15 +15291,15 @@
         OpenLayers.Util.extend(this, options);
         this.control = control;
         this.callbacks = callbacks;
-        if (control.map) {
-            this.setMap(control.map);
+
+        var map = this.map || control.map;
+        if (map) {
+            this.setMap(map); 
         }
-
-        OpenLayers.Util.extend(this, options);
-
+        
         this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
     },
-
+    
     /**
      * Method: setMap
      */
@@ -14210,7 +15325,7 @@
             (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |
             (evt.ctrlKey  ? OpenLayers.Handler.MOD_CTRL  : 0) |
             (evt.altKey   ? OpenLayers.Handler.MOD_ALT   : 0);
-
+    
         /* if it differs from the handler object's key mask,
            bail out of the event handler */
         return (keyModifiers == this.keyMask);
@@ -14219,8 +15334,8 @@
     /**
      * APIMethod: activate
      * Turn on the handler.  Returns false if the handler was already active.
-     *
-     * Returns:
+     * 
+     * Returns: 
      * {Boolean} The handler was activated.
      */
     activate: function() {
@@ -14231,17 +15346,17 @@
         var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
         for (var i=0, len=events.length; i<len; i++) {
             if (this[events[i]]) {
-                this.register(events[i], this[events[i]]);
+                this.register(events[i], this[events[i]]); 
             }
-        }
+        } 
         this.active = true;
         return true;
     },
-
+    
     /**
      * APIMethod: deactivate
      * Turn off the handler.  Returns false if the handler was already inactive.
-     *
+     * 
      * Returns:
      * {Boolean} The handler was deactivated.
      */
@@ -14253,9 +15368,9 @@
         var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
         for (var i=0, len=events.length; i<len; i++) {
             if (this[events[i]]) {
-                this.unregister(events[i], this[events[i]]);
+                this.unregister(events[i], this[events[i]]); 
             }
-        }
+        } 
         this.active = false;
         return true;
     },
@@ -14267,7 +15382,7 @@
     * Parameters:
     * name - {String} The key for the callback that is one of the properties
     *     of the handler's callbacks object.
-    * args - {Array(*)} An array of arguments (any type) with which to call
+    * args - {Array(*)} An array of arguments (any type) with which to call 
     *     the callback (defined by the control).
     */
     callback: function (name, args) {
@@ -14291,10 +15406,10 @@
     * unregister an event from the map
     */
     unregister: function (name, method) {
-        this.map.events.unregister(name, this, method);
+        this.map.events.unregister(name, this, method);   
         this.map.events.unregister(name, this, this.setEvent);
     },
-
+    
     /**
      * Method: setEvent
      * With each registered browser event, the handler sets its own evt
@@ -14325,7 +15440,7 @@
         // unregister event listeners
         this.deactivate();
         // eliminate circular references
-        this.control = this.map = null;
+        this.control = this.map = null;        
     },
 
     CLASS_NAME: "OpenLayers.Handler"
@@ -14360,8 +15475,9 @@
     OpenLayers/Map.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -14375,16 +15491,16 @@
  * Class: OpenLayers.Map
  * Instances of OpenLayers.Map are interactive maps embedded in a web page.
  * Create a new map with the <OpenLayers.Map> constructor.
- *
+ * 
  * On their own maps do not provide much functionality.  To extend a map
- * it's necessary to add controls (<OpenLayers.Control>) and
- * layers (<OpenLayers.Layer>) to the map.
+ * it's necessary to add controls (<OpenLayers.Control>) and 
+ * layers (<OpenLayers.Layer>) to the map. 
  */
 OpenLayers.Map = OpenLayers.Class({
-
+    
     /**
      * Constant: Z_INDEX_BASE
-     * {Object} Base z-indexes for different classes of thing
+     * {Object} Base z-indexes for different classes of thing 
      */
     Z_INDEX_BASE: {
         BaseLayer: 100,
@@ -14416,35 +15532,30 @@
      *
      * Supported map event types:
      *  - *preaddlayer* triggered before a layer has been added.  The event
-     *      object will include a *layer* property that references the layer
+     *      object will include a *layer* property that references the layer  
      *      to be added.
      *  - *addlayer* triggered after a layer has been added.  The event object
      *      will include a *layer* property that references the added layer.
      *  - *removelayer* triggered after a layer has been removed.  The event
      *      object will include a *layer* property that references the removed
      *      layer.
-     *  - *changelayer* triggered after a layer name change, order change, or
-     *      visibility change (due to resolution thresholds).  Listeners will
-     *      receive an event object with *layer* and *property* properties.  The
-     *      *layer* property will be a reference to the changed layer.  The
-     *      *property* property will be a key to the changed property (name,
-     *      visibility, or order).
+     *  - *changelayer* triggered after a layer name change, order change,
+     *      opacity change, params change or visibility change
+     *      (due to resolution thresholds). Listeners will receive an event
+     *      object with *layer* and *property* properties. The *layer*
+     *      property will be a reference to the changed layer. 
+     *      The *property* property will be a key to the
+     *      changed property (name, order, opacity, params or visibility).
      *  - *movestart* triggered after the start of a drag, pan, or zoom
      *  - *move* triggered after each drag, pan, or zoom
      *  - *moveend* triggered after a drag, pan, or zoom completes
      *  - *zoomend* triggered after a zoom completes
-     *  - *addmarker* triggered after a marker has been added
-     *  - *removemarker* triggered after a marker has been removed
-     *  - *clearmarkers* triggered after markers have been cleared
      *  - *mouseover* triggered after mouseover the map
      *  - *mouseout* triggered after mouseout the map
      *  - *mousemove* triggered after mousemove the map
-     *  - *dragstart* Does not work.  Register for movestart instead.
-     *  - *drag* Does not work.  Register for move instead.
-     *  - *dragend* Does not work.  Register for moveend instead.
      *  - *changebaselayer* triggered after the base layer changes
      */
-    EVENT_TYPES: [
+    EVENT_TYPES: [ 
         "preaddlayer", "addlayer", "removelayer", "changelayer", "movestart",
         "move", "moveend", "zoomend", "popupopen", "popupclose",
         "addmarker", "removemarker", "clearmarkers", "mouseover",
@@ -14456,7 +15567,7 @@
      * {String} Unique identifier for the map
      */
     id: null,
-
+    
     /**
      * Property: fractionalZoom
      * {Boolean} For a base layer that supports it, allow the map resolution
@@ -14475,14 +15586,14 @@
      *     former works for non-integer zoom levels.
      */
     fractionalZoom: false,
-
+    
     /**
      * APIProperty: events
-     * {<OpenLayers.Events>} An events object that handles all
+     * {<OpenLayers.Events>} An events object that handles all 
      *                       events on the map
      */
     events: null,
-
+    
     /**
      * APIProperty: allOverlays
      * {Boolean} Allow the map to function with "overlays" only.  Defaults to
@@ -14509,13 +15620,14 @@
      *     div property may or may not be provided.  If the div property
      *     is not provided, the map can be rendered to a container later
      *     using the <render> method.
-     *
-     * Note: If you calling <render> after map construction, do not use
+     *     
+     * Note:
+     * If you are calling <render> after map construction, do not use
      *     <maxResolution>  auto.  Instead, divide your <maxExtent> by your
      *     maximum expected dimension.
      */
     div: null,
-
+    
     /**
      * Property: dragging
      * {Boolean} The map is currently being dragged.
@@ -14527,7 +15639,7 @@
      * {<OpenLayers.Size>} Size of the main div (this.div)
      */
     size: null,
-
+    
     /**
      * Property: viewPortDiv
      * {HTMLDivElement} The element that represents the map viewport
@@ -14578,7 +15690,7 @@
      * min/max zoom level, projection, etc.
      */
     baseLayer: null,
-
+    
     /**
      * Property: center
      * {<OpenLayers.LonLat>} The current center of the map
@@ -14595,25 +15707,25 @@
      * Property: zoom
      * {Integer} The current zoom level of the map
      */
-    zoom: 0,
+    zoom: 0,    
 
     /**
      * Property: panRatio
      * {Float} The ratio of the current extent within
      *         which panning will tween.
      */
-    panRatio: 1.5,
+    panRatio: 1.5,    
 
     /**
      * Property: viewRequestID
-     * {String} Used to store a unique identifier that changes when the map
-     *          view changes. viewRequestID should be used when adding data
-     *          asynchronously to the map: viewRequestID is incremented when
-     *          you initiate your request (right now during changing of
-     *          baselayers and changing of zooms). It is stored here in the
-     *          map and also in the data that will be coming back
-     *          asynchronously. Before displaying this data on request
-     *          completion, we check that the viewRequestID of the data is
+     * {String} Used to store a unique identifier that changes when the map 
+     *          view changes. viewRequestID should be used when adding data 
+     *          asynchronously to the map: viewRequestID is incremented when 
+     *          you initiate your request (right now during changing of 
+     *          baselayers and changing of zooms). It is stored here in the 
+     *          map and also in the data that will be coming back 
+     *          asynchronously. Before displaying this data on request 
+     *          completion, we check that the viewRequestID of the data is 
      *          still the same as that of the map. Fix for #480
      */
     viewRequestID: 0,
@@ -14629,12 +15741,12 @@
 
     /**
      * APIProperty: projection
-     * {String} Set in the map options to override the default projection
-     *          string this map - also set maxExtent, maxResolution, and
+     * {String} Set in the map options to override the default projection 
+     *          string this map - also set maxExtent, maxResolution, and 
      *          units if appropriate.  Default is "EPSG:4326".
      */
-    projection: "EPSG:4326",
-
+    projection: "EPSG:4326",    
+        
     /**
      * APIProperty: units
      * {String} The map units.  Defaults to 'degrees'.  Possible values are
@@ -14644,9 +15756,9 @@
 
     /**
      * APIProperty: resolutions
-     * {Array(Float)} A list of map resolutions (map units per pixel) in
-     *     descending order.  If this is not set in the layer constructor, it
-     *     will be set based on other resolution related properties
+     * {Array(Float)} A list of map resolutions (map units per pixel) in 
+     *     descending order.  If this is not set in the layer constructor, it 
+     *     will be set based on other resolution related properties 
      *     (maxExtent, maxResolution, maxScale, etc.).
      */
     resolutions: null,
@@ -14654,8 +15766,8 @@
     /**
      * APIProperty: maxResolution
      * {Float} Default max is 360 deg / 256 px, which corresponds to
-     *          zoom level 0 on gmaps.  Specify a different value in the map
-     *          options if you are not using a geographic projection and
+     *          zoom level 0 on gmaps.  Specify a different value in the map 
+     *          options if you are not using a geographic projection and 
      *          displaying the whole world.
      */
     maxResolution: 1.40625,
@@ -14681,20 +15793,20 @@
     /**
      * APIProperty: maxExtent
      * {<OpenLayers.Bounds>} The maximum extent for the map.  Defaults to the
-     *                       whole world in decimal degrees
+     *                       whole world in decimal degrees 
      *                       (-180, -90, 180, 90).  Specify a different
-     *                        extent in the map options if you are not using a
-     *                        geographic projection and displaying the whole
+     *                        extent in the map options if you are not using a 
+     *                        geographic projection and displaying the whole 
      *                        world.
      */
     maxExtent: null,
-
+    
     /**
      * APIProperty: minExtent
      * {<OpenLayers.Bounds>}
      */
     minExtent: null,
-
+    
     /**
      * APIProperty: restrictedExtent
      * {<OpenLayers.Bounds>} Limit map navigation to this extent where possible.
@@ -14716,18 +15828,18 @@
     /**
      * APIProperty: theme
      * {String} Relative path to a CSS file from which to load theme styles.
-     *          Specify null in the map options (e.g. {theme: null}) if you
-     *          want to get cascading style declarations - by putting links to
+     *          Specify null in the map options (e.g. {theme: null}) if you 
+     *          want to get cascading style declarations - by putting links to 
      *          stylesheets or style declarations directly in your page.
      */
     theme: null,
-
-    /**
+    
+    /** 
      * APIProperty: displayProjection
      * {<OpenLayers.Projection>} Requires proj4js support.Projection used by
      *     several controls to display data to user. If this property is set,
      *     it will be set on any control which has a null displayProjection
-     *     property at the time the control is added to the map.
+     *     property at the time the control is added to the map. 
      */
     displayProjection: null,
 
@@ -14738,7 +15850,7 @@
      *           Default is to fall through.
      */
     fallThrough: true,
-
+    
     /**
      * Property: panTween
      * {OpenLayers.Tween} Animated panning tween object, see panTo()
@@ -14761,7 +15873,7 @@
      * animated panning.
      */
     panMethod: OpenLayers.Easing.Expo.easeOut,
-
+    
     /**
      * Property: panDuration
      * {Integer} The number of steps to be passed to the
@@ -14770,23 +15882,23 @@
      * Default is 50.
      */
     panDuration: 50,
-
+    
     /**
      * Property: paddingForPopups
-     * {<OpenLayers.Bounds>} Outside margin of the popup. Used to prevent
+     * {<OpenLayers.Bounds>} Outside margin of the popup. Used to prevent 
      *     the popup from getting too close to the map border.
      */
     paddingForPopups : null,
-
+    
     /**
      * Constructor: OpenLayers.Map
      * Constructor for a new OpenLayers.Map instance.  There are two possible
      *     ways to call the map constructor.  See the examples below.
      *
      * Parameters:
-     * div - {String} Id of an element in your page that will contain the map.
-     *     May be omitted if the <div> option is provided or if you intend
-     *     to use <render> later.
+     * div - {DOMElement|String}  The element or id of an element in your page
+     *     that will contain the map.  May be omitted if the <div> option is
+     *     provided or if you intend to call the <render> method later.
      * options - {Object} Optional object with properties to tag onto the map.
      *
      * Examples (method one):
@@ -14822,30 +15934,33 @@
      *     units: 'm',
      *     projection: "EPSG:41001"
      * });
-     */
+     */    
     initialize: function (div, options) {
-
+        
         // If only one argument is provided, check if it is an object.
         if(arguments.length === 1 && typeof div === "object") {
             options = div;
             div = options && options.div;
         }
 
-        // Simple-type defaults are set in class definition.
-        //  Now set complex-type defaults
+        // Simple-type defaults are set in class definition. 
+        //  Now set complex-type defaults 
         this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,
                                             OpenLayers.Map.TILE_HEIGHT);
-
+        
         this.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
-
+        
         this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);
 
-        this.theme = OpenLayers._getScriptLocation() +
-                             'theme/default/style.css';
+        this.theme = OpenLayers._getScriptLocation() + 
+                             'theme/default/style.css'; 
 
-        // now override default options
+        // now override default options 
         OpenLayers.Util.extend(this, options);
 
+        // initialize layers array
+        this.layers = [];
+
         this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_");
 
         this.div = OpenLayers.Util.getElement(div);
@@ -14854,11 +15969,11 @@
             this.div.style.height = "1px";
             this.div.style.width = "1px";
         }
-
+        
         OpenLayers.Element.addClass(this.div, 'olMap');
 
         // the viewPortDiv is the outermost div we modify
-        var id = this.div.id + "_OpenLayers_ViewPort";
+        var id = this.id + "_OpenLayers_ViewPort";
         this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null,
                                                      "relative", null,
                                                      "hidden");
@@ -14868,40 +15983,40 @@
         this.div.appendChild(this.viewPortDiv);
 
         // the layerContainerDiv is the one that holds all the layers
-        id = this.div.id + "_OpenLayers_Container";
+        id = this.id + "_OpenLayers_Container";
         this.layerContainerDiv = OpenLayers.Util.createDiv(id);
         this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
-
+        
         this.viewPortDiv.appendChild(this.layerContainerDiv);
 
-        this.events = new OpenLayers.Events(this,
-                                            this.div,
-                                            this.EVENT_TYPES,
-                                            this.fallThrough,
+        this.events = new OpenLayers.Events(this, 
+                                            this.div, 
+                                            this.EVENT_TYPES, 
+                                            this.fallThrough, 
                                             {includeXY: true});
         this.updateSize();
         if(this.eventListeners instanceof Object) {
             this.events.on(this.eventListeners);
         }
-
+ 
         // update the map size and location before the map moves
         this.events.register("movestart", this, this.updateSize);
 
-        // Because Mozilla does not support the "resize" event for elements
-        // other than "window", we need to put a hack here.
+        // Because Mozilla does not support the "resize" event for elements 
+        // other than "window", we need to put a hack here. 
         if (OpenLayers.String.contains(navigator.appName, "Microsoft")) {
             // If IE, register the resize on the div
             this.events.register("resize", this, this.updateSize);
         } else {
             // Else updateSize on catching the window's resize
-            //  Note that this is ok, as updateSize() does nothing if the
+            //  Note that this is ok, as updateSize() does nothing if the 
             //  map's size has not actually changed.
-            this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize,
+            this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize, 
                 this);
             OpenLayers.Event.observe(window, 'resize',
                             this.updateSizeDestroy);
         }
-
+        
         // only append link stylesheet if the theme property is set
         if(this.theme) {
             // check existing links for equivalent url
@@ -14924,9 +16039,7 @@
                 document.getElementsByTagName('head')[0].appendChild(cssNode);
             }
         }
-
-        this.layers = [];
-
+        
         if (this.controls == null) {
             if (OpenLayers.Control != null) { // running full or lite?
                 this.controls = [ new OpenLayers.Control.Navigation(),
@@ -14946,16 +16059,26 @@
         this.popups = [];
 
         this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);
+        
 
-
         // always call map.destroy()
         OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
+        
+        // add any initial layers
+        if (options && options.layers) {
+            this.addLayers(options.layers);        
+            // set center (and optionally zoom)
+            if (options.center) {
+                // zoom can be undefined here
+                this.setCenter(options.center, options.zoom);
+            }
+        }
     },
-
+    
     /**
      * APIMethod: render
      * Render the map to a specified container.
-     *
+     * 
      * Parameters:
      * div - {String|DOMElement} The container that the map should be rendered
      *     to. If different than the current container, the map viewport
@@ -14976,11 +16099,11 @@
      *     so that if map is manually destroyed, we can unregister this.
      */
     unloadDestroy: null,
-
+    
     /**
      * Method: updateSizeDestroy
      * When the map is destroyed, we need to stop listening to updateSize
-     *    events: this method stores the function we need to unregister in
+     *    events: this method stores the function we need to unregister in 
      *    non-IE browsers.
      */
     updateSizeDestroy: null,
@@ -14994,32 +16117,38 @@
         if (!this.unloadDestroy) {
             return false;
         }
+        
+        // make sure panning doesn't continue after destruction
+        if(this.panTween) {
+            this.panTween.stop();
+            this.panTween = null;
+        }
 
         // map has been destroyed. dont do it again!
         OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);
         this.unloadDestroy = null;
 
         if (this.updateSizeDestroy) {
-            OpenLayers.Event.stopObserving(window, 'resize',
+            OpenLayers.Event.stopObserving(window, 'resize', 
                                            this.updateSizeDestroy);
         } else {
             this.events.unregister("resize", this, this.updateSize);
-        }
+        }    
+        
+        this.paddingForPopups = null;    
 
-        this.paddingForPopups = null;
-
         if (this.controls != null) {
             for (var i = this.controls.length - 1; i>=0; --i) {
                 this.controls[i].destroy();
-            }
+            } 
             this.controls = null;
         }
         if (this.layers != null) {
             for (var i = this.layers.length - 1; i>=0; --i) {
-                //pass 'false' to destroy so that map wont try to set a new
+                //pass 'false' to destroy so that map wont try to set a new 
                 // baselayer after each baselayer is removed
                 this.layers[i].destroy(false);
-            }
+            } 
             this.layers = null;
         }
         if (this.viewPortDiv) {
@@ -15194,7 +16323,7 @@
   /*     The following functions deal with adding and     */
   /*        removing Layers to and from the Map           */
   /*                                                      */
-  /********************************************************/
+  /********************************************************/         
 
     /**
      * APIMethod: getLayer
@@ -15204,7 +16333,7 @@
      * id - {String} A layer id
      *
      * Returns:
-     * {<OpenLayers.Layer>} The Layer with the corresponding id from the map's
+     * {<OpenLayers.Layer>} The Layer with the corresponding id from the map's 
      *                      layer collection, or null if not found.
      */
     getLayer: function(id) {
@@ -15221,11 +16350,11 @@
 
     /**
     * Method: setLayerZIndex
-    *
+    * 
     * Parameters:
-    * layer - {<OpenLayers.Layer>}
-    * zIdx - {int}
-    */
+    * layer - {<OpenLayers.Layer>} 
+    * zIdx - {int} 
+    */    
     setLayerZIndex: function (layer, zIdx) {
         layer.setZIndex(
             this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay']
@@ -15247,12 +16376,12 @@
     * APIMethod: addLayer
     *
     * Parameters:
-    * layer - {<OpenLayers.Layer>}
-    */
+    * layer - {<OpenLayers.Layer>} 
+    */    
     addLayer: function (layer) {
         for(var i=0, len=this.layers.length; i <len; i++) {
             if (this.layers[i] == layer) {
-                var msg = OpenLayers.i18n('layerAlreadyAdded',
+                var msg = OpenLayers.i18n('layerAlreadyAdded', 
                                                       {'layerName':layer.name});
                 OpenLayers.Console.warn(msg);
                 return false;
@@ -15262,8 +16391,10 @@
             layer.isBaseLayer = false;
         }
 
-        this.events.triggerEvent("preaddlayer", {layer: layer});
-
+        if (this.events.triggerEvent("preaddlayer", {layer: layer}) === false) {
+            return;
+        }
+        
         layer.div.className = "olLayerDiv";
         layer.div.style.overflow = "";
         this.setLayerZIndex(layer, this.layers.length);
@@ -15292,43 +16423,43 @@
     },
 
     /**
-    * APIMethod: addLayers
+    * APIMethod: addLayers 
     *
     * Parameters:
-    * layers - {Array(<OpenLayers.Layer>)}
-    */
+    * layers - {Array(<OpenLayers.Layer>)} 
+    */    
     addLayers: function (layers) {
         for (var i=0, len=layers.length; i<len; i++) {
             this.addLayer(layers[i]);
         }
     },
 
-    /**
+    /** 
      * APIMethod: removeLayer
-     * Removes a layer from the map by removing its visual element (the
-     *   layer.div property), then removing it from the map's internal list
-     *   of layers, setting the layer's map property to null.
-     *
+     * Removes a layer from the map by removing its visual element (the 
+     *   layer.div property), then removing it from the map's internal list 
+     *   of layers, setting the layer's map property to null. 
+     * 
      *   a "removelayer" event is triggered.
-     *
+     * 
      *   very worthy of mention is that simply removing a layer from a map
      *   will not cause the removal of any popups which may have been created
      *   by the layer. this is due to the fact that it was decided at some
-     *   point that popups would not belong to layers. thus there is no way
+     *   point that popups would not belong to layers. thus there is no way 
      *   for us to know here to which layer the popup belongs.
-     *
+     *    
      *     A simple solution to this is simply to call destroy() on the layer.
      *     the default OpenLayers.Layer class's destroy() function
      *     automatically takes care to remove itself from whatever map it has
-     *     been attached to.
-     *
-     *     The correct solution is for the layer itself to register an
-     *     event-handler on "removelayer" and when it is called, if it
+     *     been attached to. 
+     * 
+     *     The correct solution is for the layer itself to register an 
+     *     event-handler on "removelayer" and when it is called, if it 
      *     recognizes itself as the layer being removed, then it cycles through
      *     its own personal list of popups, removing them from the map.
-     *
+     * 
      * Parameters:
-     * layer - {<OpenLayers.Layer>}
+     * layer - {<OpenLayers.Layer>} 
      * setNewBaseLayer - {Boolean} Default is true
      */
     removeLayer: function(layer, setNewBaseLayer) {
@@ -15366,7 +16497,7 @@
 
     /**
      * APIMethod: getNumLayers
-     *
+     * 
      * Returns:
      * {Int} The number of layers attached to the map.
      */
@@ -15374,7 +16505,7 @@
         return this.layers.length;
     },
 
-    /**
+    /** 
      * APIMethod: getLayerIndex
      *
      * Parameters:
@@ -15387,8 +16518,8 @@
     getLayerIndex: function (layer) {
         return OpenLayers.Util.indexOf(this.layers, layer);
     },
-
-    /**
+    
+    /** 
      * APIMethod: setLayerIndex
      * Move the given layer to the specified (zero-based) index in the layer
      *     list, changing its z-index in the map display. Use
@@ -15397,8 +16528,8 @@
      *     raise base layers above overlays.
      *
      * Parameters:
-     * layer - {<OpenLayers.Layer>}
-     * idx - {int}
+     * layer - {<OpenLayers.Layer>} 
+     * idx - {int} 
      */
     setLayerIndex: function (layer, idx) {
         var base = this.getLayerIndex(layer);
@@ -15426,81 +16557,73 @@
         }
     },
 
-    /**
+    /** 
      * APIMethod: raiseLayer
-     * Change the index of the given layer by delta. If delta is positive,
+     * Change the index of the given layer by delta. If delta is positive, 
      *     the layer is moved up the map's layer stack; if delta is negative,
      *     the layer is moved down.  Again, note that this cannot (or at least
      *     should not) be effectively used to raise base layers above overlays.
      *
      * Paremeters:
-     * layer - {<OpenLayers.Layer>}
-     * delta - {int}
+     * layer - {<OpenLayers.Layer>} 
+     * delta - {int} 
      */
     raiseLayer: function (layer, delta) {
         var idx = this.getLayerIndex(layer) + delta;
         this.setLayerIndex(layer, idx);
     },
-
-    /**
+    
+    /** 
      * APIMethod: setBaseLayer
      * Allows user to specify one of the currently-loaded layers as the Map's
      *     new base layer.
-     *
+     * 
      * Parameters:
      * newBaseLayer - {<OpenLayers.Layer>}
      */
     setBaseLayer: function(newBaseLayer) {
-        var oldExtent = null;
-        if (this.baseLayer) {
-            oldExtent = this.baseLayer.getExtent();
-        }
-
+        
         if (newBaseLayer != this.baseLayer) {
-
-            // is newBaseLayer an already loaded layer?m
+          
+            // ensure newBaseLayer is already loaded
             if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
 
-                // make the old base layer invisible
+                // preserve center and scale when changing base layers
+                var center = this.getCenter();
+                var newResolution = OpenLayers.Util.getResolutionFromScale(
+                    this.getScale(), newBaseLayer.units
+                );
+
+                // make the old base layer invisible 
                 if (this.baseLayer != null && !this.allOverlays) {
                     this.baseLayer.setVisibility(false);
                 }
 
                 // set new baselayer
                 this.baseLayer = newBaseLayer;
-
-                // Increment viewRequestID since the baseLayer is
-                // changing. This is used by tiles to check if they should
+                
+                // Increment viewRequestID since the baseLayer is 
+                // changing. This is used by tiles to check if they should 
                 // draw themselves.
                 this.viewRequestID++;
-                if(!this.allOverlays) {
-                    this.baseLayer.visibility = true;
+                if(!this.allOverlays || this.baseLayer.visibility) {
+                    this.baseLayer.setVisibility(true);
                 }
 
-                //redraw all layers
-                var center = this.getCenter();
+                // recenter the map
                 if (center != null) {
-
-                    //either get the center from the old Extent or just from
-                    // the current center of the map.
-                    var newCenter = (oldExtent)
-                        ? oldExtent.getCenterLonLat()
-                        : center;
-
-                    //the new zoom will either come from the old Extent or
-                    // from the current resolution of the map
-                    var newZoom = (oldExtent)
-                        ? this.getZoomForExtent(oldExtent, true)
-                        : this.getZoomForResolution(this.resolution, true);
-
+                    // new zoom level derived from old scale
+                    var newZoom = this.getZoomForResolution(
+                        newResolution || this.resolution, true
+                    );
                     // zoom and force zoom change
-                    this.setCenter(newCenter, newZoom, false, true);
+                    this.setCenter(center, newZoom, false, true);
                 }
 
                 this.events.triggerEvent("changebaselayer", {
                     layer: this.baseLayer
                 });
-            }
+            }        
         }
     },
 
@@ -15512,39 +16635,63 @@
   /*     The following functions deal with adding and     */
   /*        removing Controls to and from the Map         */
   /*                                                      */
-  /********************************************************/
+  /********************************************************/         
 
     /**
      * APIMethod: addControl
-     *
+     * Add the passed over control to the map. Optionally 
+     *     position the control at the given pixel.
+     * 
      * Parameters:
      * control - {<OpenLayers.Control>}
      * px - {<OpenLayers.Pixel>}
-     */
+     */    
     addControl: function (control, px) {
         this.controls.push(control);
         this.addControlToMap(control, px);
     },
+    
+    /**
+     * APIMethod: addControls
+     * Add all of the passed over controls to the map. 
+     *     You can pass over an optional second array
+     *     with pixel-objects to position the controls.
+     *     The indices of the two arrays should match and
+     *     you can add null as pixel for those controls 
+     *     you want to be autopositioned.   
+     *     
+     * Parameters:
+     * controls - {Array(<OpenLayers.Control>)}
+     * pixels - {Array(<OpenLayers.Pixel>)}
+     */    
+    addControls: function (controls, pixels) {
+        var pxs = (arguments.length === 1) ? [] : pixels;
+        for (var i=0, len=controls.length; i<len; i++) {
+            var ctrl = controls[i];
+            var px = (pxs[i]) ? pxs[i] : null;
+            this.addControl( ctrl, px );
+        }
+    },
 
     /**
      * Method: addControlToMap
-     *
+     * 
      * Parameters:
-     *
+     * 
      * control - {<OpenLayers.Control>}
      * px - {<OpenLayers.Pixel>}
-     */
+     */    
     addControlToMap: function (control, px) {
         // If a control doesn't have a div at this point, it belongs in the
         // viewport.
         control.outsideViewport = (control.div != null);
-
-        // If the map has a displayProjection, and the control doesn't, set
+        
+        // If the map has a displayProjection, and the control doesn't, set 
         // the display projection.
         if (this.displayProjection && !control.displayProjection) {
             control.displayProjection = this.displayProjection;
-        }
-
+        }    
+        
         control.setMap(this);
         var div = control.draw(px);
         if (div) {
@@ -15554,19 +16701,22 @@
                 this.viewPortDiv.appendChild( div );
             }
         }
+        if(control.autoActivate) {
+            control.activate();
+        }
     },
-
+    
     /**
      * APIMethod: getControl
-     *
+     * 
      * Parameters:
      * id - {String} ID of the control to return.
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Control>} The control from the map's list of controls
-     *                        which has a matching 'id'. If none found,
+     * {<OpenLayers.Control>} The control from the map's list of controls 
+     *                        which has a matching 'id'. If none found, 
      *                        returns null.
-     */
+     */    
     getControl: function (id) {
         var returnControl = null;
         for(var i=0, len=this.controls.length; i<len; i++) {
@@ -15578,16 +16728,16 @@
         }
         return returnControl;
     },
-
-    /**
+    
+    /** 
      * APIMethod: removeControl
-     * Remove a control from the map. Removes the control both from the map
-     *     object's internal array of controls, as well as from the map's
+     * Remove a control from the map. Removes the control both from the map 
+     *     object's internal array of controls, as well as from the map's 
      *     viewPort (assuming the control was not added outsideViewport)
-     *
+     * 
      * Parameters:
      * control - {<OpenLayers.Control>} The control to remove.
-     */
+     */    
     removeControl: function (control) {
         //make sure control is non-null and actually part of our map
         if ( (control) && (control == this.getControl(control.id)) ) {
@@ -15605,11 +16755,11 @@
   /*     The following functions deal with adding and     */
   /*        removing Popups to and from the Map           */
   /*                                                      */
-  /********************************************************/
+  /********************************************************/         
 
-    /**
+    /** 
      * APIMethod: addPopup
-     *
+     * 
      * Parameters:
      * popup - {<OpenLayers.Popup>}
      * exclusive - {Boolean} If true, closes all other popups first
@@ -15632,10 +16782,10 @@
             this.layerContainerDiv.appendChild(popupDiv);
         }
     },
-
-    /**
+    
+    /** 
     * APIMethod: removePopup
-    *
+    * 
     * Parameters:
     * popup - {<OpenLayers.Popup>}
     */
@@ -15656,15 +16806,15 @@
   /*   The following functions deal with the access to    */
   /*    and maintenance of the size of the container div  */
   /*                                                      */
-  /********************************************************/
+  /********************************************************/     
 
     /**
      * APIMethod: getSize
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Size>} An <OpenLayers.Size> object that represents the
-     *                     size, in pixels, of the div into which OpenLayers
-     *                     has been loaded.
+     * {<OpenLayers.Size>} An <OpenLayers.Size> object that represents the 
+     *                     size, in pixels, of the div into which OpenLayers 
+     *                     has been loaded. 
      *                     Note - A clone() of this locally cached variable is
      *                     returned, so as not to allow users to modify it.
      */
@@ -15679,55 +16829,55 @@
     /**
      * APIMethod: updateSize
      * This function should be called by any external code which dynamically
-     *     changes the size of the map div (because mozilla wont let us catch
+     *     changes the size of the map div (because mozilla wont let us catch 
      *     the "onresize" for an element)
      */
     updateSize: function() {
         // the div might have moved on the page, also
-        this.events.clearMouseCache();
         var newSize = this.getCurrentSize();
-        var oldSize = this.getSize();
-        if (oldSize == null) {
-            this.size = oldSize = newSize;
-        }
-        if (!newSize.equals(oldSize)) {
-
-            // store the new size
-            this.size = newSize;
-
-            //notify layers of mapresize
-            for(var i=0, len=this.layers.length; i<len; i++) {
-                this.layers[i].onMapResize();
+        if (newSize && !isNaN(newSize.h) && !isNaN(newSize.w)) {
+            this.events.clearMouseCache();
+            var oldSize = this.getSize();
+            if (oldSize == null) {
+                this.size = oldSize = newSize;
             }
-
-            if (this.baseLayer != null) {
-                var center = new OpenLayers.Pixel(newSize.w /2, newSize.h / 2);
-                var centerLL = this.getLonLatFromViewPortPx(center);
-                var zoom = this.getZoom();
-                this.zoom = null;
-                this.setCenter(this.getCenter(), zoom);
+            if (!newSize.equals(oldSize)) {
+                
+                // store the new size
+                this.size = newSize;
+    
+                //notify layers of mapresize
+                for(var i=0, len=this.layers.length; i<len; i++) {
+                    this.layers[i].onMapResize();                
+                }
+    
+                var center = this.getCenter();
+    
+                if (this.baseLayer != null && center != null) {
+                    var zoom = this.getZoom();
+                    this.zoom = null;
+                    this.setCenter(center, zoom);
+                }
+    
             }
-
         }
     },
-
+    
     /**
      * Method: getCurrentSize
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Size>} A new <OpenLayers.Size> object with the dimensions
+     * {<OpenLayers.Size>} A new <OpenLayers.Size> object with the dimensions 
      *                     of the map div
      */
     getCurrentSize: function() {
 
-        var size = new OpenLayers.Size(this.div.clientWidth,
+        var size = new OpenLayers.Size(this.div.clientWidth, 
                                        this.div.clientHeight);
 
-        // Workaround for the fact that hidden elements return 0 for size.
         if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
-            var dim = OpenLayers.Element.getDimensions(this.div);
-            size.w = dim.width;
-            size.h = dim.height;
+            size.w = this.div.offsetWidth;
+            size.h = this.div.offsetHeight;
         }
         if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
             size.w = parseInt(this.div.style.width);
@@ -15736,39 +16886,39 @@
         return size;
     },
 
-    /**
+    /** 
      * Method: calculateBounds
-     *
+     * 
      * Parameters:
      * center - {<OpenLayers.LonLat>} Default is this.getCenter()
-     * resolution - {float} Default is this.getResolution()
-     *
+     * resolution - {float} Default is this.getResolution() 
+     * 
      * Returns:
-     * {<OpenLayers.Bounds>} A bounds based on resolution, center, and
+     * {<OpenLayers.Bounds>} A bounds based on resolution, center, and 
      *                       current mapsize.
      */
     calculateBounds: function(center, resolution) {
 
         var extent = null;
-
+        
         if (center == null) {
             center = this.getCenter();
-        }
+        }                
         if (resolution == null) {
             resolution = this.getResolution();
         }
-
+    
         if ((center != null) && (resolution != null)) {
 
             var size = this.getSize();
             var w_deg = size.w * resolution;
             var h_deg = size.h * resolution;
-
+        
             extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
                                            center.lat - h_deg / 2,
                                            center.lon + w_deg / 2,
                                            center.lat + h_deg / 2);
-
+        
         }
 
         return extent;
@@ -15786,7 +16936,7 @@
   /********************************************************/
     /**
      * APIMethod: getCenter
-     *
+     * 
      * Returns:
      * {<OpenLayers.LonLat>}
      */
@@ -15801,18 +16951,18 @@
 
     /**
      * APIMethod: getZoom
-     *
+     * 
      * Returns:
      * {Integer}
      */
     getZoom: function () {
         return this.zoom;
     },
-
-    /**
+    
+    /** 
      * APIMethod: pan
      * Allows user to pan by a value of screen pixels
-     *
+     * 
      * Parameters:
      * dx - {Integer}
      * dy - {Integer}
@@ -15831,7 +16981,7 @@
 
         // adjust
         var newCenterPx = centerPx.add(dx, dy);
-
+        
         // only call setCenter if not dragging or there has been a change
         if (!options.dragging || !newCenterPx.equals(centerPx)) {
             var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
@@ -15839,16 +16989,16 @@
                 this.panTo(newCenterLonLat);
             } else {
                 this.setCenter(newCenterLonLat, null, options.dragging);
-            }
+            }    
         }
 
    },
-
-   /**
+   
+   /** 
      * APIMethod: panTo
      * Allows user to pan to a new lonlat
      * If the new lonlat is in the current extent the map will slide smoothly
-     *
+     * 
      * Parameters:
      * lonlat - {<OpenLayers.Lonlat>}
      */
@@ -15902,13 +17052,13 @@
     /**
      * APIMethod: setCenter
      * Set the map center (and optionally, the zoom level).
-     *
+     * 
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>} The new center location.
      * zoom - {Integer} Optional zoom level.
-     * dragging - {Boolean} Specifies whether or not to trigger
+     * dragging - {Boolean} Specifies whether or not to trigger 
      *                      movestart/end events
-     * forceZoomChange - {Boolean} Specifies whether or not to trigger zoom
+     * forceZoomChange - {Boolean} Specifies whether or not to trigger zoom 
      *                             change events (needed on baseLayer change)
      *
      * TBD: reconsider forceZoomChange in 3.0
@@ -15930,9 +17080,15 @@
      * options - {Object}
      */
     moveTo: function(lonlat, zoom, options) {
-        if (!options) {
+        if (!options) { 
             options = {};
         }
+        if (zoom != null) {
+            zoom = parseFloat(zoom);
+            if (!this.fractionalZoom) {
+                zoom = Math.round(zoom);
+            }
+        }
         // dragging is false by default
         var dragging = options.dragging;
         // forceZoomChange is false by default
@@ -15942,51 +17098,51 @@
 
         if (this.panTween && options.caller == "setCenter") {
             this.panTween.stop();
-        }
-
+        }    
+             
         if (!this.center && !this.isValidLonLat(lonlat)) {
             lonlat = this.maxExtent.getCenterLonLat();
         }
 
         if(this.restrictedExtent != null) {
             // In 3.0, decide if we want to change interpretation of maxExtent.
-            if(lonlat == null) {
-                lonlat = this.getCenter();
+            if(lonlat == null) { 
+                lonlat = this.getCenter(); 
             }
-            if(zoom == null) {
-                zoom = this.getZoom();
+            if(zoom == null) { 
+                zoom = this.getZoom(); 
             }
             var resolution = this.getResolutionForZoom(zoom);
-            var extent = this.calculateBounds(lonlat, resolution);
+            var extent = this.calculateBounds(lonlat, resolution); 
             if(!this.restrictedExtent.containsBounds(extent)) {
-                var maxCenter = this.restrictedExtent.getCenterLonLat();
-                if(extent.getWidth() > this.restrictedExtent.getWidth()) {
-                    lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat);
+                var maxCenter = this.restrictedExtent.getCenterLonLat(); 
+                if(extent.getWidth() > this.restrictedExtent.getWidth()) { 
+                    lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat); 
                 } else if(extent.left < this.restrictedExtent.left) {
                     lonlat = lonlat.add(this.restrictedExtent.left -
-                                        extent.left, 0);
-                } else if(extent.right > this.restrictedExtent.right) {
+                                        extent.left, 0); 
+                } else if(extent.right > this.restrictedExtent.right) { 
                     lonlat = lonlat.add(this.restrictedExtent.right -
-                                        extent.right, 0);
-                }
-                if(extent.getHeight() > this.restrictedExtent.getHeight()) {
-                    lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat);
-                } else if(extent.bottom < this.restrictedExtent.bottom) {
+                                        extent.right, 0); 
+                } 
+                if(extent.getHeight() > this.restrictedExtent.getHeight()) { 
+                    lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat); 
+                } else if(extent.bottom < this.restrictedExtent.bottom) { 
                     lonlat = lonlat.add(0, this.restrictedExtent.bottom -
-                                        extent.bottom);
-                }
-                else if(extent.top > this.restrictedExtent.top) {
+                                        extent.bottom); 
+                } 
+                else if(extent.top > this.restrictedExtent.top) { 
                     lonlat = lonlat.add(0, this.restrictedExtent.top -
-                                        extent.top);
-                }
+                                        extent.top); 
+                } 
             }
         }
-
+        
         var zoomChanged = forceZoomChange || (
-                            (this.isValidZoomLevel(zoom)) &&
+                            (this.isValidZoomLevel(zoom)) && 
                             (zoom != this.getZoom()) );
 
-        var centerChanged = (this.isValidLonLat(lonlat)) &&
+        var centerChanged = (this.isValidLonLat(lonlat)) && 
                             (!lonlat.equals(this.center));
 
 
@@ -15998,7 +17154,7 @@
             }
 
             if (centerChanged) {
-                if ((!zoomChanged) && (this.center)) {
+                if ((!zoomChanged) && (this.center)) { 
                     // if zoom hasnt changed, just slide layerContainer
                     //  (must be done before setting this.center to new value)
                     this.centerLayerContainer(lonlat);
@@ -16018,12 +17174,12 @@
                 this.resolution = this.getResolutionForZoom(zoom);
                 // zoom level has changed, increment viewRequestID.
                 this.viewRequestID++;
-            }
-
+            }    
+            
             var bounds = this.getExtent();
+            
+            //send the move call to the baselayer and all the overlays    
 
-            //send the move call to the baselayer and all the overlays
-
             if(this.baseLayer.visibility) {
                 this.baseLayer.moveTo(bounds, zoomChanged, dragging);
                 if(dragging) {
@@ -16034,9 +17190,9 @@
                     );
                 }
             }
-
+            
             bounds = this.baseLayer.getExtent();
-
+            
             for (var i=0, len=this.layers.length; i<len; i++) {
                 var layer = this.layers[i];
                 if (layer !== this.baseLayer && !layer.isBaseLayer) {
@@ -16064,18 +17220,18 @@
                             );
                         }
                     }
-                }
+                }                
             }
-
+            
             if (zoomChanged) {
                 //redraw popups
                 for (var i=0, len=this.popups.length; i<len; i++) {
                     this.popups[i].updatePosition();
                 }
-            }
-
+            }    
+            
             this.events.triggerEvent("move");
-
+    
             if (zoomChanged) { this.events.triggerEvent("zoomend"); }
         }
 
@@ -16083,16 +17239,16 @@
         if (!dragging && !noEvent) {
             this.events.triggerEvent("moveend");
         }
-
+        
         // Store the map dragging state for later use
-        this.dragging = !!dragging;
+        this.dragging = !!dragging; 
 
     },
 
-    /**
+    /** 
      * Method: centerLayerContainer
      * This function takes care to recenter the layerContainerDiv.
-     *
+     * 
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>}
      */
@@ -16109,26 +17265,26 @@
 
     /**
      * Method: isValidZoomLevel
-     *
+     * 
      * Parameters:
      * zoomLevel - {Integer}
-     *
+     * 
      * Returns:
-     * {Boolean} Whether or not the zoom level passed in is non-null and
+     * {Boolean} Whether or not the zoom level passed in is non-null and 
      *           within the min/max range of zoom levels.
      */
     isValidZoomLevel: function(zoomLevel) {
        return ( (zoomLevel != null) &&
-                (zoomLevel >= 0) &&
+                (zoomLevel >= 0) && 
                 (zoomLevel < this.getNumZoomLevels()) );
     },
-
+    
     /**
      * Method: isValidLonLat
-     *
+     * 
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>}
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the lonlat passed in is non-null and within
      *           the maxExtent bounds
@@ -16137,7 +17293,7 @@
         var valid = false;
         if (lonlat != null) {
             var maxExtent = this.getMaxExtent();
-            valid = maxExtent.containsLonLat(lonlat);
+            valid = maxExtent.containsLonLat(lonlat);        
         }
         return valid;
     },
@@ -16149,25 +17305,25 @@
   /*    Accessor functions to Layer Options parameters    */
   /*                                                      */
   /********************************************************/
-
+    
     /**
      * APIMethod: getProjection
-     * This method returns a string representing the projection. In
+     * This method returns a string representing the projection. In 
      *     the case of projection support, this will be the srsCode which
      *     is loaded -- otherwise it will simply be the string value that
      *     was passed to the projection at startup.
      *
      * FIXME: In 3.0, we will remove getProjectionObject, and instead
-     *     return a Projection object from this function.
-     *
+     *     return a Projection object from this function. 
+     * 
      * Returns:
-     * {String} The Projection string from the base layer or null.
+     * {String} The Projection string from the base layer or null. 
      */
     getProjection: function() {
         var projection = this.getProjectionObject();
         return projection ? projection.getCode() : null;
     },
-
+    
     /**
      * APIMethod: getProjectionObject
      * Returns the projection obect from the baselayer.
@@ -16182,10 +17338,10 @@
         }
         return projection;
     },
-
+    
     /**
      * APIMethod: getMaxResolution
-     *
+     * 
      * Returns:
      * {String} The Map's Maximum Resolution
      */
@@ -16196,19 +17352,19 @@
         }
         return maxResolution;
     },
-
+        
     /**
      * APIMethod: getMaxExtent
      *
      * Parameters:
-     * options - {Object}
-     *
+     * options - {Object} 
+     * 
      * Allowed Options:
-     * restricted - {Boolean} If true, returns restricted extent (if it is
+     * restricted - {Boolean} If true, returns restricted extent (if it is 
      *     available.)
      *
      * Returns:
-     * {<OpenLayers.Bounds>} The maxExtent property as set on the current
+     * {<OpenLayers.Bounds>} The maxExtent property as set on the current 
      *     baselayer, unless the 'restricted' option is set, in which case
      *     the 'restrictedExtent' option from the map is returned (if it
      *     is set).
@@ -16219,15 +17375,15 @@
             maxExtent = this.restrictedExtent;
         } else if (this.baseLayer != null) {
             maxExtent = this.baseLayer.maxExtent;
-        }
+        }        
         return maxExtent;
     },
-
+    
     /**
      * APIMethod: getNumZoomLevels
-     *
+     * 
      * Returns:
-     * {Integer} The total number of zoom levels that can be displayed by the
+     * {Integer} The total number of zoom levels that can be displayed by the 
      *           current baseLayer.
      */
     getNumZoomLevels: function() {
@@ -16251,10 +17407,10 @@
 
     /**
      * APIMethod: getExtent
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
-     *                       bounds of the current viewPort.
+     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
+     *                       bounds of the current viewPort. 
      *                       If no baselayer is set, returns null.
      */
     getExtent: function () {
@@ -16267,24 +17423,29 @@
 
     /**
      * APIMethod: getResolution
-     *
+     * 
      * Returns:
-     * {Float} The current resolution of the map.
+     * {Float} The current resolution of the map. 
      *         If no baselayer is set, returns null.
      */
     getResolution: function () {
         var resolution = null;
         if (this.baseLayer != null) {
             resolution = this.baseLayer.getResolution();
+        } else if(this.allOverlays === true && this.layers.length > 0) {
+            // while adding the 1st layer to the map in allOverlays mode,
+            // this.baseLayer is not set yet when we need the resolution
+            // for calculateInRange.
+            resolution = this.layers[0].getResolution();
         }
         return resolution;
     },
 
     /**
      * APIMethod: getUnits
-     *
+     * 
      * Returns:
-     * {Float} The current units of the map.
+     * {Float} The current units of the map. 
      *         If no baselayer is set, returns null.
      */
     getUnits: function () {
@@ -16297,9 +17458,9 @@
 
      /**
       * APIMethod: getScale
-      *
+      * 
       * Returns:
-      * {Float} The current scale denominator of the map.
+      * {Float} The current scale denominator of the map. 
       *         If no baselayer is set, returns null.
       */
     getScale: function () {
@@ -16315,14 +17476,14 @@
 
     /**
      * APIMethod: getZoomForExtent
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * bounds - {<OpenLayers.Bounds>}
-     * closest - {Boolean} Find the zoom level that most closely fits the
-     *     specified bounds. Note that this may result in a zoom that does
+     * closest - {Boolean} Find the zoom level that most closely fits the 
+     *     specified bounds. Note that this may result in a zoom that does 
      *     not exactly contain the entire extent.
      *     Default is false.
-     *
+     * 
      * Returns:
      * {Integer} A suitable zoom level for the specified bounds.
      *           If no baselayer is set, returns null.
@@ -16337,10 +17498,10 @@
 
     /**
      * APIMethod: getResolutionForZoom
-     *
+     * 
      * Parameter:
      * zoom - {Float}
-     *
+     * 
      * Returns:
      * {Float} A suitable resolution for the specified zoom.  If no baselayer
      *     is set, returns null.
@@ -16355,17 +17516,17 @@
 
     /**
      * APIMethod: getZoomForResolution
-     *
+     * 
      * Parameter:
      * resolution - {Float}
-     * closest - {Boolean} Find the zoom level that corresponds to the absolute
+     * closest - {Boolean} Find the zoom level that corresponds to the absolute 
      *     closest resolution, which may result in a zoom whose corresponding
      *     resolution is actually smaller than we would have desired (if this
      *     is being called from a getZoomForExtent() call, then this means that
-     *     the returned zoom index might not actually contain the entire
+     *     the returned zoom index might not actually contain the entire 
      *     extent specified... but it'll be close).
      *     Default is false.
-     *
+     * 
      * Returns:
      * {Integer} A suitable zoom level for the specified resolution.
      *           If no baselayer is set, returns null.
@@ -16387,11 +17548,11 @@
   /*               the setCenter() function               */
   /*                                                      */
   /********************************************************/
-
-    /**
+  
+    /** 
      * APIMethod: zoomTo
      * Zoom to a specific zoom level
-     *
+     * 
      * Parameters:
      * zoom - {Integer}
      */
@@ -16400,20 +17561,20 @@
             this.setCenter(null, zoom);
         }
     },
-
+    
     /**
      * APIMethod: zoomIn
-     *
+     * 
      * Parameters:
      * zoom - {int}
      */
     zoomIn: function() {
         this.zoomTo(this.getZoom() + 1);
     },
-
+    
     /**
      * APIMethod: zoomOut
-     *
+     * 
      * Parameters:
      * zoom - {int}
      */
@@ -16424,35 +17585,35 @@
     /**
      * APIMethod: zoomToExtent
      * Zoom to the passed in bounds, recenter
-     *
+     * 
      * Parameters:
      * bounds - {<OpenLayers.Bounds>}
-     * closest - {Boolean} Find the zoom level that most closely fits the
-     *     specified bounds. Note that this may result in a zoom that does
+     * closest - {Boolean} Find the zoom level that most closely fits the 
+     *     specified bounds. Note that this may result in a zoom that does 
      *     not exactly contain the entire extent.
      *     Default is false.
-     *
+     * 
      */
     zoomToExtent: function(bounds, closest) {
         var center = bounds.getCenterLonLat();
         if (this.baseLayer.wrapDateLine) {
             var maxExtent = this.getMaxExtent();
 
-            //fix straddling bounds (in the case of a bbox that straddles the
-            // dateline, it's left and right boundaries will appear backwards.
+            //fix straddling bounds (in the case of a bbox that straddles the 
+            // dateline, it's left and right boundaries will appear backwards. 
             // we fix this by allowing a right value that is greater than the
-            // max value at the dateline -- this allows us to pass a valid
+            // max value at the dateline -- this allows us to pass a valid 
             // bounds to calculate zoom)
             //
             bounds = bounds.clone();
             while (bounds.right < bounds.left) {
                 bounds.right += maxExtent.getWidth();
             }
-            //if the bounds was straddling (see above), then the center point
+            //if the bounds was straddling (see above), then the center point 
             // we got from it was wrong. So we take our new bounds and ask it
-            // for the center. Because our new bounds is at least partially
-            // outside the bounds of maxExtent, the new calculated center
-            // might also be. We don't want to pass a bad center value to
+            // for the center. Because our new bounds is at least partially 
+            // outside the bounds of maxExtent, the new calculated center 
+            // might also be. We don't want to pass a bad center value to 
             // setCenter, so we have it wrap itself across the date line.
             //
             center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
@@ -16460,15 +17621,15 @@
         this.setCenter(center, this.getZoomForExtent(bounds, closest));
     },
 
-    /**
+    /** 
      * APIMethod: zoomToMaxExtent
      * Zoom to the full extent and recenter.
      *
      * Parameters:
-     * options -
-     *
+     * options - 
+     * 
      * Allowed Options:
-     * restricted - {Boolean} True to zoom to restricted extent if it is
+     * restricted - {Boolean} True to zoom to restricted extent if it is 
      *     set. Defaults to true.
      */
     zoomToMaxExtent: function(options) {
@@ -16476,25 +17637,25 @@
         var restricted = (options) ? options.restricted : true;
 
         var maxExtent = this.getMaxExtent({
-            'restricted': restricted
+            'restricted': restricted 
         });
         this.zoomToExtent(maxExtent);
     },
 
-    /**
+    /** 
      * APIMethod: zoomToScale
-     * Zoom to a specified scale
-     *
+     * Zoom to a specified scale 
+     * 
      * Parameters:
      * scale - {float}
-     * closest - {Boolean} Find the zoom level that most closely fits the
-     *     specified scale. Note that this may result in a zoom that does
+     * closest - {Boolean} Find the zoom level that most closely fits the 
+     *     specified scale. Note that this may result in a zoom that does 
      *     not exactly contain the entire extent.
      *     Default is false.
-     *
+     * 
      */
     zoomToScale: function(scale, closest) {
-        var res = OpenLayers.Util.getResolutionFromScale(scale,
+        var res = OpenLayers.Util.getResolutionFromScale(scale, 
                                                          this.baseLayer.units);
         var size = this.getSize();
         var w_deg = size.w * res;
@@ -16507,7 +17668,7 @@
                                            center.lat + h_deg / 2);
         this.zoomToExtent(extent, closest);
     },
-
+    
   /********************************************************/
   /*                                                      */
   /*             Translation Functions                    */
@@ -16516,24 +17677,24 @@
   /*           LonLat, LayerPx, and ViewPortPx            */
   /*                                                      */
   /********************************************************/
-
+      
   //
   // TRANSLATION: LonLat <-> ViewPortPx
   //
 
     /**
      * Method: getLonLatFromViewPortPx
-     *
+     * 
      * Parameters:
      * viewPortPx - {<OpenLayers.Pixel>}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
+     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view 
      *                       port <OpenLayers.Pixel>, translated into lon/lat
      *                       by the current base layer.
      */
     getLonLatFromViewPortPx: function (viewPortPx) {
-        var lonlat = null;
+        var lonlat = null; 
         if (this.baseLayer != null) {
             lonlat = this.baseLayer.getLonLatFromViewPortPx(viewPortPx);
         }
@@ -16542,37 +17703,37 @@
 
     /**
      * APIMethod: getViewPortPxFromLonLat
-     *
+     * 
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
-     *                      <OpenLayers.LonLat>, translated into view port
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in 
+     *                      <OpenLayers.LonLat>, translated into view port 
      *                      pixels by the current base layer.
      */
     getViewPortPxFromLonLat: function (lonlat) {
-        var px = null;
+        var px = null; 
         if (this.baseLayer != null) {
             px = this.baseLayer.getViewPortPxFromLonLat(lonlat);
         }
         return px;
     },
 
-
+    
   //
   // CONVENIENCE TRANSLATION FUNCTIONS FOR API
   //
 
     /**
      * APIMethod: getLonLatFromPixel
-     *
+     * 
      * Parameters:
      * px - {<OpenLayers.Pixel>}
      *
      * Returns:
      * {<OpenLayers.LonLat>} An OpenLayers.LonLat corresponding to the given
-     *                       OpenLayers.Pixel, translated into lon/lat by the
+     *                       OpenLayers.Pixel, translated into lon/lat by the 
      *                       current base layer
      */
     getLonLatFromPixel: function (px) {
@@ -16584,12 +17745,12 @@
      * Returns a pixel location given a map location.  The map location is
      *     translated to an integer pixel location (in viewport pixel
      *     coordinates) by the current base layer.
-     *
+     * 
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>} A map location.
-     *
-     * Returns:
-     * {<OpenLayers.Pixel>} An OpenLayers.Pixel corresponding to the
+     * 
+     * Returns: 
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel corresponding to the 
      *     <OpenLayers.LonLat> translated into view port pixels by the current
      *     base layer.
      */
@@ -16599,6 +17760,39 @@
         px.y = Math.round(px.y);
         return px;
     },
+    
+    /**
+     * Method: getGeodesicPixelSize
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} The pixel to get the geodesic length for. If
+     *     not provided, the center pixel of the map viewport will be used.
+     * 
+     * Returns:
+     * {<OpenLayers.Size>} The geodesic size of the pixel in kilometers.
+     */
+    getGeodesicPixelSize: function(px) {
+        var lonlat = px ? this.getLonLatFromPixel(px) : (this.getCenter() ||
+            new OpenLayers.LonLat(0, 0));
+        var res = this.getResolution();
+        var left = lonlat.add(-res / 2, 0);
+        var right = lonlat.add(res / 2, 0);
+        var bottom = lonlat.add(0, -res / 2);
+        var top = lonlat.add(0, res / 2);
+        var dest = new OpenLayers.Projection("EPSG:4326");
+        var source = this.getProjectionObject() || dest;
+        if(!source.equals(dest)) {
+            left.transform(source, dest);
+            right.transform(source, dest);
+            bottom.transform(source, dest);
+            top.transform(source, dest);
+        }
+        
+        return new OpenLayers.Size(
+            OpenLayers.Util.distVincenty(left, right),
+            OpenLayers.Util.distVincenty(bottom, top)
+        );
+    },
 
 
 
@@ -16608,12 +17802,12 @@
 
     /**
      * APIMethod: getViewPortPxFromLayerPx
-     *
+     * 
      * Parameters:
      * layerPx - {<OpenLayers.Pixel>}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Pixel>} Layer Pixel translated into ViewPort Pixel
+     * {<OpenLayers.Pixel>} Layer Pixel translated into ViewPort Pixel 
      *                      coordinates
      */
     getViewPortPxFromLayerPx:function(layerPx) {
@@ -16621,19 +17815,19 @@
         if (layerPx != null) {
             var dX = parseInt(this.layerContainerDiv.style.left);
             var dY = parseInt(this.layerContainerDiv.style.top);
-            viewPortPx = layerPx.add(dX, dY);
+            viewPortPx = layerPx.add(dX, dY);            
         }
         return viewPortPx;
     },
-
+    
     /**
      * APIMethod: getLayerPxFromViewPortPx
-     *
+     * 
      * Parameters:
      * viewPortPx - {<OpenLayers.Pixel>}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Pixel>} ViewPort Pixel translated into Layer Pixel
+     * {<OpenLayers.Pixel>} ViewPort Pixel translated into Layer Pixel 
      *                      coordinates
      */
     getLayerPxFromViewPortPx:function(viewPortPx) {
@@ -16648,14 +17842,14 @@
         }
         return layerPx;
     },
-
+    
   //
   // TRANSLATION: LonLat <-> LayerPx
   //
 
     /**
      * Method: getLonLatFromLayerPx
-     *
+     * 
      * Parameters:
      * px - {<OpenLayers.Pixel>}
      *
@@ -16665,24 +17859,24 @@
     getLonLatFromLayerPx: function (px) {
        //adjust for displacement of layerContainerDiv
        px = this.getViewPortPxFromLayerPx(px);
-       return this.getLonLatFromViewPortPx(px);
+       return this.getLonLatFromViewPortPx(px);         
     },
-
+    
     /**
      * APIMethod: getLayerPxFromLonLat
-     *
+     * 
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>} lonlat
      *
      * Returns:
-     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
-     *                      <OpenLayers.LonLat>, translated into layer pixels
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in 
+     *                      <OpenLayers.LonLat>, translated into layer pixels 
      *                      by the current base layer
      */
     getLayerPxFromLonLat: function (lonlat) {
        //adjust for displacement of layerContainerDiv
        var px = this.getPixelFromLonLat(lonlat);
-       return this.getLayerPxFromViewPortPx(px);
+       return this.getLayerPxFromViewPortPx(px);         
     },
 
     CLASS_NAME: "OpenLayers.Map"
@@ -16702,8 +17896,9 @@
     OpenLayers/Marker.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -16714,8 +17909,8 @@
 
 /**
  * Class: OpenLayers.Marker
- * Instances of OpenLayers.Marker are a combination of a
- * <OpenLayers.LonLat> and an <OpenLayers.Icon>.
+ * Instances of OpenLayers.Marker are a combination of a 
+ * <OpenLayers.LonLat> and an <OpenLayers.Icon>.  
  *
  * Markers are generally added to a special layer called
  * <OpenLayers.Layer.Markers>.
@@ -16725,9 +17920,9 @@
  * var markers = new OpenLayers.Layer.Markers( "Markers" );
  * map.addLayer(markers);
  *
- * var size = new OpenLayers.Size(10,17);
+ * var size = new OpenLayers.Size(21,25);
  * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
- * var icon = new OpenLayers.Icon('http://boston.openguides.org/markers/AQUA.png',size,offset);
+ * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset);
  * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));
  * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));
  *
@@ -16739,32 +17934,32 @@
  * markers using that same icon.
  */
 OpenLayers.Marker = OpenLayers.Class({
-
-    /**
-     * Property: icon
+    
+    /** 
+     * Property: icon 
      * {<OpenLayers.Icon>} The icon used by this marker.
      */
     icon: null,
 
-    /**
-     * Property: lonlat
+    /** 
+     * Property: lonlat 
      * {<OpenLayers.LonLat>} location of object
      */
     lonlat: null,
-
-    /**
-     * Property: events
+    
+    /** 
+     * Property: events 
      * {<OpenLayers.Events>} the event handler.
      */
     events: null,
-
-    /**
-     * Property: map
+    
+    /** 
+     * Property: map 
      * {<OpenLayers.Map>} the map this marker is attached to
      */
     map: null,
-
-    /**
+    
+    /** 
      * Constructor: OpenLayers.Marker
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>} the position of this marker
@@ -16772,7 +17967,7 @@
      */
     initialize: function(lonlat, icon) {
         this.lonlat = lonlat;
-
+        
         var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
         if (this.icon == null) {
             this.icon = newIcon;
@@ -16784,10 +17979,10 @@
         }
         this.events = new OpenLayers.Events(this, this.icon.imageDiv, null);
     },
-
+    
     /**
      * APIMethod: destroy
-     * Destroy the marker. You must first remove the marker from any
+     * Destroy the marker. You must first remove the marker from any 
      * layer which it has been added to, or you will get buggy behavior.
      * (This can not be done within the marker since the marker does not
      * know which layer it is attached to.)
@@ -16806,23 +18001,23 @@
             this.icon = null;
         }
     },
-
-    /**
+    
+    /** 
     * Method: draw
     * Calls draw on the icon, and returns that output.
-    *
+    * 
     * Parameters:
     * px - {<OpenLayers.Pixel>}
-    *
+    * 
     * Returns:
-    * {DOMElement} A new DOM Image with this marker's icon set at the
+    * {DOMElement} A new DOM Image with this marker's icon set at the 
     * location passed-in
     */
     draw: function(px) {
         return this.icon.draw(px);
-    },
+    }, 
 
-    /**
+    /** 
     * Method: erase
     * Erases any drawn elements for this marker.
     */
@@ -16830,7 +18025,7 @@
         if (this.icon != null) {
             this.icon.erase();
         }
-    },
+    }, 
 
     /**
     * Method: moveTo
@@ -16842,19 +18037,19 @@
     moveTo: function (px) {
         if ((px != null) && (this.icon != null)) {
             this.icon.moveTo(px);
-        }
+        }           
         this.lonlat = this.map.getLonLatFromLayerPx(px);
     },
 
     /**
      * APIMethod: isDrawn
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the marker is drawn.
      */
     isDrawn: function() {
         var isDrawn = (this.icon && this.icon.isDrawn());
-        return isDrawn;
+        return isDrawn;   
     },
 
     /**
@@ -16864,15 +18059,15 @@
      * {Boolean} Whether or not the marker is currently visible on screen.
      */
     onScreen:function() {
-
+        
         var onScreen = false;
         if (this.map) {
             var screenBounds = this.map.getExtent();
             onScreen = screenBounds.containsLonLat(this.lonlat);
-        }
+        }    
         return onScreen;
     },
-
+    
     /**
      * Method: inflate
      * Englarges the markers icon by the specified ratio.
@@ -16886,14 +18081,14 @@
             var newSize = new OpenLayers.Size(this.icon.size.w * inflate,
                                               this.icon.size.h * inflate);
             this.icon.setSize(newSize);
-        }
+        }        
     },
-
-    /**
+    
+    /** 
      * Method: setOpacity
-     * Change the opacity of the marker by changin the opacity of
+     * Change the opacity of the marker by changin the opacity of 
      *   its icon
-     *
+     * 
      * Parameters:
      * opacity - {float}  Specified as fraction (0.4, etc)
      */
@@ -16904,18 +18099,18 @@
     /**
      * Method: setUrl
      * Change URL of the Icon Image.
-     *
-     * url - {String}
+     * 
+     * url - {String} 
      */
     setUrl: function(url) {
         this.icon.setUrl(url);
-    },
+    },    
 
-    /**
+    /** 
      * Method: display
      * Hide or show the icon
-     *
-     * display - {Boolean}
+     * 
+     * display - {Boolean} 
      */
     display: function(display) {
         this.icon.display(display);
@@ -16928,7 +18123,7 @@
 /**
  * Function: defaultIcon
  * Creates a default <OpenLayers.Icon>.
- *
+ * 
  * Returns:
  * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
  */
@@ -16939,16 +18134,17 @@
                     return new OpenLayers.Pixel(-(size.w/2), -size.h);
                  };
 
-    return new OpenLayers.Icon(url, size, null, calculateOffset);
+    return new OpenLayers.Icon(url, size, null, calculateOffset);        
 };
+    
 
-
 /* ======================================================================
     OpenLayers/Request.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -16962,7 +18158,7 @@
  *     W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
  */
 OpenLayers.Request = {
-
+    
     /**
      * Constant: DEFAULT_CONFIG
      * {Object} Default configuration for all requests.
@@ -16982,17 +18178,17 @@
         failure: null,
         scope: null
     },
-
+    
     /**
      * APIProperty: events
-     * {<OpenLayers.Events>} An events object that handles all
+     * {<OpenLayers.Events>} An events object that handles all 
      *     events on the {<OpenLayers.Request>} object.
      *
      * All event listeners will receive an event object with three properties:
      * request - {<OpenLayers.Request.XMLHttpRequest>} The request object.
      * config - {Object} The config object sent to the specific request method.
      * requestUrl - {String} The request url.
-     *
+     * 
      * Supported event types:
      * complete - Triggered when we have a response from the request, if a
      *     listener returns false, no further response processing will take
@@ -17001,7 +18197,7 @@
      * failure - Triggered when the HTTP response does not have a success code.
      */
     events: new OpenLayers.Events(this, null, ["complete", "success", "failure"]),
-
+    
     /**
      * APIMethod: issue
      * Create a new XMLHttpRequest object, open it, set any headers, bind
@@ -17058,7 +18254,7 @@
      * {XMLHttpRequest} Request object.  To abort the request before a response
      *     is received, call abort() on the request object.
      */
-    issue: function(config) {
+    issue: function(config) {        
         // apply default config - proxy host may have changed
         var defaultConfig = OpenLayers.Util.extend(
             this.DEFAULT_CONFIG,
@@ -17077,7 +18273,11 @@
             }
         }
         if(config.proxy && (url.indexOf("http") == 0)) {
-            url = config.proxy + encodeURIComponent(url);
+            if(typeof config.proxy == "function") {
+                url = config.proxy(url);
+            } else {
+                url = config.proxy + encodeURIComponent(url);
+            }
         }
         request.open(
             config.method, url, config.async, config.user, config.password
@@ -17086,11 +18286,61 @@
             request.setRequestHeader(header, config.headers[header]);
         }
 
+        var events = this.events;
+
+        // we want to execute runCallbacks with "this" as the
+        // execution scope
+        var self = this;
+        
+        request.onreadystatechange = function() {
+            if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
+                var proceed = events.triggerEvent(
+                    "complete",
+                    {request: request, config: config, requestUrl: url}
+                );
+                if(proceed !== false) {
+                    self.runCallbacks(
+                        {request: request, config: config, requestUrl: url}
+                    );
+                }
+            }
+        };
+        
+        // send request (optionally with data) and return
+        // call in a timeout for asynchronous requests so the return is
+        // available before readyState == 4 for cached docs
+        if(config.async === false) {
+            request.send(config.data);
+        } else {
+            window.setTimeout(function(){
+                if (request._aborted !== true) {
+                    request.send(config.data);
+                }
+            }, 0);
+        }
+        return request;
+    },
+    
+    /**
+     * Method: runCallbacks
+     * Calls the complete, success and failure callbacks. Application
+     *    can listen to the "complete" event, have the listener 
+     *    display a confirm window and always return false, and
+     *    execute OpenLayers.Request.runCallbacks if the user
+     *    hits "yes" in the confirm window.
+     *
+     * Parameters:
+     * options - {Object} Hash containing request, config and requestUrl keys
+     */
+    runCallbacks: function(options) {
+        var request = options.request;
+        var config = options.config;
+        
         // bind callbacks to readyState 4 (done)
         var complete = (config.scope) ?
             OpenLayers.Function.bind(config.callback, config.scope) :
             config.callback;
-
+        
         // optional success callback
         var success;
         if(config.success) {
@@ -17107,51 +18357,22 @@
                 config.failure;
         }
 
-        var events = this.events;
+        complete(request);
 
-        request.onreadystatechange = function() {
-            if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
-                var proceed = events.triggerEvent(
-                    "complete",
-                    {request: request, config: config, requestUrl: url}
-                );
-                if(proceed !== false) {
-                    complete(request);
-                    if (!request.status || (request.status >= 200 && request.status < 300)) {
-                        events.triggerEvent(
-                            "success",
-                            {request: request, config: config, requestUrl: url}
-                        );
-                        if(success) {
-                            success(request);
-                        }
-                    }
-                    if(request.status && (request.status < 200 || request.status >= 300)) {
-                        events.triggerEvent(
-                            "failure",
-                            {request: request, config: config, requestUrl: url}
-                        );
-                        if(failure) {
-                            failure(request);
-                        }
-                    }
-                }
+        if (!request.status || (request.status >= 200 && request.status < 300)) {
+            this.events.triggerEvent("success", options);
+            if(success) {
+                success(request);
             }
-        };
-
-        // send request (optionally with data) and return
-        // call in a timeout for asynchronous requests so the return is
-        // available before readyState == 4 for cached docs
-        if(config.async === false) {
-            request.send(config.data);
-        } else {
-            window.setTimeout(function(){
-                request.send(config.data);
-            }, 0);
         }
-        return request;
+        if(request.status && (request.status < 200 || request.status >= 300)) {                    
+            this.events.triggerEvent("failure", options);
+            if(failure) {
+                failure(request);
+            }
+        }
     },
-
+    
     /**
      * APIMethod: GET
      * Send an HTTP GET request.  Additional configuration properties are
@@ -17162,7 +18383,7 @@
      * config - {Object} Object with properties for configuring the request.
      *     See the <issue> method for documentation of allowed properties.
      *     This object is modified and should not be reused.
-     *
+     * 
      * Returns:
      * {XMLHttpRequest} Request object.
      */
@@ -17170,7 +18391,7 @@
         config = OpenLayers.Util.extend(config, {method: "GET"});
         return OpenLayers.Request.issue(config);
     },
-
+    
     /**
      * APIMethod: POST
      * Send a POST request.  Additional configuration properties are
@@ -17182,7 +18403,7 @@
      *     See the <issue> method for documentation of allowed properties.  The
      *     default "Content-Type" header will be set to "application-xml" if
      *     none is provided.  This object is modified and should not be reused.
-     *
+     * 
      * Returns:
      * {XMLHttpRequest} Request object.
      */
@@ -17195,7 +18416,7 @@
         }
         return OpenLayers.Request.issue(config);
     },
-
+    
     /**
      * APIMethod: PUT
      * Send an HTTP PUT request.  Additional configuration properties are
@@ -17207,7 +18428,7 @@
      *     See the <issue> method for documentation of allowed properties.  The
      *     default "Content-Type" header will be set to "application-xml" if
      *     none is provided.  This object is modified and should not be reused.
-     *
+     * 
      * Returns:
      * {XMLHttpRequest} Request object.
      */
@@ -17220,7 +18441,7 @@
         }
         return OpenLayers.Request.issue(config);
     },
-
+    
     /**
      * APIMethod: DELETE
      * Send an HTTP DELETE request.  Additional configuration properties are
@@ -17231,7 +18452,7 @@
      * config - {Object} Object with properties for configuring the request.
      *     See the <issue> method for documentation of allowed properties.
      *     This object is modified and should not be reused.
-     *
+     * 
      * Returns:
      * {XMLHttpRequest} Request object.
      */
@@ -17239,7 +18460,7 @@
         config = OpenLayers.Util.extend(config, {method: "DELETE"});
         return OpenLayers.Request.issue(config);
     },
-
+  
     /**
      * APIMethod: HEAD
      * Send an HTTP HEAD request.  Additional configuration properties are
@@ -17250,7 +18471,7 @@
      * config - {Object} Object with properties for configuring the request.
      *     See the <issue> method for documentation of allowed properties.
      *     This object is modified and should not be reused.
-     *
+     * 
      * Returns:
      * {XMLHttpRequest} Request object.
      */
@@ -17258,7 +18479,7 @@
         config = OpenLayers.Util.extend(config, {method: "HEAD"});
         return OpenLayers.Request.issue(config);
     },
-
+    
     /**
      * APIMethod: OPTIONS
      * Send an HTTP OPTIONS request.  Additional configuration properties are
@@ -17269,7 +18490,7 @@
      * config - {Object} Object with properties for configuring the request.
      *     See the <issue> method for documentation of allowed properties.
      *     This object is modified and should not be reused.
-     *
+     * 
      * Returns:
      * {XMLHttpRequest} Request object.
      */
@@ -17283,8 +18504,9 @@
     OpenLayers/Tile/Image.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -17303,14 +18525,14 @@
  */
 OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
 
-    /**
+    /** 
      * Property: url
      * {String} The URL of the image being requested. No default. Filled in by
-     * layer.getURL() function.
+     * layer.getURL() function. 
      */
     url: null,
-
-    /**
+    
+    /** 
      * Property: imgDiv
      * {DOMElement} The div element which wraps the image.
      */
@@ -17319,22 +18541,22 @@
     /**
      * Property: frame
      * {DOMElement} The image element is appended to the frame.  Any gutter on
-     * the image will be hidden behind the frame.
-     */
-    frame: null,
-
+     * the image will be hidden behind the frame. 
+     */ 
+    frame: null, 
+    
     /**
      * Property: layerAlphaHack
      * {Boolean} True if the png alpha hack needs to be applied on the layer's div.
      */
     layerAlphaHack: null,
-
+    
     /**
      * Property: isBackBuffer
      * {Boolean} Is this tile a back buffer tile?
      */
     isBackBuffer: false,
-
+    
     /**
      * Property: lastRatio
      * {Float} Used in transition code only.  This is the previous ratio
@@ -17353,7 +18575,7 @@
      *     tiles that have been loaded can be used.
      */
     isFirstDraw: true,
-
+        
     /**
      * Property: backBufferTile
      * {<OpenLayers.Tile>} A clone of the tile used to create transition
@@ -17361,33 +18583,33 @@
      */
     backBufferTile: null,
 
-    /** TBD 3.0 - reorder the parameters to the init function to remove
-     *             URL. the getUrl() function on the layer gets called on
+    /** TBD 3.0 - reorder the parameters to the init function to remove 
+     *             URL. the getUrl() function on the layer gets called on 
      *             each draw(), so no need to specify it here.
-     *
+     * 
      * Constructor: OpenLayers.Tile.Image
      * Constructor for a new <OpenLayers.Tile.Image> instance.
-     *
+     * 
      * Parameters:
      * layer - {<OpenLayers.Layer>} layer that the tile will go in.
      * position - {<OpenLayers.Pixel>}
      * bounds - {<OpenLayers.Bounds>}
      * url - {<String>} Deprecated. Remove me in 3.0.
      * size - {<OpenLayers.Size>}
-     */
+     */   
     initialize: function(layer, position, bounds, url, size) {
         OpenLayers.Tile.prototype.initialize.apply(this, arguments);
 
         this.url = url; //deprecated remove me
+        
+        this.frame = document.createElement('div'); 
+        this.frame.style.overflow = 'hidden'; 
+        this.frame.style.position = 'absolute'; 
 
-        this.frame = document.createElement('div');
-        this.frame.style.overflow = 'hidden';
-        this.frame.style.position = 'absolute';
-
         this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();
     },
 
-    /**
+    /** 
      * APIMethod: destroy
      * nullify references to prevent circular references and memory leaks
      */
@@ -17395,13 +18617,13 @@
         if (this.imgDiv != null)  {
             if (this.layerAlphaHack) {
                 // unregister the "load" handler
-                OpenLayers.Event.stopObservingElement(this.imgDiv.childNodes[0].id);
+                OpenLayers.Event.stopObservingElement(this.imgDiv.childNodes[0]);                
             }
 
             // unregister the "load" and "error" handlers. Only the "error" handler if
             // this.layerAlphaHack is true.
-            OpenLayers.Event.stopObservingElement(this.imgDiv.id);
-
+            OpenLayers.Event.stopObservingElement(this.imgDiv);
+            
             if (this.imgDiv.parentNode == this.frame) {
                 this.frame.removeChild(this.imgDiv);
                 this.imgDiv.map = null;
@@ -17411,19 +18633,19 @@
             this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
         }
         this.imgDiv = null;
-        if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) {
-            this.layer.div.removeChild(this.frame);
+        if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) { 
+            this.layer.div.removeChild(this.frame); 
         }
-        this.frame = null;
-
+        this.frame = null; 
+        
         /* clean up the backBufferTile if it exists */
         if (this.backBufferTile) {
             this.backBufferTile.destroy();
             this.backBufferTile = null;
         }
-
+        
         this.layer.events.unregister("loadend", this, this.resetBackBuffer);
-
+        
         OpenLayers.Tile.prototype.destroy.apply(this, arguments);
     },
 
@@ -17438,27 +18660,27 @@
      */
     clone: function (obj) {
         if (obj == null) {
-            obj = new OpenLayers.Tile.Image(this.layer,
-                                            this.position,
-                                            this.bounds,
-                                            this.url,
-                                            this.size);
-        }
-
+            obj = new OpenLayers.Tile.Image(this.layer, 
+                                            this.position, 
+                                            this.bounds, 
+                                            this.url, 
+                                            this.size);        
+        } 
+        
         //pick up properties from superclass
         obj = OpenLayers.Tile.prototype.clone.apply(this, [obj]);
-
+        
         //dont want to directly copy the image div
         obj.imgDiv = null;
-
-
+            
+        
         return obj;
     },
-
+    
     /**
      * Method: draw
      * Check that a tile should be drawn, and draw it.
-     *
+     * 
      * Returns:
      * {Boolean} Always returns true.
      */
@@ -17467,8 +18689,9 @@
             this.bounds = this.getBoundsFromBaseLayer(this.position);
         }
         var drawTile = OpenLayers.Tile.prototype.draw.apply(this, arguments);
-
-        if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, this.layer.transitionEffect) != -1) {
+        
+        if ((OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, this.layer.transitionEffect) != -1) || 
+            this.layer.singleTile) {
             if (drawTile) {
                 //we use a clone of this tile to create a double buffer for visual
                 //continuity.  The backBufferTile is used to create transition
@@ -17481,10 +18704,10 @@
                     // the backBufferTile behind the main tile so the tiles can
                     // load over top and display as soon as they are loaded.
                     this.backBufferTile.isBackBuffer = true;
-
+                    
                     // potentially end any transition effects when the tile loads
                     this.events.register('loadend', this, this.resetBackBuffer);
-
+                    
                     // clear transition back buffer tile only after all tiles in
                     // this layer have loaded to avoid visual glitches
                     this.layer.events.register("loadend", this, this.resetBackBuffer);
@@ -17502,45 +18725,45 @@
             if (drawTile && this.isFirstDraw) {
                 this.events.register('loadend', this, this.showTile);
                 this.isFirstDraw = false;
-            }
-        }
-
+            }   
+        }    
+        
         if (!drawTile) {
             return false;
         }
-
+        
         if (this.isLoading) {
             //if we're already loading, send 'reload' instead of 'loadstart'.
-            this.events.triggerEvent("reload");
+            this.events.triggerEvent("reload"); 
         } else {
             this.isLoading = true;
             this.events.triggerEvent("loadstart");
         }
-
+        
         return this.renderTile();
     },
-
-    /**
+    
+    /** 
      * Method: resetBackBuffer
      * Triggered by two different events, layer loadend, and tile loadend.
-     *     In any of these cases, we check to see if we can hide the
-     *     backBufferTile yet and update its parameters to match the
+     *     In any of these cases, we check to see if we can hide the 
+     *     backBufferTile yet and update its parameters to match the 
      *     foreground tile.
      *
      * Basic logic:
      *  - If the backBufferTile hasn't been drawn yet, reset it
      *  - If layer is still loading, show foreground tile but don't hide
      *    the backBufferTile yet
-     *  - If layer is done loading, reset backBuffer tile and show
+     *  - If layer is done loading, reset backBuffer tile and show 
      *    foreground tile
      */
     resetBackBuffer: function() {
         this.showTile();
-        if (this.backBufferTile &&
+        if (this.backBufferTile && 
             (this.isFirstDraw || !this.layer.numLoadingTiles)) {
             this.isFirstDraw = false;
             // check to see if the backBufferTile is within the max extents
-            // before rendering it
+            // before rendering it 
             var maxExtent = this.layer.maxExtent;
             var withinMaxExtent = (maxExtent &&
                                    this.bounds.intersectsBounds(maxExtent, false));
@@ -17548,7 +18771,7 @@
                 this.backBufferTile.position = this.position;
                 this.backBufferTile.bounds = this.bounds;
                 this.backBufferTile.size = this.size;
-                this.backBufferTile.imageSize = this.layer.imageSize || this.size;
+                this.backBufferTile.imageSize = this.layer.getImageSize(this.bounds) || this.size;
                 this.backBufferTile.imageOffset = this.layer.imageOffset;
                 this.backBufferTile.resolution = this.layer.getResolution();
                 this.backBufferTile.renderTile();
@@ -17557,7 +18780,7 @@
             this.backBufferTile.hide();
         }
     },
-
+    
     /**
      * Method: renderTile
      * Internal function to actually initialize the image tile,
@@ -17569,7 +18792,7 @@
         }
 
         this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
-
+        
         if (this.layer.async) {
             // Asyncronous image requests call the asynchronous getURL method
             // on the layer to fetch an image that covers 'this.bounds', in the scope of
@@ -17579,16 +18802,16 @@
         } else {
             // syncronous image requests get the url and position the frame immediately,
             // and don't wait for an image request to come back.
-
+          
             // needed for changing to a different server for onload error
             if (this.layer.url instanceof Array) {
                 this.imgDiv.urls = this.layer.url.slice();
             }
-
+          
             this.url = this.layer.getURL(this.bounds);
-
+          
             // position the frame immediately
-            this.positionImage();
+            this.positionImage(); 
         }
         return true;
     },
@@ -17602,14 +18825,14 @@
      positionImage: function() {
         // if the this layer doesn't exist at the point the image is
         // returned, do not attempt to use it for size computation
-        if ( this.layer == null )
+        if (this.layer === null) {
             return;
+        }
+        // position the frame 
+        OpenLayers.Util.modifyDOMElement(this.frame, 
+                                          null, this.position, this.size);   
 
-        // position the frame
-        OpenLayers.Util.modifyDOMElement(this.frame,
-                                          null, this.position, this.size);
-
-        var imageSize = this.layer.getImageSize();
+        var imageSize = this.layer.getImageSize(this.bounds); 
         if (this.layerAlphaHack) {
             OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
                     null, null, imageSize, this.url);
@@ -17620,17 +18843,17 @@
         }
     },
 
-    /**
+    /** 
      * Method: clear
-     *  Clear the tile of any bounds/position-related data so that it can
+     *  Clear the tile of any bounds/position-related data so that it can 
      *   be reused in a new location.
      */
     clear: function() {
         if(this.imgDiv) {
             this.hide();
-            if (OpenLayers.Tile.Image.useBlankTile) {
+            if (OpenLayers.Tile.Image.useBlankTile) { 
                 this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
-            }
+            }    
         }
     },
 
@@ -17639,10 +18862,10 @@
      * Creates the imgDiv property on the tile.
      */
     initImgDiv: function() {
-
-        var offset = this.layer.imageOffset;
-        var size = this.layer.getImageSize();
-
+        
+        var offset = this.layer.imageOffset; 
+        var size = this.layer.getImageSize(this.bounds); 
+     
         if (this.layerAlphaHack) {
             this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
                                                            offset,
@@ -17663,7 +18886,7 @@
                                                       null,
                                                       true);
         }
-
+        
         this.imgDiv.className = 'olTileImage';
 
         /* checkImgURL used to be used to called as a work around, but it
@@ -17675,43 +18898,43 @@
             OpenLayers.Function.bind(this.checkImgURL, this) );
         */
         this.frame.style.zIndex = this.isBackBuffer ? 0 : 1;
-        this.frame.appendChild(this.imgDiv);
-        this.layer.div.appendChild(this.frame);
+        this.frame.appendChild(this.imgDiv); 
+        this.layer.div.appendChild(this.frame); 
 
         if(this.layer.opacity != null) {
-
+            
             OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,
-                                             null, null, null,
+                                             null, null, null, 
                                              this.layer.opacity);
         }
 
         // we need this reference to check back the viewRequestID
         this.imgDiv.map = this.layer.map;
 
-        //bind a listener to the onload of the image div so that we
+        //bind a listener to the onload of the image div so that we 
         // can register when a tile has finished loading.
         var onload = function() {
-
-            //normally isLoading should always be true here but there are some
+            
+            //normally isLoading should always be true here but there are some 
             // right funky conditions where loading and then reloading a tile
-            // with the same url *really*fast*. this check prevents sending
+            // with the same url *really*fast*. this check prevents sending 
             // a 'loadend' if the msg has already been sent
             //
-            if (this.isLoading) {
-                this.isLoading = false;
-                this.events.triggerEvent("loadend");
+            if (this.isLoading) { 
+                this.isLoading = false; 
+                this.events.triggerEvent("loadend"); 
             }
         };
+        
+        if (this.layerAlphaHack) { 
+            OpenLayers.Event.observe(this.imgDiv.childNodes[0], 'load', 
+                                     OpenLayers.Function.bind(onload, this));    
+        } else { 
+            OpenLayers.Event.observe(this.imgDiv, 'load', 
+                                 OpenLayers.Function.bind(onload, this)); 
+        } 
+        
 
-        if (this.layerAlphaHack) {
-            OpenLayers.Event.observe(this.imgDiv.childNodes[0], 'load',
-                                     OpenLayers.Function.bind(onload, this));
-        } else {
-            OpenLayers.Event.observe(this.imgDiv, 'load',
-                                 OpenLayers.Function.bind(onload, this));
-        }
-
-
         // Bind a listener to the onerror of the image div so that we
         // can registere when a tile has finished loading with errors.
         var onerror = function() {
@@ -17737,18 +18960,18 @@
      * the imgDiv display to 'none', as either (a) it will be reset to visible
      * when the new URL loads in the image, or (b) we don't want to display
      * this tile after all because its new bounds are outside our maxExtent.
-     *
+     * 
      * This function should no longer  be neccesary with the improvements to
      * Grid.js in OpenLayers 2.3. The lack of a good isEquivilantURL function
-     * caused problems in 2.2, but it's possible that with the improved
+     * caused problems in 2.2, but it's possible that with the improved 
      * isEquivilant URL function, this might be neccesary at some point.
-     *
-     * See discussion in the thread at
+     * 
+     * See discussion in the thread at 
      * http://openlayers.org/pipermail/dev/2007-January/000205.html
      */
     checkImgURL: function () {
         // Sometimes our image will load after it has already been removed
-        // from the map, in which case this check is not needed.
+        // from the map, in which case this check is not needed.  
         if (this.layer) {
             var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src;
             if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
@@ -17756,7 +18979,7 @@
             }
         }
     },
-
+    
     /**
      * Method: startTransition
      * This method is invoked on tiles that are backBuffers for tiles in the
@@ -17778,15 +19001,15 @@
         if (this.backBufferTile.resolution) {
             ratio = this.backBufferTile.resolution / this.layer.getResolution();
         }
-
+        
         // if the ratio is not the same as it was last time (i.e. we are
         // zooming), then we need to adjust the backBuffer tile
         if (ratio != this.lastRatio) {
             if (this.layer.transitionEffect == 'resize') {
-                // In this case, we can just immediately resize the
+                // In this case, we can just immediately resize the 
                 // backBufferTile.
                 var upperLeft = new OpenLayers.LonLat(
-                    this.backBufferTile.bounds.left,
+                    this.backBufferTile.bounds.left, 
                     this.backBufferTile.bounds.top
                 );
                 var size = new OpenLayers.Size(
@@ -17795,10 +19018,10 @@
                 );
 
                 var px = this.layer.map.getLayerPxFromLonLat(upperLeft);
-                OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame,
+                OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame, 
                                                  null, px, size);
                 var imageSize = this.backBufferTile.imageSize;
-                imageSize = new OpenLayers.Size(imageSize.w * ratio,
+                imageSize = new OpenLayers.Size(imageSize.w * ratio, 
                                                 imageSize.h * ratio);
                 var imageOffset = this.backBufferTile.imageOffset;
                 if(imageOffset) {
@@ -17827,8 +19050,8 @@
         this.lastRatio = ratio;
 
     },
-
-    /**
+    
+    /** 
      * Method: show
      * Show the tile by showing its frame.
      */
@@ -17836,38 +19059,39 @@
         this.frame.style.display = '';
         // Force a reflow on gecko based browsers to actually show the element
         // before continuing execution.
-        if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,
+        if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, 
                 this.layer.transitionEffect) != -1) {
-            if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) {
-                this.frame.scrollLeft = this.frame.scrollLeft;
-            }
+            if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) { 
+                this.frame.scrollLeft = this.frame.scrollLeft; 
+            } 
         }
     },
-
-    /**
+    
+    /** 
      * Method: hide
      * Hide the tile by hiding its frame.
      */
     hide: function() {
         this.frame.style.display = 'none';
     },
-
+    
     CLASS_NAME: "OpenLayers.Tile.Image"
   }
 );
 
-OpenLayers.Tile.Image.useBlankTile = (
-    OpenLayers.Util.getBrowserName() == "safari" ||
-    OpenLayers.Util.getBrowserName() == "opera");
+OpenLayers.Tile.Image.useBlankTile = ( 
+    OpenLayers.Util.getBrowserName() == "safari" || 
+    OpenLayers.Util.getBrowserName() == "opera"); 
 /* ======================================================================
     OpenLayers/Control/OverviewMap.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
-/**
+/** 
  * @requires OpenLayers/Control.js
  * @requires OpenLayers/BaseTypes.js
  * @requires OpenLayers/Events.js
@@ -17875,8 +19099,8 @@
 
 /**
  * Class: OpenLayers.Control.OverviewMap
- * The OverMap control creates a small overview map, useful to display the
- * extent of a zoomed map and your main map and provide additional
+ * The OverMap control creates a small overview map, useful to display the 
+ * extent of a zoomed map and your main map and provide additional 
  * navigation options to the User.  By default the overview map is drawn in
  * the lower right corner of the main map. Create a new overview map with the
  * <OpenLayers.Control.OverviewMap> constructor.
@@ -17891,7 +19115,7 @@
      * {DOMElement} The DOM element that contains the overview map
      */
     element: null,
-
+    
     /**
      * APIProperty: ovmap
      * {<OpenLayers.Map>} A reference to the overview map itself.
@@ -17913,7 +19137,7 @@
      * If none are sent at construction, the base layer for the main map is used.
      */
     layers: null,
-
+    
     /**
      * APIProperty: minRectSize
      * {Integer} The minimum width or height (in pixels) of the extent
@@ -17922,7 +19146,7 @@
      *     <minRectDisplayClass> property.  Default is 15 pixels.
      */
     minRectSize: 15,
-
+    
     /**
      * APIProperty: minRectDisplayClass
      * {String} Replacement style class name for the extent rectangle when
@@ -17955,7 +19179,7 @@
      *     resolution at which to zoom farther in on the overview map.
      */
     maxRatio: 32,
-
+    
     /**
      * APIProperty: mapOptions
      * {Object} An object containing any non-default properties to be sent to
@@ -17972,7 +19196,7 @@
      *     to the center.
      */
     autoPan: false,
-
+    
     /**
      * Property: handlers
      * {Object}
@@ -17986,6 +19210,12 @@
     resolutionFactor: 1,
 
     /**
+     * APIProperty: maximized
+     * {Boolean} Start as maximized (visible). Defaults to false.
+     */
+    maximized: false,
+
+    /**
      * Constructor: OpenLayers.Control.OverviewMap
      * Create a new overview map
      *
@@ -17999,7 +19229,7 @@
         this.handlers = {};
         OpenLayers.Control.prototype.initialize.apply(this, [options]);
     },
-
+    
     /**
      * APIMethod: destroy
      * Deconstruct the control
@@ -18008,16 +19238,26 @@
         if (!this.mapDiv) { // we've already been destroyed
             return;
         }
-        this.handlers.click.destroy();
+        if (this.handlers.click) {
+            this.handlers.click.destroy();
+        }
+        if (this.handlers.drag) {
+            this.handlers.drag.destroy();
+        }
 
         this.mapDiv.removeChild(this.extentRectangle);
         this.extentRectangle = null;
-        this.rectEvents.destroy();
-        this.rectEvents = null;
 
-        this.ovmap.destroy();
-        this.ovmap = null;
+        if (this.rectEvents) {
+            this.rectEvents.destroy();
+            this.rectEvents = null;
+        }
 
+        if (this.ovmap) {
+            this.ovmap.destroy();
+            this.ovmap = null;
+        }
+        
         this.element.removeChild(this.mapDiv);
         this.mapDiv = null;
 
@@ -18029,7 +19269,7 @@
             this.div.removeChild(this.maximizeDiv);
             this.maximizeDiv = null;
         }
-
+        
         if (this.minimizeDiv) {
             OpenLayers.Event.stopObservingElement(this.minimizeDiv);
             this.div.removeChild(this.minimizeDiv);
@@ -18042,13 +19282,13 @@
             scope: this
         });
 
-        OpenLayers.Control.prototype.destroy.apply(this, arguments);
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);    
     },
 
     /**
      * Method: draw
      * Render the control in the browser.
-     */
+     */    
     draw: function() {
         OpenLayers.Control.prototype.draw.apply(this, arguments);
         if(!(this.layers.length > 0)) {
@@ -18072,14 +19312,14 @@
         this.mapDiv.style.position = 'relative';
         this.mapDiv.style.overflow = 'hidden';
         this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
-
+        
         this.extentRectangle = document.createElement('div');
         this.extentRectangle.style.position = 'absolute';
         this.extentRectangle.style.zIndex = 1000;  //HACK
         this.extentRectangle.className = this.displayClass+'ExtentRectangle';
         this.mapDiv.appendChild(this.extentRectangle);
 
-        this.element.appendChild(this.mapDiv);
+        this.element.appendChild(this.mapDiv);  
 
         this.div.appendChild(this.element);
 
@@ -18091,48 +19331,48 @@
             // maximize button div
             var img = imgLocation + 'layer-switcher-maximize.png';
             this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
-                                        this.displayClass + 'MaximizeButton',
-                                        null,
-                                        new OpenLayers.Size(18,18),
-                                        img,
+                                        this.displayClass + 'MaximizeButton', 
+                                        null, 
+                                        new OpenLayers.Size(18,18), 
+                                        img, 
                                         'absolute');
             this.maximizeDiv.style.display = 'none';
             this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
-            OpenLayers.Event.observe(this.maximizeDiv, 'click',
+            OpenLayers.Event.observe(this.maximizeDiv, 'click', 
                 OpenLayers.Function.bindAsEventListener(this.maximizeControl,
                                                         this)
             );
             this.div.appendChild(this.maximizeDiv);
-
+    
             // minimize button div
             var img = imgLocation + 'layer-switcher-minimize.png';
             this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
-                                        'OpenLayers_Control_minimizeDiv',
-                                        null,
-                                        new OpenLayers.Size(18,18),
-                                        img,
+                                        'OpenLayers_Control_minimizeDiv', 
+                                        null, 
+                                        new OpenLayers.Size(18,18), 
+                                        img, 
                                         'absolute');
             this.minimizeDiv.style.display = 'none';
             this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
-            OpenLayers.Event.observe(this.minimizeDiv, 'click',
+            OpenLayers.Event.observe(this.minimizeDiv, 'click', 
                 OpenLayers.Function.bindAsEventListener(this.minimizeControl,
                                                         this)
             );
             this.div.appendChild(this.minimizeDiv);
-
+            
             var eventsToStop = ['dblclick','mousedown'];
-
+            
             for (var i=0, len=eventsToStop.length; i<len; i++) {
 
-                OpenLayers.Event.observe(this.maximizeDiv,
-                                         eventsToStop[i],
+                OpenLayers.Event.observe(this.maximizeDiv, 
+                                         eventsToStop[i], 
                                          OpenLayers.Event.stop);
 
                 OpenLayers.Event.observe(this.minimizeDiv,
-                                         eventsToStop[i],
+                                         eventsToStop[i], 
                                          OpenLayers.Event.stop);
             }
-
+            
             this.minimizeControl();
         } else {
             // show the overview map
@@ -18141,12 +19381,15 @@
         if(this.map.getExtent()) {
             this.update();
         }
-
+        
         this.map.events.register('moveend', this, this.update);
-
+        
+        if (this.maximized) {
+            this.maximizeControl();
+        }
         return this.div;
     },
-
+    
     /**
      * Method: baseLayerDraw
      * Draw the base layer - called if unable to complete in the initial draw
@@ -18184,7 +19427,7 @@
                                                        newTop));
         }
     },
-
+    
     /**
      * Method: mapDivClick
      * Handle browser events
@@ -18222,15 +19465,15 @@
         this.element.style.display = '';
         this.showToggle(false);
         if (e != null) {
-            OpenLayers.Event.stop(e);
+            OpenLayers.Event.stop(e);                                            
         }
     },
 
     /**
      * Method: minimizeControl
-     * Hide all the contents of the control, shrink the size,
+     * Hide all the contents of the control, shrink the size, 
      * add the maximize icon
-     *
+     * 
      * Parameters:
      * e - {<OpenLayers.Event>}
      */
@@ -18238,7 +19481,7 @@
         this.element.style.display = 'none';
         this.showToggle(true);
         if (e != null) {
-            OpenLayers.Event.stop(e);
+            OpenLayers.Event.stop(e);                                            
         }
     },
 
@@ -18247,7 +19490,7 @@
      * Hide/Show the toggle depending on whether the control is minimized
      *
      * Parameters:
-     * minimize - {Boolean}
+     * minimize - {Boolean} 
      */
     showToggle: function(minimize) {
         this.maximizeDiv.style.display = minimize ? '' : 'none';
@@ -18262,15 +19505,15 @@
         if(this.ovmap == null) {
             this.createMap();
         }
-
+        
         if(this.autoPan || !this.isSuitableOverview()) {
             this.updateOverview();
         }
-
+        
         // update extent rectangle
         this.updateRectToMap();
     },
-
+    
     /**
      * Method: isSuitableOverview
      * Determines if the overview map is suitable given the extent and
@@ -18283,7 +19526,7 @@
                                 Math.max(mapExtent.left, maxExtent.left),
                                 Math.max(mapExtent.bottom, maxExtent.bottom),
                                 Math.min(mapExtent.right, maxExtent.right),
-                                Math.min(mapExtent.top, maxExtent.top));
+                                Math.min(mapExtent.top, maxExtent.top));        
 
         if (this.ovmap.getProjection() != this.map.getProjection()) {
             testExtent = testExtent.transform(
@@ -18296,7 +19539,7 @@
                 (resRatio <= this.maxRatio) &&
                 (this.ovmap.getExtent().containsBounds(testExtent)));
     },
-
+    
     /**
      * Method updateOverview
      * Called by <update> if <isSuitableOverview> returns true
@@ -18307,7 +19550,7 @@
         var resRatio = targetRes / mapRes;
         if(resRatio > this.maxRatio) {
             // zoom in overview map
-            targetRes = this.minRatio * mapRes;
+            targetRes = this.minRatio * mapRes;            
         } else if(resRatio <= this.minRatio) {
             // zoom out overview map
             targetRes = this.maxRatio * mapRes;
@@ -18324,7 +19567,7 @@
             targetRes * this.resolutionFactor));
         this.updateRectToMap();
     },
-
+    
     /**
      * Method: createMap
      * Construct the map that this control contains
@@ -18332,14 +19575,14 @@
     createMap: function() {
         // create the overview map
         var options = OpenLayers.Util.extend(
-                        {controls: [], maxResolution: 'auto',
+                        {controls: [], maxResolution: 'auto', 
                          fallThrough: false}, this.mapOptions);
         this.ovmap = new OpenLayers.Map(this.mapDiv, options);
-
+        
         // prevent ovmap from being destroyed when the page unloads, because
         // the OverviewMap control has to do this (and does it).
         OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy);
-
+        
         this.ovmap.addLayers(this.layers);
         this.ovmap.zoomToMaxExtent();
         // check extent rectangle border width
@@ -18369,7 +19612,7 @@
             }
         );
         this.handlers.click.activate();
-
+        
         this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
                                                 null, true);
         this.rectEvents.register("mouseover", this, function(e) {
@@ -18393,7 +19636,7 @@
                 OpenLayers.INCHES_PER_UNIT[targetUnits] : 1;
         }
     },
-
+        
     /**
      * Method: updateRectToMap
      * Updates the extent rectangle position and size to match the map extent
@@ -18403,7 +19646,7 @@
         var bounds;
         if (this.ovmap.getProjection() != this.map.getProjection()) {
             bounds = this.map.getExtent().transform(
-                this.map.getProjectionObject(),
+                this.map.getProjectionObject(), 
                 this.ovmap.getProjectionObject() );
         } else {
             bounds = this.map.getExtent();
@@ -18413,7 +19656,7 @@
             this.setRectPxBounds(pxBounds);
         }
     },
-
+    
     /**
      * Method: updateMapToRect
      * Updates the map extent to match the extent rectangle position and size
@@ -18530,12 +19773,12 @@
         var size = this.ovmap.size;
         var res  = this.ovmap.getResolution();
         var center = this.ovmap.getExtent().getCenterLonLat();
-
+    
         var delta_x = overviewMapPx.x - (size.w / 2);
         var delta_y = overviewMapPx.y - (size.h / 2);
-
+        
         return new OpenLayers.LonLat(center.lon + delta_x * res ,
-                                     center.lat - delta_y * res);
+                                     center.lat - delta_y * res); 
     },
 
     /**
@@ -18546,7 +19789,7 @@
      * lonlat - {<OpenLayers.LonLat>}
      *
      * Returns:
-     * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat,
+     * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat, 
      * translated into overview map pixels
      */
     getOverviewPxFromLonLat: function(lonlat) {
@@ -18557,7 +19800,7 @@
             px = new OpenLayers.Pixel(
                         Math.round(1/res * (lonlat.lon - extent.left)),
                         Math.round(1/res * (extent.top - lonlat.lat)));
-        }
+        } 
         return px;
     },
 
@@ -18567,8 +19810,9 @@
     OpenLayers/Feature.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -18585,33 +19829,33 @@
  */
 OpenLayers.Feature = OpenLayers.Class({
 
-    /**
-     * Property: layer
-     * {<OpenLayers.Layer>}
+    /** 
+     * Property: layer 
+     * {<OpenLayers.Layer>} 
      */
     layer: null,
 
-    /**
-     * Property: id
-     * {String}
+    /** 
+     * Property: id 
+     * {String} 
      */
     id: null,
-
-    /**
-     * Property: lonlat
-     * {<OpenLayers.LonLat>}
+    
+    /** 
+     * Property: lonlat 
+     * {<OpenLayers.LonLat>} 
      */
     lonlat: null,
 
-    /**
-     * Property: data
-     * {Object}
+    /** 
+     * Property: data 
+     * {Object} 
      */
     data: null,
 
-    /**
-     * Property: marker
-     * {<OpenLayers.Marker>}
+    /** 
+     * Property: marker 
+     * {<OpenLayers.Marker>} 
      */
     marker: null,
 
@@ -18622,21 +19866,21 @@
      */
     popupClass: OpenLayers.Popup.AnchoredBubble,
 
-    /**
-     * Property: popup
-     * {<OpenLayers.Popup>}
+    /** 
+     * Property: popup 
+     * {<OpenLayers.Popup>} 
      */
     popup: null,
 
-    /**
+    /** 
      * Constructor: OpenLayers.Feature
      * Constructor for features.
      *
      * Parameters:
-     * layer - {<OpenLayers.Layer>}
-     * lonlat - {<OpenLayers.LonLat>}
-     * data - {Object}
-     *
+     * layer - {<OpenLayers.Layer>} 
+     * lonlat - {<OpenLayers.LonLat>} 
+     * data - {Object} 
+     * 
      * Returns:
      * {<OpenLayers.Feature>}
      */
@@ -18644,10 +19888,10 @@
         this.layer = layer;
         this.lonlat = lonlat;
         this.data = (data != null) ? data : {};
-        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); 
     },
 
-    /**
+    /** 
      * Method: destroy
      * nullify references to prevent circular references and memory leaks
      */
@@ -18659,6 +19903,10 @@
                 this.layer.map.removePopup(this.popup);
             }
         }
+        // remove the marker from the layer
+        if (this.layer != null && this.marker != null) {
+            this.layer.removeMarker(this.marker);
+        }
 
         this.layer = null;
         this.id = null;
@@ -18673,36 +19921,36 @@
             this.popup = null;
         }
     },
-
+    
     /**
      * Method: onScreen
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the feature is currently visible on screen
      *           (based on its 'lonlat' property)
      */
     onScreen:function() {
-
+        
         var onScreen = false;
         if ((this.layer != null) && (this.layer.map != null)) {
             var screenBounds = this.layer.map.getExtent();
             onScreen = screenBounds.containsLonLat(this.lonlat);
-        }
+        }    
         return onScreen;
     },
+    
 
-
     /**
      * Method: createMarker
      * Based on the data associated with the Feature, create and return a marker object.
      *
-     * Returns:
+     * Returns: 
      * {<OpenLayers.Marker>} A Marker Object created from the 'lonlat' and 'icon' properties
      *          set in this.data. If no 'lonlat' is set, returns null. If no
      *          'icon' is set, OpenLayers.Marker() will load the default image.
-     *
+     *          
      *          Note - this.marker is set to return value
-     *
+     * 
      */
     createMarker: function() {
 
@@ -18719,64 +19967,64 @@
      *   to also specify an alternative function for destroying it
      */
     destroyMarker: function() {
-        this.marker.destroy();
+        this.marker.destroy();  
     },
 
     /**
      * Method: createPopup
      * Creates a popup object created from the 'lonlat', 'popupSize',
      *     and 'popupContentHTML' properties set in this.data. It uses
-     *     this.marker.icon as default anchor.
-     *
-     *  If no 'lonlat' is set, returns null.
+     *     this.marker.icon as default anchor. 
+     *  
+     *  If no 'lonlat' is set, returns null. 
      *  If no this.marker has been created, no anchor is sent.
      *
      *  Note - the returned popup object is 'owned' by the feature, so you
      *      cannot use the popup's destroy method to discard the popup.
      *      Instead, you must use the feature's destroyPopup
-     *
+     * 
      *  Note - this.popup is set to return value
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * closeBox - {Boolean} create popup with closebox or not
-     *
+     * 
      * Returns:
      * {<OpenLayers.Popup>} Returns the created popup, which is also set
      *     as 'popup' property of this feature. Will be of whatever type
      *     specified by this feature's 'popupClass' property, but must be
      *     of type <OpenLayers.Popup>.
-     *
+     * 
      */
     createPopup: function(closeBox) {
 
         if (this.lonlat != null) {
-
+            
             var id = this.id + "_popup";
             var anchor = (this.marker) ? this.marker.icon : null;
 
             if (!this.popup) {
-                this.popup = new this.popupClass(id,
+                this.popup = new this.popupClass(id, 
                                                  this.lonlat,
                                                  this.data.popupSize,
                                                  this.data.popupContentHTML,
-                                                 anchor,
-                                                 closeBox);
-            }
+                                                 anchor, 
+                                                 closeBox); 
+            }    
             if (this.data.overflow != null) {
                 this.popup.contentDiv.style.overflow = this.data.overflow;
-            }
-
+            }    
+            
             this.popup.feature = this;
-        }
+        }        
         return this.popup;
     },
 
-
+    
     /**
      * Method: destroyPopup
      * Destroys the popup created via createPopup.
      *
-     * As with the marker, if user overrides the createPopup() function, s/he
+     * As with the marker, if user overrides the createPopup() function, s/he 
      *   should also be able to override the destruction
      */
     destroyPopup: function() {
@@ -18784,7 +20032,7 @@
             this.popup.feature = null;
             this.popup.destroy();
             this.popup = null;
-        }
+        }    
     },
 
     CLASS_NAME: "OpenLayers.Feature"
@@ -18793,9 +20041,10 @@
     OpenLayers/Handler/Click.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt
- * for the full text of the license. */
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
 
 /**
  * @requires OpenLayers/Handler.js
@@ -18811,9 +20060,9 @@
  *     click.  By setting a <pixelTolerance>, controls can also ignore clicks
  *     that include a drag.  Create a new instance with the
  *     <OpenLayers.Handler.Click> constructor.
- *
+ * 
  * Inherits from:
- *  - <OpenLayers.Handler>
+ *  - <OpenLayers.Handler> 
  */
 OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
 
@@ -18823,20 +20072,20 @@
      *     considered a double-click.
      */
     delay: 300,
-
+    
     /**
      * APIProperty: single
      * {Boolean} Handle single clicks.  Default is true.  If false, clicks
      * will not be reported.  If true, single-clicks will be reported.
      */
     single: true,
-
+    
     /**
      * APIProperty: double
      * {Boolean} Handle double-clicks.  Default is false.
      */
     'double': false,
-
+    
     /**
      * APIProperty: pixelTolerance
      * {Number} Maximum number of pixels between mouseup and mousedown for an
@@ -18846,7 +20095,7 @@
      *     constructed.
      */
     pixelTolerance: 0,
-
+    
     /**
      * APIProperty: stopSingle
      * {Boolean} Stop other listeners from being notified of clicks.  Default
@@ -18855,13 +20104,13 @@
      *     or single clicks).
      */
     stopSingle: false,
-
+    
     /**
      * APIProperty: stopDouble
      * {Boolean} Stop other listeners from being notified of double-clicks.
      *     Default is false.  If true, any click listeners registered before
      *     this one will not be notified of *any* double-click events.
-     *
+     * 
      * The one caveat with stopDouble is that given a map with two click
      *     handlers, one with stopDouble true and the other with stopSingle
      *     true, the stopSingle handler should be activated last to get
@@ -18877,24 +20126,24 @@
      * {Number} The id of the timeout waiting to clear the <delayedCall>.
      */
     timerId: null,
-
+    
     /**
      * Property: down
      * {<OpenLayers.Pixel>} The pixel location of the last mousedown.
      */
     down: null,
-
+    
     /**
      * Property: rightclickTimerId
-     * {Number} The id of the right mouse timeout waiting to clear the
+     * {Number} The id of the right mouse timeout waiting to clear the 
      *     <delayedEvent>.
      */
     rightclickTimerId: null,
-
+    
     /**
      * Constructor: OpenLayers.Handler.Click
      * Create a new click handler.
-     *
+     * 
      * Parameters:
      * control - {<OpenLayers.Control>} The control that is making use of
      *     this handler.  If a handler is being used without a control, the
@@ -18917,7 +20166,7 @@
             };
         }
     },
-
+    
     /**
      * Method: mousedown
      * Handle mousedown.  Only registered as a listener if pixelTolerance is
@@ -18931,7 +20180,7 @@
     /**
      * Method: mouseup
      * Handle mouseup.  Installed to support collection of right mouse events.
-     *
+     * 
      * Returns:
      * {Boolean} Continue propagating this event.
      */
@@ -18941,55 +20190,55 @@
         // Collect right mouse clicks from the mouseup
         //  IE - ignores the second right click in mousedown so using
         //  mouseup instead
-        if (this.checkModifiers(evt) &&
-            this.control.handleRightClicks &&
+        if (this.checkModifiers(evt) && 
+            this.control.handleRightClicks && 
             OpenLayers.Event.isRightClick(evt)) {
           propagate = this.rightclick(evt);
         }
 
         return propagate;
     },
-
+    
     /**
      * Method: rightclick
-     * Handle rightclick.  For a dblrightclick, we get two clicks so we need
-     *     to always register for dblrightclick to properly handle single
+     * Handle rightclick.  For a dblrightclick, we get two clicks so we need 
+     *     to always register for dblrightclick to properly handle single 
      *     clicks.
-     *
+     *     
      * Returns:
      * {Boolean} Continue propagating this event.
      */
     rightclick: function(evt) {
         if(this.passesTolerance(evt)) {
            if(this.rightclickTimerId != null) {
-                //Second click received before timeout this must be
+                //Second click received before timeout this must be 
                 // a double click
-                this.clearTimer();
+                this.clearTimer();      
                 this.callback('dblrightclick', [evt]);
                 return !this.stopDouble;
-            } else {
-                //Set the rightclickTimerId, send evt only if double is
+            } else { 
+                //Set the rightclickTimerId, send evt only if double is 
                 // true else trigger single
                 var clickEvent = this['double'] ?
-                    OpenLayers.Util.extend({}, evt) :
+                    OpenLayers.Util.extend({}, evt) : 
                     this.callback('rightclick', [evt]);
 
                 var delayedRightCall = OpenLayers.Function.bind(
-                    this.delayedRightCall,
-                    this,
+                    this.delayedRightCall, 
+                    this, 
                     clickEvent
                 );
                 this.rightclickTimerId = window.setTimeout(
                     delayedRightCall, this.delay
                 );
-            }
+            } 
         }
         return !this.stopSingle;
     },
-
+    
     /**
      * Method: delayedRightCall
-     * Sets <rightclickTimerId> to null.  And optionally triggers the
+     * Sets <rightclickTimerId> to null.  And optionally triggers the 
      *     rightclick callback if evt is set.
      */
     delayedRightCall: function(evt) {
@@ -18999,13 +20248,13 @@
         }
         return !this.stopSingle;
     },
-
+    
     /**
      * Method: dblclick
      * Handle dblclick.  For a dblclick, we get two clicks in some browsers
      *     (FF) and one in others (IE).  So we need to always register for
      *     dblclick to properly handle single clicks.
-     *
+     *     
      * Returns:
      * {Boolean} Continue propagating this event.
      */
@@ -19018,7 +20267,7 @@
         }
         return !this.stopDouble;
     },
-
+    
     /**
      * Method: click
      * Handle click.
@@ -19033,7 +20282,7 @@
                 this.clearTimer();
             } else {
                 // set the timer, send evt only if single is true
-                //use a clone of the event object because it will no longer
+                //use a clone of the event object because it will no longer 
                 //be a valid event object in IE in the timer callback
                 var clickEvent = this.single ?
                     OpenLayers.Util.extend({}, evt) : null;
@@ -19045,7 +20294,7 @@
         }
         return !this.stopSingle;
     },
-
+    
     /**
      * Method: passesTolerance
      * Determine whether the event is within the optional pixel tolerance.  Note
@@ -19085,7 +20334,7 @@
             this.rightclickTimerId = null;
         }
     },
-
+    
     /**
      * Method: delayedCall
      * Sets <timerId> to null.  And optionally triggers the click callback if
@@ -19121,8 +20370,9 @@
     OpenLayers/Handler/Drag.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -19151,14 +20401,14 @@
  *  - <OpenLayers.Handler>
  */
 OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
-
-    /**
+  
+    /** 
      * Property: started
      * {Boolean} When a mousedown event is received, we want to record it, but
-     *     not set 'dragging' until the mouse moves after starting.
+     *     not set 'dragging' until the mouse moves after starting. 
      */
     started: false,
-
+    
     /**
      * Property: stopDown
      * {Boolean} Stop propagation of mousedown events from getting to listeners
@@ -19166,19 +20416,19 @@
      */
     stopDown: true,
 
-    /**
-     * Property: dragging
-     * {Boolean}
+    /** 
+     * Property: dragging 
+     * {Boolean} 
      */
     dragging: false,
 
-    /**
+    /** 
      * Property: last
      * {<OpenLayers.Pixel>} The last pixel location of the drag.
      */
     last: null,
 
-    /**
+    /** 
      * Property: start
      * {<OpenLayers.Pixel>} The first pixel location of the drag.
      */
@@ -19189,28 +20439,42 @@
      * {Function}
      */
     oldOnselectstart: null,
-
+    
     /**
      * Property: interval
-     * {Integer} In order to increase performance, an interval (in
-     *     milliseconds) can be set to reduce the number of drag events
-     *     called. If set, a new drag event will not be set until the
-     *     interval has passed.
-     *     Defaults to 0, meaning no interval.
+     * {Integer} In order to increase performance, an interval (in 
+     *     milliseconds) can be set to reduce the number of drag events 
+     *     called. If set, a new drag event will not be set until the 
+     *     interval has passed. 
+     *     Defaults to 0, meaning no interval. 
      */
     interval: 0,
-
+    
     /**
      * Property: timeoutId
      * {String} The id of the timeout used for the mousedown interval.
      *     This is "private", and should be left alone.
      */
     timeoutId: null,
+    
+    /**
+     * APIProperty: documentDrag
+     * {Boolean} If set to true, the handler will also handle mouse moves when
+     *     the cursor has moved out of the map viewport. Default is false.
+     */
+    documentDrag: false,
+    
+    /**
+     * Property: documentEvents
+     * {<OpenLayers.Events>} Event instance for observing document events. Will
+     *     be set on mouseout if documentDrag is set to true.
+     */
+    documentEvents: null,
 
     /**
      * Constructor: OpenLayers.Handler.Drag
      * Returns OpenLayers.Handler.Drag
-     *
+     * 
      * Parameters:
      * control - {<OpenLayers.Control>} The control that is making use of
      *     this handler.  If a handler is being used without a control, the
@@ -19221,17 +20485,17 @@
      *     expect to recieve a single argument, the pixel location of the event.
      *     Callbacks for 'move' and 'done' are supported. You can also speficy
      *     callbacks for 'down', 'up', and 'out' to respond to those events.
-     * options - {Object}
+     * options - {Object} 
      */
     initialize: function(control, callbacks, options) {
         OpenLayers.Handler.prototype.initialize.apply(this, arguments);
     },
-
+    
     /**
      * The four methods below (down, move, up, and out) are used by subclasses
      *     to do their own processing related to these mouse events.
      */
-
+    
     /**
      * Method: down
      * This method is called during the handling of the mouse down event.
@@ -19242,7 +20506,7 @@
      */
     down: function(evt) {
     },
-
+    
     /**
      * Method: move
      * This method is called during the handling of the mouse move event.
@@ -19288,7 +20552,7 @@
      * Handle mousedown events
      *
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      *
      * Returns:
      * {Boolean} Let the event propagate.
@@ -19306,12 +20570,12 @@
             this.down(evt);
             this.callback("down", [evt.xy]);
             OpenLayers.Event.stop(evt);
-
+            
             if(!this.oldOnselectstart) {
-                this.oldOnselectstart = (document.onselectstart) ? document.onselectstart : function() { return true; };
-                document.onselectstart = function() {return false;};
+                this.oldOnselectstart = (document.onselectstart) ? document.onselectstart : OpenLayers.Function.True;
             }
-
+            document.onselectstart = OpenLayers.Function.False;
+            
             propagate = !this.stopDown;
         } else {
             this.started = false;
@@ -19326,13 +20590,23 @@
      * Handle mousemove events
      *
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      *
      * Returns:
      * {Boolean} Let the event propagate.
      */
     mousemove: function (evt) {
         if (this.started && !this.timeoutId && (evt.xy.x != this.last.x || evt.xy.y != this.last.y)) {
+            if(this.documentDrag === true && this.documentEvents) {
+                if(evt.element === document) {
+                    this.adjustXY(evt);
+                    // do setEvent manually because the documentEvents are not
+                    // registered with the map
+                    this.setEvent(evt);
+                } else {
+                    this.destroyDocumentEvents();
+                }
+            }
             if (this.interval > 0) {
                 this.timeoutId = setTimeout(OpenLayers.Function.bind(this.removeTimeout, this), this.interval);
             }
@@ -19341,13 +20615,13 @@
             this.callback("move", [evt.xy]);
             if(!this.oldOnselectstart) {
                 this.oldOnselectstart = document.onselectstart;
-                document.onselectstart = function() {return false;};
+                document.onselectstart = OpenLayers.Function.False;
             }
             this.last = this.evt.xy;
         }
         return true;
     },
-
+    
     /**
      * Method: removeTimeout
      * Private. Called by mousemove() to remove the drag timeout.
@@ -19361,13 +20635,17 @@
      * Handle mouseup events
      *
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      *
      * Returns:
      * {Boolean} Let the event propagate.
      */
     mouseup: function (evt) {
         if (this.started) {
+            if(this.documentDrag === true && this.documentEvents) {
+                this.adjustXY(evt);
+                this.destroyDocumentEvents();
+            }
             var dragged = (this.start != this.last);
             this.started = false;
             this.dragging = false;
@@ -19389,27 +20667,39 @@
      * Handle mouseout events
      *
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      *
      * Returns:
      * {Boolean} Let the event propagate.
      */
     mouseout: function (evt) {
         if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
-            var dragged = (this.start != this.last);
-            this.started = false;
-            this.dragging = false;
-            OpenLayers.Element.removeClass(
-                this.map.viewPortDiv, "olDragDown"
-            );
-            this.out(evt);
-            this.callback("out", []);
-            if(dragged) {
-                this.callback("done", [evt.xy]);
+            if(this.documentDrag === true) {
+                this.documentEvents = new OpenLayers.Events(this, document,
+                                            null, null, {includeXY: true});
+                this.documentEvents.on({
+                    mousemove: this.mousemove,
+                    mouseup: this.mouseup
+                });
+                OpenLayers.Element.addClass(
+                    document.body, "olDragDown"
+                );
+            } else {
+                var dragged = (this.start != this.last);
+                this.started = false; 
+                this.dragging = false;
+                OpenLayers.Element.removeClass(
+                    this.map.viewPortDiv, "olDragDown"
+                );
+                this.out(evt);
+                this.callback("out", []);
+                if(dragged) {
+                    this.callback("done", [evt.xy]);
+                }
+                if(document.onselectstart) {
+                    document.onselectstart = this.oldOnselectstart;
+                }
             }
-            if(document.onselectstart) {
-                document.onselectstart = this.oldOnselectstart;
-            }
         }
         return true;
     },
@@ -19417,12 +20707,12 @@
     /**
      * Method: click
      * The drag handler captures the click event.  If something else registers
-     *     for clicks on the same element, its listener will not be called
+     *     for clicks on the same element, its listener will not be called 
      *     after a drag.
-     *
-     * Parameters:
-     * evt - {Event}
-     *
+     * 
+     * Parameters: 
+     * evt - {Event} 
+     * 
      * Returns:
      * {Boolean} Let the event propagate.
      */
@@ -19434,7 +20724,7 @@
     /**
      * Method: activate
      * Activate the handler.
-     *
+     * 
      * Returns:
      * {Boolean} The handler was successfully activated.
      */
@@ -19448,9 +20738,9 @@
     },
 
     /**
-     * Method: deactivate
+     * Method: deactivate 
      * Deactivate the handler.
-     *
+     * 
      * Returns:
      * {Boolean} The handler was successfully deactivated.
      */
@@ -19468,6 +20758,35 @@
         }
         return deactivated;
     },
+    
+    /**
+     * Method: adjustXY
+     * Converts event coordinates that are relative to the document body to
+     * ones that are relative to the map viewport. The latter is the default in
+     * OpenLayers.
+     * 
+     * Parameters:
+     * evt - {Object}
+     */
+    adjustXY: function(evt) {
+        var pos = OpenLayers.Util.pagePosition(this.map.div);
+        evt.xy.x -= pos[0];
+        evt.xy.y -= pos[1];
+    },
+    
+    /**
+     * Method: destroyDocumentEvents
+     * Destroys the events instance that gets added to the document body when
+     * documentDrag is true and the mouse cursor leaves the map viewport while
+     * dragging.
+     */
+    destroyDocumentEvents: function() {
+        OpenLayers.Element.removeClass(
+            document.body, "olDragDown"
+        );
+        this.documentEvents.destroy();
+        this.documentEvents = null;
+    },
 
     CLASS_NAME: "OpenLayers.Handler.Drag"
 });
@@ -19475,8 +20794,9 @@
     OpenLayers/Handler/Feature.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -19485,7 +20805,7 @@
  */
 
 /**
- * Class: OpenLayers.Handler.Feature
+ * Class: OpenLayers.Handler.Feature 
  * Handler to respond to mouse events related to a drawn feature.  Callbacks
  *     with the following keys will be notified of the following events
  *     associated with features: click, clickout, over, out, and dblclick.
@@ -19531,7 +20851,7 @@
      * {<OpenLayers.Pixel>} The location of the last mouseup.
      */
     up: null,
-
+    
     /**
      * Property: clickTolerance
      * {Number} The number of pixels the mouse can move between mousedown
@@ -19545,7 +20865,7 @@
      * Property: geometryTypes
      * To restrict dragging to a limited set of geometry types, send a list
      * of strings corresponding to the geometry class names.
-     *
+     * 
      * @type Array(String)
      */
     geometryTypes: null,
@@ -19576,17 +20896,17 @@
      *      value of stopUp. Defaults to false.
      */
     stopUp: false,
-
+    
     /**
      * Constructor: OpenLayers.Handler.Feature
      *
      * Parameters:
-     * control - {<OpenLayers.Control>}
+     * control - {<OpenLayers.Control>} 
      * layer - {<OpenLayers.Layer.Vector>}
      * callbacks - {Object} An object with a 'over' property whos value is
-     *     a function to be called when the mouse is over a feature. The
+     *     a function to be called when the mouse is over a feature. The 
      *     callback should expect to recieve a single argument, the feature.
-     * options - {Object}
+     * options - {Object} 
      */
     initialize: function(control, layer, callbacks, options) {
         OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]);
@@ -19598,22 +20918,22 @@
      * Method: mousedown
      * Handle mouse down.  Stop propagation if a feature is targeted by this
      *     event (stops map dragging during feature selection).
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     mousedown: function(evt) {
         this.down = evt.xy;
         return this.handle(evt) ? !this.stopDown : true;
     },
-
+    
     /**
      * Method: mouseup
      * Handle mouse up.  Stop propagation if a feature is targeted by this
      *     event.
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     mouseup: function(evt) {
         this.up = evt.xy;
@@ -19624,9 +20944,9 @@
      * Method: click
      * Handle click.  Call the "click" callback if click on a feature,
      *     or the "clickout" callback if click outside any feature.
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      *
      * Returns:
      * {Boolean}
@@ -19634,14 +20954,14 @@
     click: function(evt) {
         return this.handle(evt) ? !this.stopClick : true;
     },
-
+        
     /**
      * Method: mousemove
      * Handle mouse moves.  Call the "over" callback if moving in to a feature,
      *     or the "out" callback if moving out of a feature.
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      *
      * Returns:
      * {Boolean}
@@ -19649,17 +20969,17 @@
     mousemove: function(evt) {
         if (!this.callbacks['over'] && !this.callbacks['out']) {
             return true;
-        }
+        }     
         this.handle(evt);
         return true;
     },
-
+    
     /**
      * Method: dblclick
      * Handle dblclick.  Call the "dblclick" callback if dblclick on a feature.
      *
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      *
      * Returns:
      * {Boolean}
@@ -19748,7 +21068,7 @@
         }
         return handled;
     },
-
+    
     /**
      * Method: triggerCallback
      * Call the callback keyed in the event map with the supplied arguments.
@@ -19776,7 +21096,7 @@
     },
 
     /**
-     * Method: activate
+     * Method: activate 
      * Turn on the handler.  Returns false if the handler was already active.
      *
      * Returns:
@@ -19795,12 +21115,12 @@
         }
         return activated;
     },
-
+    
     /**
-     * Method: deactivate
+     * Method: deactivate 
      * Turn off the handler.  Returns false if the handler was already active.
      *
-     * Returns:
+     * Returns: 
      * {Boolean}
      */
     deactivate: function() {
@@ -19820,10 +21140,10 @@
         }
         return deactivated;
     },
-
+    
     /**
      * Method handleMapEvents
-     *
+     * 
      * Parameters:
      * evt - {Object}
      */
@@ -19832,7 +21152,7 @@
             this.moveLayerToTop();
         }
     },
-
+    
     /**
      * Method: moveLayerToTop
      * Moves the layer for this handler to the top, so mouse events can reach
@@ -19842,9 +21162,9 @@
         var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1,
             this.layer.getZIndex()) + 1;
         this.layer.setZIndex(index);
-
+        
     },
-
+    
     /**
      * Method: moveLayerBack
      * Moves the layer back to the position determined by the map's layers
@@ -19866,9 +21186,10 @@
     OpenLayers/Handler/Hover.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt
- * for the full text of the license. */
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
 
 /**
  * @requires OpenLayers/Handler.js
@@ -19880,9 +21201,9 @@
  *      on the map that aren't DOM elements. For example one can use
  *      this handler to send WMS/GetFeatureInfo requests as the user
  *      moves the mouve over the map.
- *
+ * 
  * Inherits from:
- *  - <OpenLayers.Handler>
+ *  - <OpenLayers.Handler> 
  */
 OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, {
 
@@ -19892,7 +21213,7 @@
      *      the event is considered a hover. Default is 500.
      */
     delay: 500,
-
+    
     /**
      * APIProperty: pixelTolerance
      * {Integer} - Maximum number of pixels between mousemoves for
@@ -19919,7 +21240,7 @@
      * {Number} - The id of the timer.
      */
     timerId: null,
-
+ 
     /**
      * Constructor: OpenLayers.Handler.Hover
      * Construct a hover handler.
@@ -20052,8 +21373,9 @@
     OpenLayers/Handler/MouseWheel.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -20063,18 +21385,18 @@
 /**
  * Class: OpenLayers.Handler.MouseWheel
  * Handler for wheel up/down events.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Handler>
  */
 OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
-    /**
-     * Property: wheelListener
-     * {function}
+    /** 
+     * Property: wheelListener 
+     * {function} 
      */
     wheelListener: null,
 
-    /**
+    /** 
      * Property: mousePosition
      * {<OpenLayers.Pixel>} mousePosition is necessary because
      * evt.clientX/Y is buggy in Moz on wheel events, so we cache and use the
@@ -20083,15 +21405,41 @@
     mousePosition: null,
 
     /**
+     * Property: interval
+     * {Integer} In order to increase server performance, an interval (in 
+     *     milliseconds) can be set to reduce the number of up/down events 
+     *     called. If set, a new up/down event will not be set until the 
+     *     interval has passed. 
+     *     Defaults to 0, meaning no interval. 
+     */
+    interval: 0,
+    
+    /**
+     * Property: delta
+     * {Integer} When interval is set, delta collects the mousewheel z-deltas
+     *     of the events that occur within the interval.
+     *      See also the cumulative option
+     */
+    delta: 0,
+    
+    /**
+     * Property: cumulative
+     * {Boolean} When interval is set: true to collect all the mousewheel 
+     *     z-deltas, false to only record the delta direction (positive or
+     *     negative)
+     */
+    cumulative: true,
+
+    /**
      * Constructor: OpenLayers.Handler.MouseWheel
      *
      * Parameters:
-     * control - {<OpenLayers.Control>}
+     * control - {<OpenLayers.Control>} 
      * callbacks - {Object} An object containing a single function to be
      *                          called when the drag operation is finished.
      *                          The callback should expect to recieve a single
      *                          argument, the point geometry.
-     * options - {Object}
+     * options - {Object} 
      */
     initialize: function(control, callbacks, options) {
         OpenLayers.Handler.prototype.initialize.apply(this, arguments);
@@ -20102,7 +21450,7 @@
 
     /**
      * Method: destroy
-     */
+     */    
     destroy: function() {
         OpenLayers.Handler.prototype.destroy.apply(this, arguments);
         this.wheelListener = null;
@@ -20112,22 +21460,22 @@
      *  Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
      */
 
-    /**
+    /** 
      * Method: onWheelEvent
      * Catch the wheel event and handle it xbrowserly
-     *
+     * 
      * Parameters:
-     * e - {Event}
+     * e - {Event} 
      */
     onWheelEvent: function(e){
-
+        
         // make sure we have a map and check keyboard modifiers
         if (!this.map || !this.checkModifiers(e)) {
             return;
         }
-
-        // Ride up the element's DOM hierarchy to determine if it or any of
-        //  its ancestors was:
+        
+        // Ride up the element's DOM hierarchy to determine if it or any of 
+        //  its ancestors was: 
         //   * specifically marked as scrollable
         //   * one of our layer divs
         //   * the map div
@@ -20135,7 +21483,7 @@
         var overScrollableDiv = false;
         var overLayerDiv = false;
         var overMapDiv = false;
-
+        
         var elem = OpenLayers.Event.element(e);
         while((elem != null) && !overMapDiv && !overScrollableDiv) {
 
@@ -20144,14 +21492,14 @@
                     if (elem.currentStyle) {
                         overflow = elem.currentStyle["overflow"];
                     } else {
-                        var style =
+                        var style = 
                             document.defaultView.getComputedStyle(elem, null);
                         var overflow = style.getPropertyValue("overflow");
                     }
-                    overScrollableDiv = ( overflow &&
+                    overScrollableDiv = ( overflow && 
                         (overflow == "auto") || (overflow == "scroll") );
                 } catch(err) {
-                    //sometimes when scrolling in a popup, this causes
+                    //sometimes when scrolling in a popup, this causes 
                     // obscure browser error
                 }
             }
@@ -20159,10 +21507,10 @@
             if (!overLayerDiv) {
                 for(var i=0, len=this.map.layers.length; i<len; i++) {
                     // Are we in the layer div? Note that we have two cases
-                    // here: one is to catch EventPane layers, which have a
+                    // here: one is to catch EventPane layers, which have a 
                     // pane above the layer (layer.pane)
-                    if (elem == this.map.layers[i].div
-                        || elem == this.map.layers[i].pane) {
+                    if (elem == this.map.layers[i].div 
+                        || elem == this.map.layers[i].pane) { 
                         overLayerDiv = true;
                         break;
                     }
@@ -20172,27 +21520,51 @@
 
             elem = elem.parentNode;
         }
-
+        
         // Logic below is the following:
         //
         // If we are over a scrollable div or not over the map div:
         //  * do nothing (let the browser handle scrolling)
         //
-        //    otherwise
-        //
-        //    If we are over the layer div:
+        //    otherwise 
+        // 
+        //    If we are over the layer div: 
         //     * zoom/in out
         //     then
         //     * kill event (so as not to also scroll the page after zooming)
         //
         //       otherwise
         //
-        //       Kill the event (dont scroll the page if we wheel over the
+        //       Kill the event (dont scroll the page if we wheel over the 
         //        layerswitcher or the pan/zoom control)
         //
         if (!overScrollableDiv && overMapDiv) {
             if (overLayerDiv) {
-                this.wheelZoom(e);
+                var delta = 0;
+                if (!e) {
+                    e = window.event;
+                }
+                if (e.wheelDelta) {
+                    delta = e.wheelDelta/120; 
+                    if (window.opera && window.opera.version() < 9.2) {
+                        delta = -delta;
+                    }
+                } else if (e.detail) {
+                    delta = -e.detail / 3;
+                }
+                this.delta = this.delta + delta;
+
+                if(this.interval) {
+                    window.clearTimeout(this._timeoutId);
+                    this._timeoutId = window.setTimeout(
+                        OpenLayers.Function.bind(function(){
+                            this.wheelZoom(e);
+                        }, this),
+                        this.interval
+                    );
+                } else {
+                    this.wheelZoom(e);
+                }
             }
             OpenLayers.Event.stop(e);
         }
@@ -20202,58 +21574,48 @@
      * Method: wheelZoom
      * Given the wheel event, we carry out the appropriate zooming in or out,
      *     based on the 'wheelDelta' or 'detail' property of the event.
-     *
+     * 
      * Parameters:
      * e - {Event}
      */
     wheelZoom: function(e) {
-
-        var delta = 0;
-        if (!e) {
-            e = window.event;
-        }
-        if (e.wheelDelta) {
-            delta = e.wheelDelta/120;
-            if (window.opera && window.opera.version() < 9.2) {
-                delta = -delta;
-            }
-        } else if (e.detail) {
-            delta = -e.detail / 3;
-        }
+        var delta = this.delta;
+        this.delta = 0;
+        
         if (delta) {
-            // add the mouse position to the event because mozilla has
-            // a bug with clientX and clientY (see
+            // add the mouse position to the event because mozilla has 
+            // a bug with clientX and clientY (see 
             // https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
             // getLonLatFromViewPortPx(e) returns wrong values
             if (this.mousePosition) {
                 e.xy = this.mousePosition;
-            }
+            } 
             if (!e.xy) {
                 // If the mouse hasn't moved over the map yet, then
                 // we don't have a mouse position (in FF), so we just
                 // act as if the mouse was at the center of the map.
-                // Note that we can tell we are in the map -- and
+                // Note that we can tell we are in the map -- and 
                 // this.map is ensured to be true above.
                 e.xy = this.map.getPixelFromLonLat(
                     this.map.getCenter()
                 );
             }
             if (delta < 0) {
-               this.callback("down", [e, delta]);
+                this.callback("down", [e, this.cumulative ? delta : -1]);
             } else {
-               this.callback("up", [e, delta]);
+                this.callback("up", [e, this.cumulative ? delta : 1]);
             }
         }
     },
-
+    
     /**
      * Method: mousemove
      * Update the stored mousePosition on every move.
-     *
+     * 
      * Parameters:
      * evt - {Event} The browser event
      *
-     * Returns:
+     * Returns: 
      * {Boolean} Allow event propagation
      */
     mousemove: function (evt) {
@@ -20261,7 +21623,7 @@
     },
 
     /**
-     * Method: activate
+     * Method: activate 
      */
     activate: function (evt) {
         if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
@@ -20277,7 +21639,7 @@
     },
 
     /**
-     * Method: deactivate
+     * Method: deactivate 
      */
     deactivate: function (evt) {
         if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
@@ -20298,8 +21660,9 @@
     OpenLayers/Layer.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -20319,13 +21682,13 @@
      */
     id: null,
 
-    /**
+    /** 
      * APIProperty: name
      * {String}
      */
     name: null,
 
-    /**
+    /** 
      * APIProperty: div
      * {DOMElement}
      */
@@ -20339,20 +21702,20 @@
 
     /**
      * APIProperty: alwaysInRange
-     * {Boolean} If a layer's display should not be scale-based, this should
-     *     be set to true. This will cause the layer, as an overlay, to always
-     *     be 'active', by always returning true from the calculateInRange()
-     *     function.
-     *
-     *     If not explicitly specified for a layer, its value will be
-     *     determined on startup in initResolutions() based on whether or not
-     *     any scale-specific properties have been set as options on the
-     *     layer. If no scale-specific options have been set on the layer, we
+     * {Boolean} If a layer's display should not be scale-based, this should 
+     *     be set to true. This will cause the layer, as an overlay, to always 
+     *     be 'active', by always returning true from the calculateInRange() 
+     *     function. 
+     * 
+     *     If not explicitly specified for a layer, its value will be 
+     *     determined on startup in initResolutions() based on whether or not 
+     *     any scale-specific properties have been set as options on the 
+     *     layer. If no scale-specific options have been set on the layer, we 
      *     assume that it should always be in range.
-     *
+     * 
      *     See #987 for more info.
      */
-    alwaysInRange: null,
+    alwaysInRange: null,   
 
     /**
      * Constant: EVENT_TYPES
@@ -20384,6 +21747,18 @@
                   "move", "moveend"],
 
     /**
+     * Constant: RESOLUTION_PROPERTIES
+     * {Array} The properties that are used for calculating resolutions
+     *     information.
+     */
+    RESOLUTION_PROPERTIES: [
+        'scales', 'resolutions',
+        'maxScale', 'minScale',
+        'maxResolution', 'minResolution',
+        'numZoomLevels', 'maxZoomLevel'
+    ],
+
+    /**
      * APIProperty: events
      * {<OpenLayers.Events>}
      */
@@ -20391,25 +21766,25 @@
 
     /**
      * APIProperty: map
-     * {<OpenLayers.Map>} This variable is set when the layer is added to
+     * {<OpenLayers.Map>} This variable is set when the layer is added to 
      *     the map, via the accessor function setMap().
      */
     map: null,
-
+    
     /**
      * APIProperty: isBaseLayer
-     * {Boolean} Whether or not the layer is a base layer. This should be set
+     * {Boolean} Whether or not the layer is a base layer. This should be set 
      *     individually by all subclasses. Default is false
      */
     isBaseLayer: false,
-
+ 
     /**
      * Property: alpha
-     * {Boolean} The layer's images have an alpha channel.  Default is false.
+     * {Boolean} The layer's images have an alpha channel.  Default is false. 
      */
     alpha: false,
 
-    /**
+    /** 
      * APIProperty: displayInLayerSwitcher
      * {Boolean} Display the layer's name in the layer switcher.  Default is
      *     true.
@@ -20424,36 +21799,36 @@
 
     /**
      * APIProperty: attribution
-     * {String} Attribution string, displayed when an
+     * {String} Attribution string, displayed when an 
      *     <OpenLayers.Control.Attribution> has been added to the map.
      */
-    attribution: null,
+    attribution: null, 
 
-    /**
+    /** 
      * Property: inRange
-     * {Boolean} The current map resolution is within the layer's min/max
-     *     range. This is set in <OpenLayers.Map.setCenter> whenever the zoom
+     * {Boolean} The current map resolution is within the layer's min/max 
+     *     range. This is set in <OpenLayers.Map.setCenter> whenever the zoom 
      *     changes.
      */
     inRange: false,
-
+    
     /**
      * Propery: imageSize
-     * {<OpenLayers.Size>} For layers with a gutter, the image is larger than
+     * {<OpenLayers.Size>} For layers with a gutter, the image is larger than 
      *     the tile by twice the gutter in each dimension.
      */
     imageSize: null,
-
+    
     /**
      * Property: imageOffset
-     * {<OpenLayers.Pixel>} For layers with a gutter, the image offset
+     * {<OpenLayers.Pixel>} For layers with a gutter, the image offset 
      *     represents displacement due to the gutter.
      */
     imageOffset: null,
 
   // OPTIONS
 
-    /**
+    /** 
      * Property: options
      * {Object} An optional object whose properties will be set on the layer.
      *     Any of the layer properties can be set as a property of the options
@@ -20479,8 +21854,8 @@
      *     at tile edges to be ignored.  Set a gutter value that is equal to
      *     half the size of the widest symbol that needs to be displayed.
      *     Defaults to zero.  Non-tiled layers always have zero gutter.
-     */
-    gutter: 0,
+     */ 
+    gutter: 0, 
 
     /**
      * APIProperty: projection
@@ -20488,10 +21863,10 @@
      *     override the default projection string this layer - also set maxExtent,
      *     maxResolution, and units if appropriate. Can be either a string or
      *     an <OpenLayers.Projection> object when created -- will be converted
-     *     to an object when setMap is called if a string is passed.
+     *     to an object when setMap is called if a string is passed.  
      */
-    projection: null,
-
+    projection: null,    
+    
     /**
      * APIProperty: units
      * {String} The layer map units.  Defaults to 'degrees'.  Possible values
@@ -20518,7 +21893,7 @@
      *     maxResolution, maxScale, etc.).
      */
     resolutions: null,
-
+    
     /**
      * APIProperty: maxExtent
      * {<OpenLayers.Bounds>}  The center of these bounds will not stray outside
@@ -20527,18 +21902,18 @@
      *     requested that falls completely outside of these bounds.
      */
     maxExtent: null,
-
+    
     /**
      * APIProperty: minExtent
      * {<OpenLayers.Bounds>}
      */
     minExtent: null,
-
+    
     /**
      * APIProperty: maxResolution
      * {Float} Default max is 360 deg / 256 px, which corresponds to
-     *     zoom level 0 on gmaps.  Specify a different value in the layer
-     *     options if you are not using a geographic projection and
+     *     zoom level 0 on gmaps.  Specify a different value in the layer 
+     *     options if you are not using a geographic projection and 
      *     displaying the whole world.
      */
     maxResolution: null,
@@ -20554,13 +21929,13 @@
      * {Integer}
      */
     numZoomLevels: null,
-
+   
     /**
      * APIProperty: minScale
      * {Float}
      */
     minScale: null,
-
+    
     /**
      * APIProperty: maxScale
      * {Float}
@@ -20569,21 +21944,21 @@
 
     /**
      * APIProperty: displayOutsideMaxExtent
-     * {Boolean} Request map tiles that are completely outside of the max
+     * {Boolean} Request map tiles that are completely outside of the max 
      *     extent for this layer. Defaults to false.
      */
     displayOutsideMaxExtent: false,
 
     /**
      * APIProperty: wrapDateLine
-     * {Boolean} #487 for more info.
+     * {Boolean} #487 for more info.   
      */
     wrapDateLine: false,
-
+    
     /**
      * APIProperty: transitionEffect
      * {String} The transition effect to use when the map is panned or
-     *     zoomed.
+     *     zoomed.  
      *
      * There are currently two supported values:
      *  - *null* No transition effect (the default).
@@ -20593,15 +21968,22 @@
      *    resized tiles.
      */
     transitionEffect: null,
-
+    
     /**
      * Property: SUPPORTED_TRANSITIONS
-     * {Array} An immutable (that means don't change it!) list of supported
+     * {Array} An immutable (that means don't change it!) list of supported 
      *     transitionEffect values.
      */
     SUPPORTED_TRANSITIONS: ['resize'],
 
     /**
+     * Property: metadata
+     * {Object} This object can be used to store additional information on a
+     *     layer object.
+     */
+    metadata: {},
+    
+    /**
      * Constructor: OpenLayers.Layer
      *
      * Parameters:
@@ -20613,7 +21995,7 @@
         this.addOptions(options);
 
         this.name = name;
-
+        
         if (this.id == null) {
 
             this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
@@ -20623,7 +22005,7 @@
             this.div.style.height = "100%";
             this.div.dir = "ltr";
 
-            this.events = new OpenLayers.Events(this, this.div,
+            this.events = new OpenLayers.Events(this, this.div, 
                                                 this.EVENT_TYPES);
             if(this.eventListeners instanceof Object) {
                 this.events.on(this.eventListeners);
@@ -20635,7 +22017,7 @@
             this.displayOutsideMaxExtent = true;
         }
     },
-
+    
     /**
      * Method: destroy
      * Destroy is a destructor: this is to alleviate cyclic references which
@@ -20667,7 +22049,7 @@
         this.eventListeners = null;
         this.events = null;
     },
-
+    
    /**
     * Method: clone
     *
@@ -20678,22 +22060,39 @@
     * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
     */
     clone: function (obj) {
-
+        
         if (obj == null) {
-            obj = new OpenLayers.Layer(this.name, this.options);
+            obj = new OpenLayers.Layer(this.name, this.getOptions());
         }
-
+        
         // catch any randomly tagged-on properties
         OpenLayers.Util.applyDefaults(obj, this);
-
+        
         // a cloned layer should never have its map property set
-        //  because it has not been added to a map yet.
+        //  because it has not been added to a map yet. 
         obj.map = null;
-
+        
         return obj;
     },
-
+    
     /**
+     * Method: getOptions
+     * Extracts an object from the layer with the properties that were set as
+     *     options, but updates them with the values currently set on the
+     *     instance.
+     * 
+     * Returns:
+     * {Object} the <options> of the layer, representing the current state.
+     */
+    getOptions: function() {
+        var options = {};
+        for(var o in this.options) {
+            options[o] = this[o];
+        }
+        return options;
+    },
+    
+    /** 
      * APIMethod: setName
      * Sets the new layer name for this layer.  Can trigger a changelayer event
      *     on the map.
@@ -20711,11 +22110,11 @@
                 });
             }
         }
-    },
-
+    },    
+    
    /**
     * APIMethod: addOptions
-    *
+    * 
     * Parameters:
     * newOptions - {Object}
     */
@@ -20730,6 +22129,34 @@
 
         // add new options to this
         OpenLayers.Util.extend(this, newOptions);
+
+        // make sure this.projection references a projection object
+        if(typeof this.projection == "string") {
+            this.projection = new OpenLayers.Projection(this.projection);
+        }
+
+        // get the units from the projection, if we have a projection
+        // and it it has units
+        if(this.projection && this.projection.getUnits()) {
+            this.units = this.projection.getUnits();
+        }
+
+        // re-initialize resolutions if necessary, i.e. if any of the
+        // properties of the "properties" array defined below is set
+        // in the new options
+        if(this.map) {
+            var properties = this.RESOLUTION_PROPERTIES.concat(
+                ["projection", "units", "minExtent", "maxExtent"]
+            );
+            for(var o in newOptions) {
+                if(newOptions.hasOwnProperty(o) &&
+                   OpenLayers.Util.indexOf(properties, o) >= 0) {
+
+                    this.initResolutions();
+                    break;
+                }
+            }
+        }
     },
 
     /**
@@ -20737,7 +22164,7 @@
      * This function can be implemented by subclasses
      */
     onMapResize: function() {
-        //this function can be implemented by subclasses
+        //this function can be implemented by subclasses  
     },
 
     /**
@@ -20770,7 +22197,7 @@
 
     /**
      * Method: moveTo
-     *
+     * 
      * Parameters:
      * bound - {<OpenLayers.Bounds>}
      * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
@@ -20788,26 +22215,27 @@
     /**
      * Method: setMap
      * Set the map property for the layer. This is done through an accessor
-     *     so that subclasses can override this and take special action once
-     *     they have their map variable set.
-     *
-     *     Here we take care to bring over any of the necessary default
-     *     properties from the map.
-     *
+     *     so that subclasses can override this and take special action once 
+     *     they have their map variable set. 
+     * 
+     *     Here we take care to bring over any of the necessary default 
+     *     properties from the map. 
+     * 
      * Parameters:
      * map - {<OpenLayers.Map>}
      */
     setMap: function(map) {
         if (this.map == null) {
-
+        
             this.map = map;
-
+            
             // grab some essential layer data from the map if it hasn't already
             //  been set
             this.maxExtent = this.maxExtent || this.map.maxExtent;
+            this.minExtent = this.minExtent || this.map.minExtent;
+
             this.projection = this.projection || this.map.projection;
-
-            if (this.projection && typeof this.projection == "string") {
+            if (typeof this.projection == "string") {
                 this.projection = new OpenLayers.Projection(this.projection);
             }
 
@@ -20815,20 +22243,20 @@
             // to properties.
             this.units = this.projection.getUnits() ||
                          this.units || this.map.units;
-
+            
             this.initResolutions();
-
+            
             if (!this.isBaseLayer) {
                 this.inRange = this.calculateInRange();
                 var show = ((this.visibility) && (this.inRange));
                 this.div.style.display = show ? "" : "none";
             }
-
+            
             // deal with gutters
             this.setTileSize();
         }
     },
-
+    
     /**
      * Method: afterAdd
      * Called at the end of the map.addLayer sequence.  At this point, the map
@@ -20836,39 +22264,44 @@
      */
     afterAdd: function() {
     },
-
+    
     /**
      * APIMethod: removeMap
-     * Just as setMap() allows each layer the possibility to take a
+     * Just as setMap() allows each layer the possibility to take a 
      *     personalized action on being added to the map, removeMap() allows
-     *     each layer to take a personalized action on being removed from it.
+     *     each layer to take a personalized action on being removed from it. 
      *     For now, this will be mostly unused, except for the EventPane layer,
      *     which needs this hook so that it can remove the special invisible
-     *     pane.
-     *
+     *     pane. 
+     * 
      * Parameters:
      * map - {<OpenLayers.Map>}
      */
     removeMap: function(map) {
         //to be overridden by subclasses
     },
-
+    
     /**
      * APIMethod: getImageSize
      *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} optional tile bounds, can be used
+     *     by subclasses that have to deal with different tile sizes at the
+     *     layer extent edges (e.g. Zoomify)
+     * 
      * Returns:
-     * {<OpenLayers.Size>} The size that the image should be, taking into
+     * {<OpenLayers.Size>} The size that the image should be, taking into 
      *     account gutters.
-     */
-    getImageSize: function() {
-        return (this.imageSize || this.tileSize);
-    },
-
+     */ 
+    getImageSize: function(bounds) { 
+        return (this.imageSize || this.tileSize); 
+    },    
+  
     /**
      * APIMethod: setTileSize
      * Set the tile size based on the map size.  This also sets layer.imageSize
      *     and layer.imageOffset for use by Tile.Image.
-     *
+     * 
      * Parameters:
      * size - {<OpenLayers.Size>}
      */
@@ -20884,16 +22317,16 @@
           //                              this.name + ": layers with " +
           //                              "gutters need non-null tile sizes");
           //}
-            this.imageOffset = new OpenLayers.Pixel(-this.gutter,
-                                                    -this.gutter);
-            this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter),
-                                                 tileSize.h + (2*this.gutter));
+            this.imageOffset = new OpenLayers.Pixel(-this.gutter, 
+                                                    -this.gutter); 
+            this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter), 
+                                                 tileSize.h + (2*this.gutter)); 
         }
     },
 
     /**
      * APIMethod: getVisibility
-     *
+     * 
      * Returns:
      * {Boolean} The layer should be displayed (if in range).
      */
@@ -20901,18 +22334,18 @@
         return this.visibility;
     },
 
-    /**
+    /** 
      * APIMethod: setVisibility
-     * Set the visibility flag for the layer and hide/show & redraw
+     * Set the visibility flag for the layer and hide/show & redraw 
      *     accordingly. Fire event unless otherwise specified
-     *
+     * 
      * Note that visibility is no longer simply whether or not the layer's
-     *     style.display is set to "block". Now we store a 'visibility' state
-     *     property on the layer class, this allows us to remember whether or
-     *     not we *desire* for a layer to be visible. In the case where the
-     *     map's resolution is out of the layer's range, this desire may be
+     *     style.display is set to "block". Now we store a 'visibility' state 
+     *     property on the layer class, this allows us to remember whether or 
+     *     not we *desire* for a layer to be visible. In the case where the 
+     *     map's resolution is out of the layer's range, this desire may be 
      *     subverted.
-     *
+     * 
      * Parameters:
      * visible - {Boolean} Whether or not to display the layer (if in range)
      */
@@ -20931,26 +22364,25 @@
         }
     },
 
-    /**
+    /** 
      * APIMethod: display
      * Hide or show the Layer
-     *
+     * 
      * Parameters:
      * display - {Boolean}
      */
     display: function(display) {
-        var inRange = this.calculateInRange();
         if (display != (this.div.style.display != "none")) {
-            this.div.style.display = (display && inRange) ? "block" : "none";
+            this.div.style.display = (display && this.calculateInRange()) ? "block" : "none";
         }
     },
 
     /**
      * APIMethod: calculateInRange
-     *
+     * 
      * Returns:
      * {Boolean} The layer is displayable at the current map's current
-     *     resolution. Note that if 'alwaysInRange' is true for the layer,
+     *     resolution. Note that if 'alwaysInRange' is true for the layer, 
      *     this function will always return true.
      */
     calculateInRange: function() {
@@ -20968,9 +22400,9 @@
         return inRange;
     },
 
-    /**
+    /** 
      * APIMethod: setIsBaseLayer
-     *
+     * 
      * Parameters:
      * isBaseLayer - {Boolean}
      */
@@ -20990,205 +22422,263 @@
   /*                 Baselayer Functions                  */
   /*                                                      */
   /********************************************************/
-
-    /**
+  
+    /** 
      * Method: initResolutions
-     * This method's responsibility is to set up the 'resolutions' array
+     * This method's responsibility is to set up the 'resolutions' array 
      *     for the layer -- this array is what the layer will use to interface
-     *     between the zoom levels of the map and the resolution display
+     *     between the zoom levels of the map and the resolution display 
      *     of the layer.
-     *
+     * 
      * The user has several options that determine how the array is set up.
-     *
-     * For a detailed explanation, see the following wiki from the
+     *  
+     * For a detailed explanation, see the following wiki from the 
      *     openlayers.org homepage:
      *     http://trac.openlayers.org/wiki/SettingZoomLevels
      */
     initResolutions: function() {
 
-        // These are the relevant options which are used for calculating
-        //  resolutions information.
+        // ok we want resolutions, here's our strategy:
         //
-        var props = new Array(
-          'projection', 'units',
-          'scales', 'resolutions',
-          'maxScale', 'minScale',
-          'maxResolution', 'minResolution',
-          'minExtent', 'maxExtent',
-          'numZoomLevels', 'maxZoomLevel'
-        );
+        // 1. if resolutions are defined in the layer config, use them
+        // 2. else, if scales are defined in the layer config then derive
+        //    resolutions from these scales
+        // 3. else, attempt to calculate resolutions from maxResolution,
+        //    minResolution, numZoomLevels, maxZoomLevel set in the
+        //    layer config
+        // 4. if we still don't have resolutions, and if resolutions
+        //    are defined in the same, use them
+        // 5. else, if scales are defined in the map then derive
+        //    resolutions from these scales
+        // 6. else, attempt to calculate resolutions from maxResolution,
+        //    minResolution, numZoomLevels, maxZoomLevel set in the
+        //    map
+        // 7. hope for the best!
 
-        //these are the properties which do *not* imply that user wishes
-        // this layer to be scale-dependant
-        var notScaleProps = ['projection', 'units'];
+        var i, len;
+        var props = {}, alwaysInRange = true;
 
-        //should the layer be scale-dependant? default is false -- this will
-        // only be set true if we find that the user has specified a property
-        // from the 'props' array that is not in 'notScaleProps'
-        var useInRange = false;
-
-        // First we create a new object where we will store all of the
-        //  resolution-related properties that we find in either the layer's
-        //  'options' array or from the map.
-        //
-        var confProps = {};
-        for(var i=0, len=props.length; i<len; i++) {
-            var property = props[i];
-
-            // If the layer had one of these properties set *and* it is
-            // a scale property (is not a non-scale property), then we assume
-            // the user did intend to use scale-dependant display (useInRange).
-            if (this.options[property] &&
-                OpenLayers.Util.indexOf(notScaleProps, property) == -1) {
-                useInRange = true;
+        // get resolution data from layer config
+        // (we also set alwaysInRange in the layer as appropriate)
+        for(i=0, len=this.RESOLUTION_PROPERTIES.length; i<len; i++) {
+            var p = this.RESOLUTION_PROPERTIES[i];
+            props[p] = this.options[p];
+            if(alwaysInRange && this.options[p]) {
+                alwaysInRange = false;
             }
+        }
+        if(this.alwaysInRange == null) {
+            this.alwaysInRange = alwaysInRange;
+        }
 
-            confProps[property] = this.options[property] || this.map[property];
+        // if we don't have resolutions then attempt to derive them from scales
+        if(props.resolutions == null) {
+            props.resolutions = this.resolutionsFromScales(props.scales);
         }
 
-        //only automatically set 'alwaysInRange' if the user hasn't already
-        // set it (to true or false, since the default is null). If user did
-        // not intend to use scale-dependant display then we set they layer
-        // as alwaysInRange. This means calculateInRange() will always return
-        // true and the layer will never be turned off due to scale changes.
-        //
-        if (this.alwaysInRange == null) {
-            this.alwaysInRange = !useInRange;
+        // if we still don't have resolutions then attempt to calculate them
+        if(props.resolutions == null) {
+            props.resolutions = this.calculateResolutions(props);
         }
 
-        // Do not use the scales array set at the map level if
-        // either minScale or maxScale or both are set at the
-        // layer level
-        if ((this.options.minScale != null ||
-             this.options.maxScale != null) &&
-            this.options.scales == null) {
-
-            confProps.scales = null;
+        // if we couldn't calculate resolutions then we look at we have
+        // in the map
+        if(props.resolutions == null) {
+            for(i=0, len=this.RESOLUTION_PROPERTIES.length; i<len; i++) {
+                var p = this.RESOLUTION_PROPERTIES[i];
+                props[p] = this.options[p] != null ?
+                    this.options[p] : this.map[p];
+            }
+            if(props.resolutions == null) {
+                props.resolutions = this.resolutionsFromScales(props.scales);
+            }
+            if(props.resolutions == null) {
+                props.resolutions = this.calculateResolutions(props);
+            }
         }
-        // Do not use the resolutions array set at the map level if
-        // either minResolution or maxResolution or both are set at the
-        // layer level
-        if ((this.options.minResolution != null ||
-             this.options.maxResolution != null) &&
-            this.options.resolutions == null) {
 
-            confProps.resolutions = null;
+        // ok, we new need to set properties in the instance
+
+        // get maxResolution from the config if it's defined there
+        var maxResolution;
+        if(this.options.maxResolution &&
+           this.options.maxResolution !== "auto") {
+            maxResolution = this.options.maxResolution;
         }
+        if(this.options.minScale) {
+            maxResolution = OpenLayers.Util.getResolutionFromScale(
+                this.options.minScale, this.units);
+        }
 
-        // If numZoomLevels hasn't been set and the maxZoomLevel *has*,
-        //  then use maxZoomLevel to calculate numZoomLevels
-        //
-        if ( (!confProps.numZoomLevels) && (confProps.maxZoomLevel) ) {
-            confProps.numZoomLevels = confProps.maxZoomLevel + 1;
+        // get minResolution from the config if it's defined there
+        var minResolution;
+        if(this.options.minResolution &&
+           this.options.minResolution !== "auto") {
+            minResolution = this.options.minResolution;
         }
+        if(this.options.maxScale) {
+            minResolution = OpenLayers.Util.getResolutionFromScale(
+                this.options.maxScale, this.units);
+        }
 
-        // First off, we take whatever hodge-podge of values we have and
-        //  calculate/distill them down into a resolutions[] array
-        //
-        if ((confProps.scales != null) || (confProps.resolutions != null)) {
-          //preset levels
-            if (confProps.scales != null) {
-                confProps.resolutions = [];
-                for(var i=0, len=confProps.scales.length; i<len; i++) {
-                    var scale = confProps.scales[i];
-                    confProps.resolutions[i] =
-                       OpenLayers.Util.getResolutionFromScale(scale,
-                                                              confProps.units);
-                }
-            }
-            confProps.numZoomLevels = confProps.resolutions.length;
+        if(props.resolutions) {
 
-        } else {
-          //maxResolution and numZoomLevels based calculation
+            //sort resolutions array descendingly
+            props.resolutions.sort(function(a, b) {
+                return (b - a);
+            });
 
-            // determine maxResolution
-            if (confProps.minScale) {
-                confProps.maxResolution =
-                    OpenLayers.Util.getResolutionFromScale(confProps.minScale,
-                                                           confProps.units);
-            } else if (confProps.maxResolution == "auto") {
-                var viewSize = this.map.getSize();
-                var wRes = confProps.maxExtent.getWidth() / viewSize.w;
-                var hRes = confProps.maxExtent.getHeight()/ viewSize.h;
-                confProps.maxResolution = Math.max(wRes, hRes);
+            // if we still don't have a maxResolution get it from the
+            // resolutions array
+            if(!maxResolution) {
+                maxResolution = props.resolutions[0];
             }
 
-            // determine minResolution
-            if (confProps.maxScale != null) {
-                confProps.minResolution =
-                    OpenLayers.Util.getResolutionFromScale(confProps.maxScale,
-                                                           confProps.units);
-            } else if ( (confProps.minResolution == "auto") &&
-                        (confProps.minExtent != null) ) {
-                var viewSize = this.map.getSize();
-                var wRes = confProps.minExtent.getWidth() / viewSize.w;
-                var hRes = confProps.minExtent.getHeight()/ viewSize.h;
-                confProps.minResolution = Math.max(wRes, hRes);
+            // if we still don't have a minResolution get it from the
+            // resolutions array
+            if(!minResolution) {
+                var lastIdx = props.resolutions.length - 1;
+                minResolution = props.resolutions[lastIdx];
             }
+        }
 
-            // determine numZoomLevels if not already set on the layer
-            // this gives numZoomLevels assuming approximately base 2 scaling
-            if (confProps.minResolution != null &&
-                this.options.numZoomLevels == undefined) {
-                var ratio = confProps.maxResolution / confProps.minResolution;
-                confProps.numZoomLevels =
-                    Math.floor(Math.log(ratio) / Math.log(2)) + 1;
+        this.resolutions = props.resolutions;
+        if(this.resolutions) {
+            len = this.resolutions.length;
+            this.scales = new Array(len);
+            for(i=0; i<len; i++) {
+                this.scales[i] = OpenLayers.Util.getScaleFromResolution(
+                    this.resolutions[i], this.units);
             }
+            this.numZoomLevels = len;
+        }
+        this.minResolution = minResolution;
+        if(minResolution) {
+            this.maxScale = OpenLayers.Util.getScaleFromResolution(
+                minResolution, this.units);
+        }
+        this.maxResolution = maxResolution;
+        if(maxResolution) {
+            this.minScale = OpenLayers.Util.getScaleFromResolution(
+                maxResolution, this.units);
+        }
+    },
 
-            // now we have numZoomLevels and maxResolution,
-            //  we can populate the resolutions array
-            confProps.resolutions = new Array(confProps.numZoomLevels);
-            var base = 2;
-            if(typeof confProps.minResolution == "number" &&
-               confProps.numZoomLevels > 1) {
-                /**
-                 * If maxResolution and minResolution are set (or related
-                 * scale properties), we calculate the base for exponential
-                 * scaling that starts at maxResolution and ends at
-                 * minResolution in numZoomLevels steps.
-                 */
-                base = Math.pow(
-                    (confProps.maxResolution / confProps.minResolution),
-                    (1 / (confProps.numZoomLevels - 1))
-                );
-            }
-            for (var i=0; i < confProps.numZoomLevels; i++) {
-                var res = confProps.maxResolution / Math.pow(base, i);
-                confProps.resolutions[i] = res;
-            }
+    /**
+     * Method: resolutionsFromScales
+     * Derive resolutions from scales.
+     *
+     * Parameters:
+     * scales - {Array(Number)} Scales
+     *
+     * Returns
+     * {Array(Number)} Resolutions
+     */
+    resolutionsFromScales: function(scales) {
+        if(scales == null) {
+            return;
         }
+        var resolutions, i, len;
+        len = scales.length;
+        resolutions = new Array(len);
+        for(i=0; i<len; i++) {
+            resolutions[i] = OpenLayers.Util.getResolutionFromScale(
+                scales[i], this.units);
+        }
+        return resolutions;
+    },
 
-        //sort resolutions array ascendingly
-        //
-        confProps.resolutions.sort( function(a, b) { return(b-a); } );
+    /**
+     * Method: calculateResolutions
+     * Calculate resolutions based on the provided properties.
+     *
+     * Parameters:
+     * props - {Object} Properties
+     *
+     * Return:
+     * {Array({Number})} Array of resolutions.
+     */
+    calculateResolutions: function(props) {
 
-        // now set our newly calculated values back to the layer
-        //  Note: We specifically do *not* set them to layer.options, which we
-        //        will preserve as it was when we added this layer to the map.
-        //        this way cloned layers reset themselves to new map div
-        //        dimensions)
-        //
+        // determine maxResolution
+        var maxResolution = props.maxResolution;
+        if(props.minScale != null) {
+            maxResolution =
+                OpenLayers.Util.getResolutionFromScale(props.minScale,
+                                                       this.units);
+        } else if(maxResolution == "auto" && this.maxExtent != null) {
+            var viewSize = this.map.getSize();
+            var wRes = this.maxExtent.getWidth() / viewSize.w;
+            var hRes = this.maxExtent.getHeight() / viewSize.h;
+            maxResolution = Math.max(wRes, hRes);
+        }
 
-        this.resolutions = confProps.resolutions;
-        this.maxResolution = confProps.resolutions[0];
-        var lastIndex = confProps.resolutions.length - 1;
-        this.minResolution = confProps.resolutions[lastIndex];
+        // determine minResolution
+        var minResolution = props.minResolution;
+        if(props.maxScale != null) {
+            minResolution =
+                OpenLayers.Util.getResolutionFromScale(props.maxScale,
+                                                       this.units);
+        } else if(props.minResolution == "auto" && this.minExtent != null) {
+            var viewSize = this.map.getSize();
+            var wRes = this.minExtent.getWidth() / viewSize.w;
+            var hRes = this.minExtent.getHeight()/ viewSize.h;
+            minResolution = Math.max(wRes, hRes);
+        }
 
-        this.scales = [];
-        for(var i=0, len=confProps.resolutions.length; i<len; i++) {
-            this.scales[i] =
-               OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i],
-                                                      confProps.units);
+        // determine numZoomLevels
+        var maxZoomLevel = props.maxZoomLevel;
+        var numZoomLevels = props.numZoomLevels;
+        if(typeof minResolution === "number" &&
+           typeof maxResolution === "number" && numZoomLevels === undefined) {
+            var ratio = maxResolution / minResolution;
+            numZoomLevels = Math.floor(Math.log(ratio) / Math.log(2)) + 1;
+        } else if(numZoomLevels === undefined && maxZoomLevel != null) {
+            numZoomLevels = maxZoomLevel + 1;
         }
-        this.minScale = this.scales[0];
-        this.maxScale = this.scales[this.scales.length - 1];
 
-        this.numZoomLevels = confProps.numZoomLevels;
+        // are we able to calculate resolutions?
+        if(typeof numZoomLevels !== "number" || numZoomLevels <= 0 ||
+           (typeof maxResolution !== "number" &&
+                typeof minResolution !== "number")) {
+            return;
+        }
+
+        // now we have numZoomLevels and at least one of maxResolution
+        // or minResolution, we can populate the resolutions array
+
+        var resolutions = new Array(numZoomLevels);
+        var base = 2;
+        if(typeof minResolution == "number" &&
+           typeof maxResolution == "number") {
+            // if maxResolution and minResolution are set, we calculate
+            // the base for exponential scaling that starts at
+            // maxResolution and ends at minResolution in numZoomLevels
+            // steps.
+            base = Math.pow(
+                    (maxResolution / minResolution),
+                (1 / (numZoomLevels - 1))
+            );
+        }
+
+        var i;
+        if(typeof maxResolution === "number") {
+            for(i=0; i<numZoomLevels; i++) {
+                resolutions[i] = maxResolution / Math.pow(base, i);
+            }
+        } else {
+            for(i=0; i<numZoomLevels; i++) {
+                resolutions[numZoomLevels - 1 - i] =
+                    minResolution * Math.pow(base, i);
+            }
+        }
+
+        return resolutions;
     },
 
     /**
      * APIMethod: getResolution
-     *
+     * 
      * Returns:
      * {Float} The currently selected resolution of the map, taken from the
      *     resolutions array, indexed by current zoom level.
@@ -21198,11 +22688,11 @@
         return this.getResolutionForZoom(zoom);
     },
 
-    /**
+    /** 
      * APIMethod: getExtent
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
+     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
      *     bounds of the current viewPort.
      */
     getExtent: function() {
@@ -21214,18 +22704,18 @@
 
     /**
      * APIMethod: getZoomForExtent
-     *
+     * 
      * Parameters:
      * bounds - {<OpenLayers.Bounds>}
-     * closest - {Boolean} Find the zoom level that most closely fits the
-     *     specified bounds. Note that this may result in a zoom that does
+     * closest - {Boolean} Find the zoom level that most closely fits the 
+     *     specified bounds. Note that this may result in a zoom that does 
      *     not exactly contain the entire extent.
      *     Default is false.
      *
      * Returns:
-     * {Integer} The index of the zoomLevel (entry in the resolutions array)
-     *     for the passed-in extent. We do this by calculating the ideal
-     *     resolution for the given extent (based on the map size) and then
+     * {Integer} The index of the zoomLevel (entry in the resolutions array) 
+     *     for the passed-in extent. We do this by calculating the ideal 
+     *     resolution for the given extent (based on the map size) and then 
      *     calling getZoomForResolution(), passing along the 'closest'
      *     parameter.
      */
@@ -21236,12 +22726,12 @@
 
         return this.getZoomForResolution(idealResolution, closest);
     },
-
-    /**
+    
+    /** 
      * Method: getDataExtent
      * Calculates the max extent which includes all of the data for the layer.
      *     This function is to be implemented by subclasses.
-     *
+     * 
      * Returns:
      * {<OpenLayers.Bounds>}
      */
@@ -21251,10 +22741,10 @@
 
     /**
      * APIMethod: getResolutionForZoom
-     *
+     * 
      * Parameter:
      * zoom - {Float}
-     *
+     * 
      * Returns:
      * {Float} A suitable resolution for the specified zoom.
      */
@@ -21274,20 +22764,20 @@
 
     /**
      * APIMethod: getZoomForResolution
-     *
+     * 
      * Parameters:
      * resolution - {Float}
-     * closest - {Boolean} Find the zoom level that corresponds to the absolute
+     * closest - {Boolean} Find the zoom level that corresponds to the absolute 
      *     closest resolution, which may result in a zoom whose corresponding
      *     resolution is actually smaller than we would have desired (if this
      *     is being called from a getZoomForExtent() call, then this means that
-     *     the returned zoom index might not actually contain the entire
+     *     the returned zoom index might not actually contain the entire 
      *     extent specified... but it'll be close).
      *     Default is false.
-     *
+     * 
      * Returns:
-     * {Integer} The index of the zoomLevel (entry in the resolutions array)
-     *     that corresponds to the best fit resolution given the passed in
+     * {Integer} The index of the zoomLevel (entry in the resolutions array) 
+     *     that corresponds to the best fit resolution given the passed in 
      *     value and the 'closest' specification.
      */
     getZoomForResolution: function(resolution, closest) {
@@ -21319,7 +22809,7 @@
         } else {
             var diff;
             var minDiff = Number.POSITIVE_INFINITY;
-            for(var i=0, len=this.resolutions.length; i<len; i++) {
+            for(var i=0, len=this.resolutions.length; i<len; i++) {            
                 if (closest) {
                     diff = Math.abs(this.resolutions[i] - resolution);
                     if (diff > minDiff) {
@@ -21336,15 +22826,15 @@
         }
         return zoom;
     },
-
+    
     /**
      * APIMethod: getLonLatFromViewPortPx
-     *
+     * 
      * Parameters:
      * viewPortPx - {<OpenLayers.Pixel>}
      *
      * Returns:
-     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in
+     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in 
      *     view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
      */
     getLonLatFromViewPortPx: function (viewPortPx) {
@@ -21354,12 +22844,12 @@
             var center = this.map.getCenter();
             if (center) {
                 var res  = this.map.getResolution();
-
+        
                 var delta_x = viewPortPx.x - (size.w / 2);
                 var delta_y = viewPortPx.y - (size.h / 2);
-
+            
                 lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
-                                             center.lat - delta_y * res);
+                                             center.lat - delta_y * res); 
 
                 if (this.wrapDateLine) {
                     lonlat = lonlat.wrapDateLine(this.maxExtent);
@@ -21373,31 +22863,31 @@
      * APIMethod: getViewPortPxFromLonLat
      * Returns a pixel location given a map location.  This method will return
      *     fractional pixel values.
-     *
+     * 
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>}
      *
-     * Returns:
-     * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in
+     * Returns: 
+     * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in 
      *     <OpenLayers.LonLat>,translated into view port pixels.
      */
     getViewPortPxFromLonLat: function (lonlat) {
-        var px = null;
+        var px = null; 
         if (lonlat != null) {
             var resolution = this.map.getResolution();
             var extent = this.map.getExtent();
             px = new OpenLayers.Pixel(
                 (1/resolution * (lonlat.lon - extent.left)),
                 (1/resolution * (extent.top - lonlat.lat))
-            );
+            );    
         }
         return px;
     },
-
+    
     /**
      * APIMethod: setOpacity
      * Sets the opacity for the entire layer (all images)
-     *
+     * 
      * Parameter:
      * opacity - {Float}
      */
@@ -21406,28 +22896,34 @@
             this.opacity = opacity;
             for(var i=0, len=this.div.childNodes.length; i<len; ++i) {
                 var element = this.div.childNodes[i].firstChild;
-                OpenLayers.Util.modifyDOMElement(element, null, null, null,
+                OpenLayers.Util.modifyDOMElement(element, null, null, null, 
                                                  null, null, null, opacity);
             }
+            if (this.map != null) {
+                this.map.events.triggerEvent("changelayer", {
+                    layer: this,
+                    property: "opacity"
+                });
+            }
         }
     },
 
     /**
      * Method: getZIndex
-     *
-     * Returns:
+     * 
+     * Returns: 
      * {Integer} the z-index of this layer
-     */
+     */    
     getZIndex: function () {
         return this.div.style.zIndex;
     },
 
     /**
      * Method: setZIndex
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * zIndex - {Integer}
-     */
+     */    
     setZIndex: function (zIndex) {
         this.div.style.zIndex = zIndex;
     },
@@ -21435,18 +22931,18 @@
     /**
      * Method: adjustBounds
      * This function will take a bounds, and if wrapDateLine option is set
-     *     on the layer, it will return a bounds which is wrapped around the
-     *     world. We do not wrap for bounds which *cross* the
-     *     maxExtent.left/right, only bounds which are entirely to the left
+     *     on the layer, it will return a bounds which is wrapped around the 
+     *     world. We do not wrap for bounds which *cross* the 
+     *     maxExtent.left/right, only bounds which are entirely to the left 
      *     or entirely to the right.
-     *
+     * 
      * Parameters:
      * bounds - {<OpenLayers.Bounds>}
      */
     adjustBounds: function (bounds) {
 
         if (this.gutter) {
-            // Adjust the extent of a bounds in map units by the
+            // Adjust the extent of a bounds in map units by the 
             // layer's gutter in pixels.
             var mapGutter = this.gutter * this.map.getResolution();
             bounds = new OpenLayers.Bounds(bounds.left - mapGutter,
@@ -21457,11 +22953,11 @@
 
         if (this.wrapDateLine) {
             // wrap around the date line, within the limits of rounding error
-            var wrappingOptions = {
+            var wrappingOptions = { 
                 'rightTolerance':this.getResolution()
-            };
+            };    
             bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
-
+                              
         }
         return bounds;
     },
@@ -21472,8 +22968,9 @@
     OpenLayers/Marker/Box.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -21485,29 +22982,29 @@
  * Class: OpenLayers.Marker.Box
  *
  * Inherits from:
- *  - <OpenLayers.Marker>
+ *  - <OpenLayers.Marker> 
  */
 OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, {
 
-    /**
-     * Property: bounds
-     * {<OpenLayers.Bounds>}
+    /** 
+     * Property: bounds 
+     * {<OpenLayers.Bounds>} 
      */
     bounds: null,
 
-    /**
-     * Property: div
-     * {DOMElement}
+    /** 
+     * Property: div 
+     * {DOMElement} 
      */
     div: null,
-
-    /**
+    
+    /** 
      * Constructor: OpenLayers.Marker.Box
      *
      * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * borderColor - {String}
-     * borderWidth - {int}
+     * bounds - {<OpenLayers.Bounds>} 
+     * borderColor - {String} 
+     * borderWidth - {int} 
      */
     initialize: function(bounds, borderColor, borderWidth) {
         this.bounds = bounds;
@@ -21518,8 +23015,8 @@
     },
 
     /**
-     * Method: destroy
-     */
+     * Method: destroy 
+     */    
     destroy: function() {
 
         this.bounds = null;
@@ -21528,10 +23025,10 @@
         OpenLayers.Marker.prototype.destroy.apply(this, arguments);
     },
 
-    /**
+    /** 
      * Method: setBorder
      * Allow the user to change the box's color and border width
-     *
+     * 
      * Parameters:
      * color - {String} Default is "red"
      * width - {int} Default is 2
@@ -21545,26 +23042,26 @@
         }
         this.div.style.border = width + "px solid " + color;
     },
-
-    /**
+    
+    /** 
     * Method: draw
-    *
+    * 
     * Parameters:
-    * px - {<OpenLayers.Pixel>}
-    * sz - {<OpenLayers.Size>}
-    *
-    * Returns:
-    * {DOMElement} A new DOM Image with this marker´s icon set at the
+    * px - {<OpenLayers.Pixel>} 
+    * sz - {<OpenLayers.Size>} 
+    * 
+    * Returns: 
+    * {DOMElement} A new DOM Image with this marker´s icon set at the 
     *         location passed-in
     */
     draw: function(px, sz) {
         OpenLayers.Util.modifyDOMElement(this.div, null, px, sz);
         return this.div;
-    },
+    }, 
 
     /**
      * Method: onScreen
-     *
+     * 
      * Rreturn:
      * {Boolean} Whether or not the marker is currently visible on screen.
      */
@@ -21573,16 +23070,16 @@
         if (this.map) {
             var screenBounds = this.map.getExtent();
             onScreen = screenBounds.containsBounds(this.bounds, true, true);
-        }
+        }    
         return onScreen;
     },
-
+    
     /**
      * Method: display
      * Hide or show the icon
-     *
+     * 
      * Parameters:
-     * display - {Boolean}
+     * display - {Boolean} 
      */
     display: function(display) {
         this.div.style.display = (display) ? "" : "none";
@@ -21595,7 +23092,7 @@
     OpenLayers/Request/XMLHttpRequest.js
    ====================================================================== */
 
-// Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
+// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com)
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -21620,11 +23117,13 @@
 
     // Define on browser type
     var bGecko    = !!window.controllers,
-        bIE        = window.document.all && !window.opera;
+        bIE        = window.document.all && !window.opera,
+        bIE7    = bIE && window.navigator.userAgent.match(/MSIE ([\.0-9]+)/) && RegExp.$1 == 7;
 
     // Constructor
     function cXMLHttpRequest() {
-        this._object    = oXMLHttpRequest ? new oXMLHttpRequest : new window.ActiveXObject('Microsoft.XMLHTTP');
+        this._object    = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP");
+        this._listeners    = [];
     };
 
     // BUGFIX: Firefox with Firebug installed would break pages if not executed
@@ -21640,10 +23139,10 @@
 
     // Public Properties
     cXMLHttpRequest.prototype.readyState    = cXMLHttpRequest.UNSENT;
-    cXMLHttpRequest.prototype.responseText    = "";
+    cXMLHttpRequest.prototype.responseText    = '';
     cXMLHttpRequest.prototype.responseXML    = null;
     cXMLHttpRequest.prototype.status        = 0;
-    cXMLHttpRequest.prototype.statusText    = "";
+    cXMLHttpRequest.prototype.statusText    = '';
 
     // Instance-level Events Handlers
     cXMLHttpRequest.prototype.onreadystatechange    = null;
@@ -21656,24 +23155,50 @@
 
     // Public Methods
     cXMLHttpRequest.prototype.open    = function(sMethod, sUrl, bAsync, sUser, sPassword) {
+        // Delete headers, required when object is reused
+        delete this._headers;
 
+        // When bAsync parameter value is omitted, use true as default
+        if (arguments.length < 3)
+            bAsync    = true;
+
         // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
         this._async        = bAsync;
 
         // Set the onreadystatechange handler
         var oRequest    = this,
-            nState        = this.readyState;
+            nState        = this.readyState,
+            fOnUnload;
 
         // BUGFIX: IE - memory leak on page unload (inter-page leak)
-        if (bIE) {
-            var fOnUnload    = function() {
-                if (oRequest._object.readyState != cXMLHttpRequest.DONE)
+        if (bIE && bAsync) {
+            fOnUnload = function() {
+                if (nState != cXMLHttpRequest.DONE) {
                     fCleanTransport(oRequest);
+                    // Safe to abort here since onreadystatechange handler removed
+                    oRequest.abort();
+                }
             };
-            if (bAsync)
                 window.attachEvent("onunload", fOnUnload);
         }
 
+        // Add method sniffer
+        if (cXMLHttpRequest.onopen)
+            cXMLHttpRequest.onopen.apply(this, arguments);
+
+        if (arguments.length > 4)
+            this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+        else
+        if (arguments.length > 3)
+            this._object.open(sMethod, sUrl, bAsync, sUser);
+        else
+            this._object.open(sMethod, sUrl, bAsync);
+
+        if (!bGecko && !bIE) {
+            this.readyState    = cXMLHttpRequest.OPENED;
+            fReadyStateChange(this);
+        }
+
         this._object.onreadystatechange    = function() {
             if (bGecko && !bAsync)
                 return;
@@ -21684,7 +23209,7 @@
             //
             fSynchronizeValues(oRequest);
 
-            // BUGFIX: Firefox fires unneccesary DONE when aborting
+            // BUGFIX: Firefox fires unnecessary DONE when aborting
             if (oRequest._aborted) {
                 // Reset readyState to UNSENT
                 oRequest.readyState    = cXMLHttpRequest.UNSENT;
@@ -21707,7 +23232,14 @@
                     cXMLHttpRequest.call(oRequest);
 
                     // Re-send request
+                    if (sUser) {
+                         if (sPassword)
                     oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+                        else
+                            oRequest._object.open(sMethod, sUrl, bAsync, sUser);
+                    }
+                    else
+                        oRequest._object.open(sMethod, sUrl, bAsync);
                     oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
                     // Copy headers set
                     if (oRequest._headers)
@@ -21751,7 +23283,7 @@
                     };
                     oRequest._object.send(null);
 
-                    // Return now - wait untill re-sent request is finished
+                    // Return now - wait until re-sent request is finished
                     return;
                 };
 */
@@ -21765,19 +23297,6 @@
                 fReadyStateChange(oRequest);
 
             nState    = oRequest.readyState;
-        };
-
-        // Add method sniffer
-        if (cXMLHttpRequest.onopen)
-            cXMLHttpRequest.onopen.apply(this, arguments);
-
-        this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
-
-        // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
-        if (!bAsync && bGecko) {
-            this.readyState    = cXMLHttpRequest.OPENED;
-
-            fReadyStateChange(this);
         }
     };
     cXMLHttpRequest.prototype.send    = function(vData) {
@@ -21818,7 +23337,7 @@
         if (cXMLHttpRequest.onabort)
             cXMLHttpRequest.onabort.apply(this, arguments);
 
-        // BUGFIX: Gecko - unneccesary DONE when aborting
+        // BUGFIX: Gecko - unnecessary DONE when aborting
         if (this.readyState > cXMLHttpRequest.UNSENT)
             this._aborted    = true;
 
@@ -21841,34 +23360,86 @@
 
         return this._object.setRequestHeader(sName, sValue);
     };
+
+    // EventTarget interface implementation
+    cXMLHttpRequest.prototype.addEventListener    = function(sName, fHandler, bUseCapture) {
+        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
+            if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)
+                return;
+        // Add listener
+        this._listeners.push([sName, fHandler, bUseCapture]);
+    };
+
+    cXMLHttpRequest.prototype.removeEventListener    = function(sName, fHandler, bUseCapture) {
+        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
+            if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)
+                break;
+        // Remove listener
+        if (oListener)
+            this._listeners.splice(nIndex, 1);
+    };
+
+    cXMLHttpRequest.prototype.dispatchEvent    = function(oEvent) {
+        var oEventPseudo    = {
+            'type':            oEvent.type,
+            'target':        this,
+            'currentTarget':this,
+            'eventPhase':    2,
+            'bubbles':        oEvent.bubbles,
+            'cancelable':    oEvent.cancelable,
+            'timeStamp':    oEvent.timeStamp,
+            'stopPropagation':    function() {},    // There is no flow
+            'preventDefault':    function() {},    // There is no default action
+            'initEvent':        function() {}    // Original event object should be initialized
+        };
+
+        // Execute onreadystatechange
+        if (oEventPseudo.type == "readystatechange" && this.onreadystatechange)
+            (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);
+
+        // Execute listeners
+        for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
+            if (oListener[0] == oEventPseudo.type && !oListener[2])
+                (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);
+    };
+
+    //
     cXMLHttpRequest.prototype.toString    = function() {
         return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
     };
+
     cXMLHttpRequest.toString    = function() {
         return '[' + "XMLHttpRequest" + ']';
     };
 
     // Helper function
     function fReadyStateChange(oRequest) {
-        // Execute onreadystatechange
-        if (oRequest.onreadystatechange)
-            oRequest.onreadystatechange.apply(oRequest);
-
         // Sniffing code
         if (cXMLHttpRequest.onreadystatechange)
             cXMLHttpRequest.onreadystatechange.apply(oRequest);
+
+        // Fake event
+        oRequest.dispatchEvent({
+            'type':            "readystatechange",
+            'bubbles':        false,
+            'cancelable':    false,
+            'timeStamp':    new Date + 0
+        });
     };
 
     function fGetDocument(oRequest) {
-        var oDocument    = oRequest.responseXML;
+        var oDocument    = oRequest.responseXML,
+            sResponse    = oRequest.responseText;
         // Try parsing responseText
-        if (bIE && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
-            oDocument    = new ActiveXObject('Microsoft.XMLDOM');
-            oDocument.loadXML(oRequest.responseText);
+        if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
+            oDocument    = new window.ActiveXObject("Microsoft.XMLDOM");
+            oDocument.async                = false;
+            oDocument.validateOnParse    = false;
+            oDocument.loadXML(sResponse);
         }
         // Check if there is no error in document
         if (oDocument)
-            if ((bIE && oDocument.parseError != 0) || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror"))
+            if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror"))
                 return null;
         return oDocument;
     };
@@ -21883,9 +23454,6 @@
     function fCleanTransport(oRequest) {
         // BUGFIX: IE - memory leak (on-page leak)
         oRequest._object.onreadystatechange    = new window.Function;
-
-        // Delete private properties
-        delete oRequest._headers;
     };
 
     // Internet Explorer 5.0 (missing apply)
@@ -21912,8 +23480,9 @@
     OpenLayers/Ajax.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -21930,19 +23499,19 @@
  *  @uri url to do remote XML http get
  *  @param {String} 'get' format params (x=y&a=b...)
  *  @who object to handle callbacks for this request
- *  @complete  the function to be called on success
+ *  @complete  the function to be called on success 
  *  @failure  the function to be called on failure
- *
+ *  
  *   example usage from a caller:
- *
+ *  
  *     caps: function(request) {
- *      -blah-
+ *      -blah-  
  *     },
- *
+ *  
  *     OpenLayers.loadURL(url,params,this,caps);
  *
  * Notice the above example does not provide an error handler; a default empty
- * handler is provided which merely logs the error if a failure handler is not
+ * handler is provided which merely logs the error if a failure handler is not 
  * supplied
  *
  */
@@ -21956,8 +23525,8 @@
     OpenLayers.Console.userError(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText}));
 };
 
-/**
- * APIFunction: loadURL
+/** 
+ * APIFunction: OpenLayers.loadURL
  * Background load a document.  For more flexibility in using XMLHttpRequest,
  *     see the <OpenLayers.Request> methods.
  *
@@ -21970,7 +23539,7 @@
  * onComplete - {Function} Optional callback for success.  The callback
  *     will be called with this set to caller and will receive the request
  *     object as an argument.  Note that if you do not specify an onComplete
- *     function, <OpenLayers.nullHandler> will be called (which pops up a
+ *     function, <OpenLayers.nullHandler> will be called (which pops up a 
  *     user friendly error message dialog).
  * onFailure - {Function} Optional callback for failure.  In the event of
  *     a failure, the callback will be called with this set to caller and will
@@ -21984,26 +23553,26 @@
  */
 OpenLayers.loadURL = function(uri, params, caller,
                                   onComplete, onFailure) {
-
+    
     if(typeof params == 'string') {
         params = OpenLayers.Util.getParameters(params);
     }
     var success = (onComplete) ? onComplete : OpenLayers.nullHandler;
     var failure = (onFailure) ? onFailure : OpenLayers.nullHandler;
-
+    
     return OpenLayers.Request.GET({
         url: uri, params: params,
         success: success, failure: failure, scope: caller
     });
 };
 
-/**
- * Function: parseXMLString
+/** 
+ * Function: OpenLayers.parseXMLString
  * Parse XML into a doc structure
- *
+ * 
  * Parameters:
- * text - {String}
- *
+ * text - {String} 
+ * 
  * Returns:
  * {?} Parsed AJAX Responsev
  */
@@ -22052,8 +23621,8 @@
 
     /**
      * Method: getTransport
-     *
-     * Returns:
+     * 
+     * Returns: 
      * {Object} Transport mechanism for whichever browser we're in, or false if
      *          none available.
      */
@@ -22077,7 +23646,7 @@
  * {Object}
  */
 OpenLayers.Ajax.Responders = {
-
+  
     /**
      * Property: responders
      * {Array}
@@ -22086,7 +23655,7 @@
 
     /**
      * Method: register
-     *
+     *  
      * Parameters:
      * responderToAdd - {?}
      */
@@ -22101,7 +23670,7 @@
 
     /**
      * Method: unregister
-     *
+     *  
      * Parameters:
      * responderToRemove - {?}
      */
@@ -22111,7 +23680,7 @@
 
     /**
      * Method: dispatch
-     *
+     * 
      * Parameters:
      * callback - {?}
      * request - {?}
@@ -22121,11 +23690,11 @@
         var responder;
         for (var i = 0; i < this.responders.length; i++) {
             responder = this.responders[i];
-
-            if (responder[callback] &&
+     
+            if (responder[callback] && 
                 typeof responder[callback] == 'function') {
                 try {
-                    responder[callback].apply(responder,
+                    responder[callback].apply(responder, 
                                               [request, transport]);
                 } catch (e) {}
             }
@@ -22134,7 +23703,7 @@
 };
 
 OpenLayers.Ajax.Responders.register({
-    /**
+    /** 
      * Function: onCreate
      */
     onCreate: function() {
@@ -22153,11 +23722,11 @@
  * Class: OpenLayers.Ajax.Base
  */
 OpenLayers.Ajax.Base = OpenLayers.Class({
-
+      
     /**
      * Constructor: OpenLayers.Ajax.Base
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * options - {Object}
      */
     initialize: function(options) {
@@ -22168,11 +23737,11 @@
             parameters:   ''
         };
         OpenLayers.Util.extend(this.options, options || {});
-
+        
         this.options.method = this.options.method.toLowerCase();
-
+        
         if (typeof this.options.parameters == 'string') {
-            this.options.parameters =
+            this.options.parameters = 
                 OpenLayers.Util.getParameters(this.options.parameters);
         }
     }
@@ -22193,28 +23762,28 @@
      * {Boolean}
      */
     _complete: false,
-
+      
     /**
      * Constructor: OpenLayers.Ajax.Request
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * url - {String}
      * options - {Object}
      */
     initialize: function(url, options) {
         OpenLayers.Ajax.Base.prototype.initialize.apply(this, [options]);
-
+        
         if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(url, "http")) {
             url = OpenLayers.ProxyHost + encodeURIComponent(url);
         }
-
+        
         this.transport = OpenLayers.Ajax.getTransport();
         this.request(url);
     },
 
     /**
      * Method: request
-     *
+     * 
      * Parameters:
      * url - {String}
      */
@@ -22222,15 +23791,15 @@
         this.url = url;
         this.method = this.options.method;
         var params = OpenLayers.Util.extend({}, this.options.parameters);
-
+        
         if (this.method != 'get' && this.method != 'post') {
             // simulate other verbs over post
             params['_method'] = this.method;
             this.method = 'post';
         }
 
-        this.parameters = params;
-
+        this.parameters = params;        
+        
         if (params = OpenLayers.Util.getParameterString(params)) {
             // when GET, append parameters to URL
             if (this.method == 'get') {
@@ -22244,31 +23813,31 @@
             if (this.options.onCreate) {
                 this.options.onCreate(response);
             }
-
-            OpenLayers.Ajax.Responders.dispatch('onCreate',
-                                                this,
+            
+            OpenLayers.Ajax.Responders.dispatch('onCreate', 
+                                                this, 
                                                 response);
-
-            this.transport.open(this.method.toUpperCase(),
+    
+            this.transport.open(this.method.toUpperCase(), 
                                 this.url,
                                 this.options.asynchronous);
-
+    
             if (this.options.asynchronous) {
                 window.setTimeout(
                     OpenLayers.Function.bind(this.respondToReadyState, this, 1),
                     10);
             }
-
-            this.transport.onreadystatechange =
-                OpenLayers.Function.bind(this.onStateChange, this);
+            
+            this.transport.onreadystatechange = 
+                OpenLayers.Function.bind(this.onStateChange, this);    
             this.setRequestHeaders();
-
+    
             this.body =  this.method == 'post' ?
                 (this.options.postBody || params) : null;
             this.transport.send(this.body);
-
+    
             // Force Firefox to handle ready state 4 for synchronous requests
-            if (!this.options.asynchronous &&
+            if (!this.options.asynchronous && 
                 this.transport.overrideMimeType) {
                 this.onStateChange();
             }
@@ -22286,7 +23855,7 @@
             this.respondToReadyState(this.transport.readyState);
         }
     },
-
+     
     /**
      * Method: setRequestHeaders
      */
@@ -22300,7 +23869,7 @@
         if (this.method == 'post') {
             headers['Content-type'] = this.options.contentType +
                 (this.options.encoding ? '; charset=' + this.options.encoding : '');
-
+    
             /* Force "Connection: close" for older Mozilla browsers to work
              * around a bug where XMLHttpRequest sends an incorrect
              * Content-length header. See Mozilla Bugzilla #246651.
@@ -22311,9 +23880,9 @@
             }
         }
         // user-defined headers
-        if (typeof this.options.requestHeaders == 'object') {
+        if (typeof this.options.requestHeaders == 'object') {    
             var extras = this.options.requestHeaders;
-
+            
             if (typeof extras.push == 'function') {
                 for (var i = 0, length = extras.length; i < length; i += 2) {
                     headers[extras[i]] = extras[i+1];
@@ -22324,23 +23893,23 @@
                 }
             }
         }
-
+        
         for (var name in headers) {
             this.transport.setRequestHeader(name, headers[name]);
         }
     },
-
+    
     /**
      * Method: success
      *
      * Returns:
-     * {Boolean} -
+     * {Boolean} - 
      */
     success: function() {
         var status = this.getStatus();
         return !status || (status >=200 && status < 300);
     },
-
+    
     /**
      * Method: getStatus
      *
@@ -22364,7 +23933,7 @@
     respondToReadyState: function(readyState) {
         var state = OpenLayers.Ajax.Request.Events[readyState];
         var response = new OpenLayers.Ajax.Response(this);
-
+    
         if (state == 'Complete') {
             try {
                 this._complete = true;
@@ -22374,29 +23943,29 @@
             } catch (e) {
                 this.dispatchException(e);
             }
-
+    
             var contentType = response.getHeader('Content-type');
         }
-
+    
         try {
-            (this.options['on' + state] ||
+            (this.options['on' + state] || 
              OpenLayers.Ajax.emptyFunction)(response);
-             OpenLayers.Ajax.Responders.dispatch('on' + state,
-                                                 this,
+             OpenLayers.Ajax.Responders.dispatch('on' + state, 
+                                                 this, 
                                                  response);
         } catch (e) {
             this.dispatchException(e);
         }
-
+    
         if (state == 'Complete') {
             // avoid memory leak in MSIE: clean up
             this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
         }
     },
-
+    
     /**
      * Method: getHeader
-     *
+     * 
      * Parameters:
      * name - {String} Header name
      *
@@ -22416,7 +23985,7 @@
      * If the optional onException function is set, execute it
      * and then dispatch the call to any other listener registered
      * for onException.
-     *
+     * 
      * If no optional onException function is set, we suspect that
      * the user may have also not used
      * OpenLayers.Ajax.Responders.register to register a listener
@@ -22428,7 +23997,7 @@
      * request.options.onException to an empty function (function(){})
      * or register an empty function with <OpenLayers.Ajax.Responders>
      * for onException.
-     *
+     * 
      * Parameters:
      * exception - {?}
      */
@@ -22459,7 +24028,7 @@
     }
 });
 
-/**
+/** 
  * Property: Events
  * {Array(String)}
  */
@@ -22477,26 +24046,26 @@
      * {Integer}
      */
     status: 0,
+    
 
-
     /**
      * Property: statusText
      *
      * {String}
      */
     statusText: '',
-
+      
     /**
      * Constructor: OpenLayers.Ajax.Response
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * request - {Object}
      */
     initialize: function(request) {
         this.request = request;
         var transport = this.transport = request.transport,
             readyState = this.readyState = transport.readyState;
-
+        
         if ((readyState > 2 &&
             !(!!(window.attachEvent && !window.opera))) ||
             readyState == 4) {
@@ -22505,18 +24074,18 @@
             this.responseText = transport.responseText == null ?
                 '' : String(transport.responseText);
         }
-
+        
         if(readyState == 4) {
             var xml = transport.responseXML;
             this.responseXML  = xml === undefined ? null : xml;
         }
     },
-
+    
     /**
      * Method: getStatus
      */
     getStatus: OpenLayers.Ajax.Request.prototype.getStatus,
-
+    
     /**
      * Method: getStatustext
      *
@@ -22530,13 +24099,13 @@
             return '';
         }
     },
-
+    
     /**
      * Method: getHeader
      */
     getHeader: OpenLayers.Ajax.Request.prototype.getHeader,
-
-    /**
+    
+    /** 
      * Method: getResponseHeader
      *
      * Returns:
@@ -22550,17 +24119,17 @@
 
 /**
  * Function: getElementsByTagNameNS
- *
+ * 
  * Parameters:
  * parentnode - {?}
  * nsuri - {?}
  * nsprefix - {?}
  * tagname - {?}
- *
+ * 
  * Returns:
  * {?}
  */
-OpenLayers.Ajax.getElementsByTagNameNS  = function(parentnode, nsuri,
+OpenLayers.Ajax.getElementsByTagNameNS  = function(parentnode, nsuri, 
                                                    nsprefix, tagname) {
     var elem = null;
     if (parentnode.getElementsByTagNameNS) {
@@ -22578,9 +24147,9 @@
  *     IE/Safari. We need to come up with a way to serialize in those browser:
  *     for now, these browsers will just fail. #535, #536
  *
- * Parameters:
+ * Parameters: 
  * xmldom {XMLNode} xml dom to serialize
- *
+ * 
  * Returns:
  * {?}
  */
@@ -22593,8 +24162,9 @@
     OpenLayers/Control/DragPan.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -22611,18 +24181,18 @@
  */
 OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {
 
-    /**
+    /** 
      * Property: type
      * {OpenLayers.Control.TYPES}
      */
     type: OpenLayers.Control.TYPE_TOOL,
-
+    
     /**
      * Property: panned
      * {Boolean} The map moved.
      */
     panned: false,
-
+    
     /**
      * Property: interval
      * {Integer} The number of milliseconds that should ellapse before
@@ -22630,18 +24200,26 @@
      *     Defaults to 25 milliseconds.
      */
     interval: 25,
-
+    
     /**
+     * APIProperty: documentDrag
+     * {Boolean} If set to true, mouse dragging will continue even if the
+     *     mouse cursor leaves the map viewport. Default is false.
+     */
+    documentDrag: false,
+    
+    /**
      * Method: draw
      * Creates a Drag handler, using <panMap> and
      * <panMapDone> as callbacks.
-     */
+     */    
     draw: function() {
         this.handler = new OpenLayers.Handler.Drag(this, {
                 "move": this.panMap,
                 "done": this.panMapDone
             }, {
-                interval: this.interval
+                interval: this.interval,
+                documentDrag: this.documentDrag
             }
         );
     },
@@ -22660,7 +24238,7 @@
             {dragging: this.handler.dragging, animate: false}
         );
     },
-
+    
     /**
      * Method: panMapDone
      * Finish the panning operation.  Only call setCenter (through <panMap>)
@@ -22682,8 +24260,9 @@
     OpenLayers/Feature/Vector.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 // TRASH THIS
@@ -22704,30 +24283,30 @@
  * Class: OpenLayers.Feature.Vector
  * Vector features use the OpenLayers.Geometry classes as geometry description.
  * They have an 'attributes' property, which is the data object, and a 'style'
- * property, the default values of which are defined in the
+ * property, the default values of which are defined in the 
  * <OpenLayers.Feature.Vector.style> objects.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Feature>
  */
 OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {
 
-    /**
-     * Property: fid
-     * {String}
+    /** 
+     * Property: fid 
+     * {String} 
      */
     fid: null,
-
-    /**
-     * APIProperty: geometry
-     * {<OpenLayers.Geometry>}
+    
+    /** 
+     * APIProperty: geometry 
+     * {<OpenLayers.Geometry>} 
      */
     geometry: null,
 
-    /**
-     * APIProperty: attributes
-     * {Object} This object holds arbitrary properties that describe the
-     *     feature.
+    /** 
+     * APIProperty: attributes 
+     * {Object} This object holds arbitrary, serializable properties that
+     *     describe the feature.
      */
     attributes: null,
 
@@ -22736,37 +24315,44 @@
      * {<OpenLayers.Bounds>} The box bounding that feature's geometry, that
      *     property can be set by an <OpenLayers.Format> object when
      *     deserializing the feature, so in most cases it represents an
-     *     information set by the server.
+     *     information set by the server. 
      */
     bounds: null,
 
-    /**
-     * Property: state
-     * {String}
+    /** 
+     * Property: state 
+     * {String} 
      */
     state: null,
-
-    /**
-     * APIProperty: style
-     * {Object}
+    
+    /** 
+     * APIProperty: style 
+     * {Object} 
      */
     style: null,
 
     /**
+     * APIProperty: url
+     * {String} If this property is set it will be taken into account by
+     *     {<OpenLayers.HTTP>} when upadting or deleting the feature.
+     */
+    url: null,
+    
+    /**
      * Property: renderIntent
      * {String} rendering intent currently being used
      */
     renderIntent: "default",
 
-    /**
+    /** 
      * Constructor: OpenLayers.Feature.Vector
-     * Create a vector feature.
-     *
+     * Create a vector feature. 
+     * 
      * Parameters:
      * geometry - {<OpenLayers.Geometry>} The geometry that this feature
      *     represents.
      * attributes - {Object} An optional object that will be mapped to the
-     *     <attributes> property.
+     *     <attributes> property. 
      * style - {Object} An optional style object.
      */
     initialize: function(geometry, attributes, style) {
@@ -22780,10 +24366,10 @@
             this.attributes = OpenLayers.Util.extend(this.attributes,
                                                      attributes);
         }
-        this.style = style ? style : null;
+        this.style = style ? style : null; 
     },
-
-    /**
+    
+    /** 
      * Method: destroy
      * nullify references to prevent circular references and memory leaks
      */
@@ -22792,11 +24378,11 @@
             this.layer.removeFeatures(this);
             this.layer = null;
         }
-
+            
         this.geometry = null;
         OpenLayers.Feature.prototype.destroy.apply(this, arguments);
     },
-
+    
     /**
      * Method: clone
      * Create a clone of this vector feature.  Does not set any non-standard
@@ -22824,7 +24410,7 @@
      * boundsOnly - {Boolean} Only test whether a feature's bounds intersects
      *     the viewport bounds.  Default is false.  If false, the feature's
      *     geometry must intersect the viewport for onScreen to return true.
-     *
+     * 
      * Returns:
      * {Boolean} The feature is currently visible on screen (optionally
      *     based on its bounds if boundsOnly is true).
@@ -22840,15 +24426,36 @@
                 var screenPoly = screenBounds.toGeometry();
                 onScreen = screenPoly.intersects(this.geometry);
             }
-        }
+        }    
         return onScreen;
     },
 
     /**
+     * Method: getVisibility
+     * Determine whether the feature is displayed or not. It may not displayed
+     *     because:
+     *     - its style display property is set to 'none',
+     *     - it doesn't belong to any layer,
+     *     - the styleMap creates a symbolizer with display property set to 'none'
+     *          for it,
+     *     - the layer which it belongs to is not visible.
+     * 
+     * Returns:
+     * {Boolean} The feature is currently displayed.
+     */
+    getVisibility: function() {
+        return !(this.style && this.style.display == 'none' ||
+                 !this.layer ||
+                 this.layer && this.layer.styleMap &&
+                 this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' ||
+                 this.layer && !this.layer.getVisibility());
+    },
+    
+    /**
      * Method: createMarker
      * HACK - we need to decide if all vector features should be able to
      *     create markers
-     *
+     * 
      * Returns:
      * {<OpenLayers.Marker>} For now just returns null
      */
@@ -22860,7 +24467,7 @@
      * Method: destroyMarker
      * HACK - we need to decide if all vector features should be able to
      *     delete markers
-     *
+     * 
      * If user overrides the createMarker() function, s/he should be able
      *   to also specify an alternative function for destroying it
      */
@@ -22872,7 +24479,7 @@
      * Method: createPopup
      * HACK - we need to decide if all vector features should be able to
      *     create popups
-     *
+     * 
      * Returns:
      * {<OpenLayers.Popup>} For now just returns null
      */
@@ -22883,19 +24490,19 @@
     /**
      * Method: atPoint
      * Determins whether the feature intersects with the specified location.
-     *
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
+     * 
+     * Parameters: 
+     * lonlat - {<OpenLayers.LonLat>} 
      * toleranceLon - {float} Optional tolerance in Geometric Coords
      * toleranceLat - {float} Optional tolerance in Geographic Coords
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the feature is at the specified location
      */
     atPoint: function(lonlat, toleranceLon, toleranceLat) {
         var atPoint = false;
         if(this.geometry) {
-            atPoint = this.geometry.atPoint(lonlat, toleranceLon,
+            atPoint = this.geometry.atPoint(lonlat, toleranceLon, 
                                                     toleranceLat);
         }
         return atPoint;
@@ -22931,7 +24538,7 @@
         } else {
             pixel = location;
         }
-
+        
         var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());
         var res = this.layer.map.getResolution();
         this.geometry.move(res * (pixel.x - lastPixel.x),
@@ -22939,13 +24546,13 @@
         this.layer.drawFeature(this);
         return lastPixel;
     },
-
+    
     /**
      * Method: toState
      * Sets the new state
      *
      * Parameters:
-     * state - {String}
+     * state - {String} 
      */
     toState: function(state) {
         if (state == OpenLayers.State.UPDATE) {
@@ -22982,24 +24589,24 @@
             this.state = state;
         }
     },
-
+    
     CLASS_NAME: "OpenLayers.Feature.Vector"
 });
 
 
 /**
  * Constant: OpenLayers.Feature.Vector.style
- * OpenLayers features can have a number of style attributes. The 'default'
+ * OpenLayers features can have a number of style attributes. The 'default' 
  *     style will typically be used if no other style is specified. These
  *     styles correspond for the most part, to the styling properties defined
- *     by the SVG standard.
+ *     by the SVG standard. 
  *     Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties
  *     Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties
  *
  * Symbolizer properties:
  * fill - {Boolean} Set to false if no fill is desired.
  * fillColor - {String} Hex fill color.  Default is "#ee9900".
- * fillOpacity - {Number} Fill opacity (0-1).  Default is 0.4
+ * fillOpacity - {Number} Fill opacity (0-1).  Default is 0.4 
  * stroke - {Boolean} Set to false if no stroke is desired.
  * strokeColor - {String} Hex stroke color.  Default is "#ee9900".
  * strokeOpacity - {Number} Stroke opacity (0-1).  Default is 1.
@@ -23016,6 +24623,7 @@
  * graphicOpacity - {Number} Opacity (0-1) for an external graphic.
  * graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic.
  * graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic.
+ * rotation - {Number} For point symbolizers, this is the rotation of a graphic in the clockwise direction about its center point (or any point off center as specified by graphicXOffset and graphicYOffset).
  * graphicZIndex - {Number} The integer z-index value to use in rendering.
  * graphicName - {String} Named graphic to use when rendering points.  Supported values include "circle" (default),
  *     "square", "star", "x", "cross", "triangle".
@@ -23033,16 +24641,21 @@
  *     alignment. Valid values for horizontal alignment: "l"=left, "c"=center, "r"=right. Valid values for vertical
  *     alignment: "t"=top, "m"=middle, "b"=bottom. Example values: "lt", "cm", "rb". The canvas renderer does not
  *     support vertical alignment, it will always use "b".
+ * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label.
+ * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label.
+ * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.
+ *     Default is false.
  * fontColor - {String} The font color for the label, to be provided like CSS.
+ * fontOpacity - {Number} Opacity (0-1) for the label
  * fontFamily - {String} The font family for the label, to be provided like in CSS.
  * fontSize - {String} The font size for the label, to be provided like in CSS.
  * fontWeight - {String} The font weight for the label, to be provided like in CSS.
  * display - {String} Symbolizers will have no effect if display is set to "none".  All other values have no effect.
- */
+ */ 
 OpenLayers.Feature.Vector.style = {
     'default': {
         fillColor: "#ee9900",
-        fillOpacity: 0.4,
+        fillOpacity: 0.4, 
         hoverFillColor: "white",
         hoverFillOpacity: 0.8,
         strokeColor: "#ee9900",
@@ -23061,7 +24674,7 @@
     },
     'select': {
         fillColor: "blue",
-        fillOpacity: 0.4,
+        fillOpacity: 0.4, 
         hoverFillColor: "white",
         hoverFillOpacity: 0.8,
         strokeColor: "blue",
@@ -23080,7 +24693,7 @@
     },
     'temporary': {
         fillColor: "#66cccc",
-        fillOpacity: 0.2,
+        fillOpacity: 0.2, 
         hoverFillColor: "white",
         hoverFillOpacity: 0.8,
         strokeColor: "#66cccc",
@@ -23100,13 +24713,14 @@
     'delete': {
         display: "none"
     }
-};
+};    
 /* ======================================================================
     OpenLayers/Handler/Box.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -23116,17 +24730,17 @@
 
 /**
  * Class: OpenLayers.Handler.Box
- * Handler for dragging a rectangle across the map.  Box is displayed
+ * Handler for dragging a rectangle across the map.  Box is displayed 
  * on mouse down, moves on mouse move, and is finished on mouse up.
  *
  * Inherits from:
- *  - <OpenLayers.Handler>
+ *  - <OpenLayers.Handler> 
  */
 OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
 
-    /**
-     * Property: dragHandler
-     * {<OpenLayers.Handler.Drag>}
+    /** 
+     * Property: dragHandler 
+     * {<OpenLayers.Handler.Drag>} 
      */
     dragHandler: null,
 
@@ -23136,7 +24750,7 @@
      *     olHandlerBoxZoomBox
      */
     boxDivClassName: 'olHandlerBoxZoomBox',
-
+    
     /**
      * Property: boxCharacteristics
      * {Object} Caches some box characteristics from css. This is used
@@ -23148,18 +24762,18 @@
      * Constructor: OpenLayers.Handler.Box
      *
      * Parameters:
-     * control - {<OpenLayers.Control>}
+     * control - {<OpenLayers.Control>} 
      * callbacks - {Object} An object containing a single function to be
      *                          called when the drag operation is finished.
      *                          The callback should expect to recieve a single
      *                          argument, the point geometry.
-     * options - {Object}
+     * options - {Object} 
      */
     initialize: function(control, callbacks, options) {
         OpenLayers.Handler.prototype.initialize.apply(this, arguments);
         var callbacks = {
-            "down": this.startBox,
-            "move": this.moveBox,
+            "down": this.startBox, 
+            "move": this.moveBox, 
             "out":  this.removeBox,
             "up":   this.endBox
         };
@@ -23168,6 +24782,17 @@
     },
 
     /**
+     * Method: destroy
+     */
+    destroy: function() {
+        if (this.dragHandler) {
+            this.dragHandler.destroy();
+            this.dragHandler = null;
+        }            
+        OpenLayers.Handler.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
      * Method: setMap
      */
     setMap: function (map) {
@@ -23181,12 +24806,12 @@
     * Method: startBox
     *
     * Parameters:
-    * evt - {Event}
+    * evt - {Event} 
     */
     startBox: function (xy) {
         this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
                                                  this.dragHandler.start);
-        this.zoomBox.className = this.boxDivClassName;
+        this.zoomBox.className = this.boxDivClassName;                                         
         this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
         this.map.viewPortDiv.appendChild(this.zoomBox);
 
@@ -23228,8 +24853,8 @@
     */
     endBox: function(end) {
         var result;
-        if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||
-            Math.abs(this.dragHandler.start.y - end.y) > 5) {
+        if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||    
+            Math.abs(this.dragHandler.start.y - end.y) > 5) {   
             var start = this.dragHandler.start;
             var top = Math.min(start.y, end.y);
             var bottom = Math.max(start.y, end.y);
@@ -23238,7 +24863,7 @@
             result = new OpenLayers.Bounds(left, bottom, right, top);
         } else {
             result = this.dragHandler.start.clone(); // i.e. OL.Pixel
-        }
+        } 
         this.removeBox();
 
         this.callback("done", [result]);
@@ -23281,11 +24906,11 @@
             return false;
         }
     },
-
+    
     /**
      * Method: getCharacteristics
      * Determines offset and box model for a box.
-     *
+     * 
      * Returns:
      * {Object} a hash with the following properties:
      *     - xOffset - Corner offset in x-direction
@@ -23318,8 +24943,9 @@
     OpenLayers/Handler/RegularPolygon.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -23333,12 +24959,12 @@
  *     down, moves or is modified on mouse move, and is finished on mouse up.
  *     The handler triggers callbacks for 'done' and 'cancel'.  Create a new
  *     instance with the <OpenLayers.Handler.RegularPolygon> constructor.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Handler>
  */
 OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, {
-
+    
     /**
      * APIProperty: sides
      * {Integer} Number of sides for the regular polygon.  Needs to be greater
@@ -23355,15 +24981,15 @@
      *     default.
      */
     radius: null,
-
+    
     /**
      * APIProperty: snapAngle
      * {Float} If set to a non-zero value, the handler will snap the polygon
      *     rotation to multiples of the snapAngle.  Value is an angle measured
-     *     in degrees counterclockwise from the positive x-axis.
+     *     in degrees counterclockwise from the positive x-axis.  
      */
     snapAngle: null,
-
+    
     /**
      * APIProperty: snapToggle
      * {String} If set, snapToggle is checked on mouse events and will set
@@ -23374,6 +25000,12 @@
      *     non-zero value.
      */
     snapToggle: 'shiftKey',
+    
+    /**
+     * Property: layerOptions
+     * {Object} Any optional properties to be set on the sketch layer.
+     */
+    layerOptions: null,
 
     /**
      * APIProperty: persist
@@ -23450,24 +25082,26 @@
      *     cancel callback will receive a geometry.
      */
     initialize: function(control, callbacks, options) {
-        this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
+        if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
+            this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
+        }
 
         OpenLayers.Handler.prototype.initialize.apply(this,
                                                 [control, callbacks, options]);
-        this.options = (options) ? options : new Object();
+        this.options = (options) ? options : {};
     },
-
+    
     /**
      * APIMethod: setOptions
-     *
+     * 
      * Parameters:
-     * newOptions - {Object}
+     * newOptions - {Object} 
      */
     setOptions: function (newOptions) {
         OpenLayers.Util.extend(this.options, newOptions);
         OpenLayers.Util.extend(this, newOptions);
     },
-
+    
     /**
      * APIMethod: activate
      * Turn on the handler.
@@ -23479,14 +25113,14 @@
         var activated = false;
         if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
             // create temporary vector layer for rendering geometry sketch
-            var options = {
+            var options = OpenLayers.Util.extend({
                 displayInLayerSwitcher: false,
                 // indicate that the temp vector layer will never be out of range
                 // without this, resolution properties must be specified at the
                 // map-level for this temporary layer to init its resolutions
                 // correctly
-                calculateInRange: function() { return true; }
-            };
+                calculateInRange: OpenLayers.Function.True
+            }, this.layerOptions);
             this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
             this.map.addLayer(this.layer);
             activated = true;
@@ -23525,7 +25159,7 @@
         }
         return deactivated;
     },
-
+    
     /**
      * Method: down
      * Start drawing a new feature
@@ -23552,7 +25186,7 @@
         this.layer.addFeatures([this.feature], {silent: true});
         this.layer.drawFeature(this.feature, this.style);
     },
-
+    
     /**
      * Method: move
      * Respond to drag move events
@@ -23632,13 +25266,13 @@
             this.origin, this.radius, this.sides, this.snapAngle
         );
     },
-
+    
     /**
      * Method: modifyGeometry
      * Modify the polygon geometry in place.
      */
     modifyGeometry: function() {
-        var angle, dx, dy, point;
+        var angle, point;
         var ring = this.feature.geometry.components[0];
         // if the number of sides ever changes, create a new geometry
         if(ring.components.length != (this.sides + 1)) {
@@ -23653,7 +25287,7 @@
             point.clearBounds();
         }
     },
-
+    
     /**
      * Method: calculateAngle
      * Calculate the angle based on settings.
@@ -23699,10 +25333,12 @@
      *     is true).
      */
     clear: function() {
-        this.layer.renderer.clear();
-        this.layer.destroyFeatures();
+        if (this.layer) {
+            this.layer.renderer.clear();
+            this.layer.destroyFeatures();
+        }
     },
-
+    
     /**
      * Method: callback
      * Trigger the control's named callback with the given arguments
@@ -23732,8 +25368,9 @@
     OpenLayers/Layer/EventPane.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -23746,21 +25383,21 @@
  * Class: OpenLayers.Layer.EventPane
  * Base class for 3rd party layers.  Create a new event pane layer with the
  * <OpenLayers.Layer.EventPane> constructor.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Layer>
  */
 OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, {
-
+    
     /**
      * APIProperty: smoothDragPan
      * {Boolean} smoothDragPan determines whether non-public/internal API
-     *     methods are used for better performance while dragging EventPane
-     *     layers. When not in sphericalMercator mode, the smoother dragging
-     *     doesn't actually move north/south directly with the number of
-     *     pixels moved, resulting in a slight offset when you drag your mouse
-     *     north south with this option on. If this visual disparity bothers
-     *     you, you should turn this option off, or use spherical mercator.
+     *     methods are used for better performance while dragging EventPane 
+     *     layers. When not in sphericalMercator mode, the smoother dragging 
+     *     doesn't actually move north/south directly with the number of 
+     *     pixels moved, resulting in a slight offset when you drag your mouse 
+     *     north south with this option on. If this visual disparity bothers 
+     *     you, you should turn this option off, or use spherical mercator. 
      *     Default is on.
      */
     smoothDragPan: true,
@@ -23768,13 +25405,13 @@
     /**
      * Property: isBaseLayer
      * {Boolean} EventPaned layers are always base layers, by necessity.
-     */
+     */ 
     isBaseLayer: true,
 
     /**
      * APIProperty: isFixed
      * {Boolean} EventPaned layers are fixed by default.
-     */
+     */ 
     isFixed: true,
 
     /**
@@ -23787,9 +25424,9 @@
     /**
      * Property: mapObject
      * {Object} This is the object which will be used to load the 3rd party library
-     * in the case of the google layer, this will be of type GMap,
+     * in the case of the google layer, this will be of type GMap, 
      * in the case of the ve layer, this will be of type VEMap
-     */
+     */ 
     mapObject: null,
 
 
@@ -23807,35 +25444,36 @@
             this.pane = OpenLayers.Util.createDiv(this.div.id + "_EventPane");
         }
     },
-
+    
     /**
      * APIMethod: destroy
      * Deconstruct this layer.
      */
     destroy: function() {
         this.mapObject = null;
-        OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+        this.pane = null;
+        OpenLayers.Layer.prototype.destroy.apply(this, arguments); 
     },
 
-
+    
     /**
      * Method: setMap
      * Set the map property for the layer. This is done through an accessor
-     * so that subclasses can override this and take special action once
-     * they have their map variable set.
+     * so that subclasses can override this and take special action once 
+     * they have their map variable set. 
      *
      * Parameters:
      * map - {<OpenLayers.Map>}
      */
     setMap: function(map) {
         OpenLayers.Layer.prototype.setMap.apply(this, arguments);
-
+        
         this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1;
         this.pane.style.display = this.div.style.display;
         this.pane.style.width="100%";
         this.pane.style.height="100%";
         if (OpenLayers.Util.getBrowserName() == "msie") {
-            this.pane.style.background =
+            this.pane.style.background = 
                 "url(" + OpenLayers.Util.getImagesLocation() + "blank.gif)";
         }
 
@@ -23847,7 +25485,7 @@
 
         // once our layer has been added to the map, we can load it
         this.loadMapObject();
-
+    
         // if map didn't load, display warning
         if (this.mapObject == null) {
             this.loadWarningMessage();
@@ -23857,26 +25495,25 @@
     /**
      * APIMethod: removeMap
      * On being removed from the map, we'll like to remove the invisible 'pane'
-     *     div that we added to it on creation.
-     *
+     *     div that we added to it on creation. 
+     * 
      * Parameters:
      * map - {<OpenLayers.Map>}
      */
     removeMap: function(map) {
         if (this.pane && this.pane.parentNode) {
             this.pane.parentNode.removeChild(this.pane);
-            this.pane = null;
         }
         OpenLayers.Layer.prototype.removeMap.apply(this, arguments);
     },
-
+  
     /**
      * Method: loadWarningMessage
-     * If we can't load the map lib, then display an error message to the
+     * If we can't load the map lib, then display an error message to the 
      *     user and tell them where to go for help.
-     *
+     * 
      *     This function sets up the layout for the warning message. Each 3rd
-     *     party layer must implement its own getWarningHTML() function to
+     *     party layer must implement its own getWarningHTML() function to 
      *     provide the actual warning message.
      */
     loadWarningMessage:function() {
@@ -23884,17 +25521,17 @@
         this.div.style.backgroundColor = "darkblue";
 
         var viewSize = this.map.getSize();
-
+        
         var msgW = Math.min(viewSize.w, 300);
         var msgH = Math.min(viewSize.h, 200);
         var size = new OpenLayers.Size(msgW, msgH);
 
         var centerPx = new OpenLayers.Pixel(viewSize.w/2, viewSize.h/2);
 
-        var topLeft = centerPx.add(-size.w/2, -size.h/2);
+        var topLeft = centerPx.add(-size.w/2, -size.h/2);            
 
-        var div = OpenLayers.Util.createDiv(this.name + "_warning",
-                                            topLeft,
+        var div = OpenLayers.Util.createDiv(this.name + "_warning", 
+                                            topLeft, 
                                             size,
                                             null,
                                             null,
@@ -23907,11 +25544,11 @@
         div.innerHTML = this.getWarningHTML();
         this.div.appendChild(div);
     },
-
-    /**
+  
+    /** 
      * Method: getWarningHTML
      * To be implemented by subclasses.
-     *
+     * 
      * Returns:
      * {String} String with information on why layer is broken, how to get
      *          it working.
@@ -23920,7 +25557,7 @@
         //should be implemented by subclasses
         return "";
     },
-
+  
     /**
      * Method: display
      * Set the display on the pane
@@ -23932,11 +25569,11 @@
         OpenLayers.Layer.prototype.display.apply(this, arguments);
         this.pane.style.display = this.div.style.display;
     },
-
+  
     /**
      * Method: setZIndex
      * Set the z-index order for the pane.
-     *
+     * 
      * Parameters:
      * zIndex - {int}
      */
@@ -23948,7 +25585,7 @@
     /**
      * Method: moveTo
      * Handle calls to move the layer.
-     *
+     * 
      * Parameters:
      * bounds - {<OpenLayers.Bounds>}
      * zoomChanged - {Boolean}
@@ -23970,10 +25607,10 @@
                 var moOldZoom = this.getMapObjectZoom();
                 var oldZoom= this.getOLZoomFromMapObjectZoom(moOldZoom);
 
-                if ( !(newCenter.equals(oldCenter)) ||
+                if ( !(newCenter.equals(oldCenter)) || 
                      !(newZoom == oldZoom) ) {
 
-                    if (dragging && this.dragPanMapObject &&
+                    if (dragging && this.dragPanMapObject && 
                         this.smoothDragPan) {
                         var oldPx = this.map.getViewPortPxFromLonLat(oldCenter);
                         var newPx = this.map.getViewPortPxFromLonLat(newCenter);
@@ -23998,7 +25635,7 @@
     /**
      * Method: getLonLatFromViewPortPx
      * Get a map location from a pixel location
-     *
+     * 
      * Parameters:
      * viewPortPx - {<OpenLayers.Pixel>}
      *
@@ -24009,7 +25646,7 @@
      */
     getLonLatFromViewPortPx: function (viewPortPx) {
         var lonlat = null;
-        if ( (this.mapObject != null) &&
+        if ( (this.mapObject != null) && 
              (this.getMapObjectCenter() != null) ) {
             var moPixel = this.getMapObjectPixelFromOLPixel(viewPortPx);
             var moLonLat = this.getMapObjectLonLatFromMapObjectPixel(moPixel);
@@ -24018,7 +25655,7 @@
         return lonlat;
     },
 
-
+ 
     /**
      * Method: getViewPortPxFromLonLat
      * Get a pixel location from a map location
@@ -24033,12 +25670,12 @@
      */
     getViewPortPxFromLonLat: function (lonlat) {
         var viewPortPx = null;
-        if ( (this.mapObject != null) &&
+        if ( (this.mapObject != null) && 
              (this.getMapObjectCenter() != null) ) {
 
             var moLonLat = this.getMapObjectLonLatFromOLLonLat(lonlat);
             var moPixel = this.getMapObjectPixelFromMapObjectLonLat(moLonLat);
-
+        
             viewPortPx = this.getOLPixelFromMapObjectPixel(moPixel);
         }
         return viewPortPx;
@@ -24063,9 +25700,9 @@
      *
      * Parameters
      * moLonLat - {Object}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.LonLat>} An OpenLayers.LonLat, translated from the passed in
+     * {<OpenLayers.LonLat>} An OpenLayers.LonLat, translated from the passed in 
      *          MapObject LonLat
      *          Returns null if null value is passed in
      */
@@ -24085,9 +25722,9 @@
      *
      * Parameters:
      * olLonLat - {<OpenLayers.LonLat>}
-     *
+     * 
      * Returns:
-     * {Object} A MapObject LonLat, translated from the passed in
+     * {Object} A MapObject LonLat, translated from the passed in 
      *          OpenLayers.LonLat
      *          Returns null if null value is passed in
      */
@@ -24111,9 +25748,9 @@
      *
      * Parameters:
      * moPixel - {Object}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Pixel>} An OpenLayers.Pixel, translated from the passed in
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel, translated from the passed in 
      *          MapObject Pixel
      *          Returns null if null value is passed in
      */
@@ -24133,9 +25770,9 @@
      *
      * Parameters:
      * olPixel - {<OpenLayers.Pixel>}
-     *
+     * 
      * Returns:
-     * {Object} A MapObject Pixel, translated from the passed in
+     * {Object} A MapObject Pixel, translated from the passed in 
      *          OpenLayers.Pixel
      *          Returns null if null value is passed in
      */
@@ -24153,8 +25790,9 @@
     OpenLayers/Layer/FixedZoomLevels.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -24163,47 +25801,47 @@
 
 /**
  * Class: OpenLayers.Layer.FixedZoomLevels
- *   Some Layers will already have established zoom levels (like google
+ *   Some Layers will already have established zoom levels (like google 
  *    or ve). Instead of trying to determine them and populate a resolutions[]
  *    Array with those values, we will hijack the resolution functionality
  *    here.
- *
- *   When you subclass FixedZoomLevels:
- *
- *   The initResolutions() call gets nullified, meaning no resolutions[] array
- *    is set up. Which would be a big problem getResolution() in Layer, since
+ * 
+ *   When you subclass FixedZoomLevels: 
+ * 
+ *   The initResolutions() call gets nullified, meaning no resolutions[] array 
+ *    is set up. Which would be a big problem getResolution() in Layer, since 
  *    it merely takes map.zoom and indexes into resolutions[]... but....
- *
- *   The getResolution() call is also overridden. Instead of using the
+ * 
+ *   The getResolution() call is also overridden. Instead of using the 
  *    resolutions[] array, we simply calculate the current resolution based
  *    on the current extent and the current map size. But how will we be able
  *    to calculate the current extent without knowing the resolution...?
- *
+ *  
  *   The getExtent() function is also overridden. Instead of calculating extent
- *    based on the center point and the current resolution, we instead
- *    calculate the extent by getting the lonlats at the top-left and
+ *    based on the center point and the current resolution, we instead 
+ *    calculate the extent by getting the lonlats at the top-left and 
  *    bottom-right by using the getLonLatFromViewPortPx() translation function,
- *    taken from the pixel locations (0,0) and the size of the map. But how
+ *    taken from the pixel locations (0,0) and the size of the map. But how 
  *    will we be able to do lonlat-px translation without resolution....?
- *
+ * 
  *   The getZoomForResolution() method is overridden. Instead of indexing into
  *    the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in
- *    the desired resolution. With this extent, we then call getZoomForExtent()
- *
- *
- *   Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels,
+ *    the desired resolution. With this extent, we then call getZoomForExtent() 
+ * 
+ * 
+ *   Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels, 
  *    it is your responsibility to provide the following three functions:
- *
+ * 
  *   - getLonLatFromViewPortPx
  *   - getViewPortPxFromLonLat
  *   - getZoomForExtent
- *
- *  ...those three functions should generally be provided by any reasonable
+ * 
+ *  ...those three functions should generally be provided by any reasonable 
  *  API that you might be working from.
  *
  */
 OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({
-
+      
   /********************************************************/
   /*                                                      */
   /*                 Baselayer Functions                  */
@@ -24212,19 +25850,19 @@
   /*                  by all base layers                  */
   /*                                                      */
   /********************************************************/
-
+    
     /**
      * Constructor: OpenLayers.Layer.FixedZoomLevels
      * Create a new fixed zoom levels layer.
      */
     initialize: function() {
-        //this class is only just to add the following functions...
+        //this class is only just to add the following functions... 
         // nothing to actually do here... but it is probably a good
-        // idea to have layers that use these functions call this
-        // inititalize() anyways, in case at some point we decide we
-        // do want to put some functionality or state in here.
+        // idea to have layers that use these functions call this 
+        // inititalize() anyways, in case at some point we decide we 
+        // do want to put some functionality or state in here. 
     },
-
+    
     /**
      * Method: initResolutions
      * Populate the resolutions array
@@ -24232,64 +25870,64 @@
     initResolutions: function() {
 
         var props = new Array('minZoomLevel', 'maxZoomLevel', 'numZoomLevels');
-
+          
         for(var i=0, len=props.length; i<len; i++) {
             var property = props[i];
-            this[property] = (this.options[property] != null)
-                                     ? this.options[property]
+            this[property] = (this.options[property] != null)  
+                                     ? this.options[property] 
                                      : this.map[property];
         }
 
         if ( (this.minZoomLevel == null) ||
              (this.minZoomLevel < this.MIN_ZOOM_LEVEL) ){
             this.minZoomLevel = this.MIN_ZOOM_LEVEL;
-        }
+        }        
 
         //
         // At this point, we know what the minimum desired zoom level is, and
-        //  we must calculate the total number of zoom levels.
-        //
+        //  we must calculate the total number of zoom levels. 
+        //  
         //  Because we allow for the setting of either the 'numZoomLevels'
-        //   or the 'maxZoomLevel' properties... on either the layer or the
+        //   or the 'maxZoomLevel' properties... on either the layer or the  
         //   map, we have to define some rules to see which we take into
-        //   account first in this calculation.
+        //   account first in this calculation. 
         //
         // The following is the precedence list for these properties:
-        //
+        // 
         // (1) numZoomLevels set on layer
         // (2) maxZoomLevel set on layer
         // (3) numZoomLevels set on map
         // (4) maxZoomLevel set on map*
         // (5) none of the above*
         //
-        // *Note that options (4) and (5) are only possible if the user
-        //  _explicitly_ sets the 'numZoomLevels' property on the map to
-        //  null, since it is set by default to 16.
+        // *Note that options (4) and (5) are only possible if the user 
+        //  _explicitly_ sets the 'numZoomLevels' property on the map to 
+        //  null, since it is set by default to 16. 
         //
 
         //
-        // Note to future: In 3.0, I think we should remove the default
-        // value of 16 for map.numZoomLevels. Rather, I think that value
+        // Note to future: In 3.0, I think we should remove the default 
+        // value of 16 for map.numZoomLevels. Rather, I think that value 
         // should be set as a default on the Layer.WMS class. If someone
-        // creates a 3rd party layer and does not specify any 'minZoomLevel',
-        // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly
+        // creates a 3rd party layer and does not specify any 'minZoomLevel', 
+        // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly 
         // specified any of those on the map object either.. then I think
         // it is fair to say that s/he wants all the zoom levels available.
-        //
-        // By making map.numZoomLevels *null* by default, that will be the
+        // 
+        // By making map.numZoomLevels *null* by default, that will be the 
         // case. As it is, I don't feel comfortable changing that right now
         // as it would be a glaring API change and actually would probably
-        // break many peoples' codes.
+        // break many peoples' codes. 
         //
 
         //the number of zoom levels we'd like to have.
         var desiredZoomLevels;
 
-        //this is the maximum number of zoom levels the layer will allow,
+        //this is the maximum number of zoom levels the layer will allow, 
         // given the specified starting minimum zoom level.
         var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1;
 
-        if ( ((this.options.numZoomLevels == null) &&
+        if ( ((this.options.numZoomLevels == null) && 
               (this.options.maxZoomLevel != null)) // (2)
               ||
              ((this.numZoomLevels == null) &&
@@ -24306,18 +25944,18 @@
         if (desiredZoomLevels != null) {
             //Now that we know what we would *like* the number of zoom levels
             // to be, based on layer or map options, we have to make sure that
-            // it does not conflict with the actual limit, as specified by
+            // it does not conflict with the actual limit, as specified by 
             // the constants on the layer itself (and calculated into the
-            // 'limitZoomLevels' variable).
+            // 'limitZoomLevels' variable). 
             this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels);
         } else {
-            // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was
-            // set on either the layer or the map. So we just use the
+            // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was 
+            // set on either the layer or the map. So we just use the 
             // maximum limit as calculated by the layer's constants.
             this.numZoomLevels = limitZoomLevels;
         }
 
-        //now that the 'numZoomLevels' is appropriately, safely set,
+        //now that the 'numZoomLevels' is appropriately, safely set, 
         // we go back and re-calculate the 'maxZoomLevel'.
         this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1;
 
@@ -24325,17 +25963,17 @@
             var resolutionsIndex = 0;
             this.resolutions = [];
             for(var i= this.minZoomLevel; i <= this.maxZoomLevel; i++) {
-                this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i];
+                this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i];            
             }
             this.maxResolution = this.resolutions[0];
             this.minResolution = this.resolutions[this.resolutions.length - 1];
-        }
+        }       
     },
-
+    
     /**
      * APIMethod: getResolution
      * Get the current map resolution
-     *
+     * 
      * Returns:
      * {Float} Map units per Pixel
      */
@@ -24345,10 +25983,10 @@
             return OpenLayers.Layer.prototype.getResolution.apply(this, arguments);
         } else {
             var resolution = null;
-
+            
             var viewSize = this.map.getSize();
             var extent = this.getExtent();
-
+            
             if ((viewSize != null) && (extent != null)) {
                 resolution = Math.max( extent.getWidth()  / viewSize.w,
                                        extent.getHeight() / viewSize.h );
@@ -24359,29 +25997,29 @@
 
     /**
      * APIMethod: getExtent
-     * Calculates using px-> lonlat translation functions on tl and br
+     * Calculates using px-> lonlat translation functions on tl and br 
      *     corners of viewport
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
+     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
      *                       bounds of the current viewPort.
      */
     getExtent: function () {
         var extent = null;
-
-
+        
+        
         var size = this.map.getSize();
-
+        
         var tlPx = new OpenLayers.Pixel(0,0);
         var tlLL = this.getLonLatFromViewPortPx(tlPx);
 
         var brPx = new OpenLayers.Pixel(size.w, size.h);
         var brLL = this.getLonLatFromViewPortPx(brPx);
-
+        
         if ((tlLL != null) && (brLL != null)) {
-            extent = new OpenLayers.Bounds(tlLL.lon,
-                                       brLL.lat,
-                                       brLL.lon,
+            extent = new OpenLayers.Bounds(tlLL.lon, 
+                                       brLL.lat, 
+                                       brLL.lon, 
                                        tlLL.lat);
         }
 
@@ -24400,7 +26038,7 @@
      *           If no baselayer is set, returns null.
      */
     getZoomForResolution: function(resolution) {
-
+      
         if (this.resolutions != null) {
             return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments);
         } else {
@@ -24411,28 +26049,28 @@
 
 
 
-
+    
     /********************************************************/
     /*                                                      */
     /*             Translation Functions                    */
     /*                                                      */
-    /*    The following functions translate GMaps and OL    */
+    /*    The following functions translate GMaps and OL    */ 
     /*     formats for Pixel, LonLat, Bounds, and Zoom      */
     /*                                                      */
     /********************************************************/
-
-
+    
+    
     //
     // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
     //
-
+  
     /**
      * Method: getOLZoomFromMapObjectZoom
      * Get the OL zoom index from the map object zoom level
      *
      * Parameters:
      * moZoom - {Integer}
-     *
+     * 
      * Returns:
      * {Integer} An OpenLayers Zoom level, translated from the passed in zoom
      *           Returns null if null value is passed in
@@ -24444,20 +26082,20 @@
         }
         return zoom;
     },
-
+    
     /**
      * Method: getMapObjectZoomFromOLZoom
      * Get the map object zoom level from the OL zoom level
      *
      * Parameters:
      * olZoom - {Integer}
-     *
+     * 
      * Returns:
      * {Integer} A MapObject level, translated from the passed in olZoom
      *           Returns null if null value is passed in
      */
     getMapObjectZoomFromOLZoom: function(olZoom) {
-        var zoom = null;
+        var zoom = null; 
         if (olZoom != null) {
             zoom = olZoom + this.minZoomLevel;
         }
@@ -24471,8 +26109,9 @@
     OpenLayers/Layer/HTTPRequest.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -24482,47 +26121,47 @@
 
 /**
  * Class: OpenLayers.Layer.HTTPRequest
- *
- * Inherits from:
+ * 
+ * Inherits from: 
  *  - <OpenLayers.Layer>
  */
 OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
 
-    /**
+    /** 
      * Constant: URL_HASH_FACTOR
      * {Float} Used to hash URL param strings for multi-WMS server selection.
      *         Set to the Golden Ratio per Knuth's recommendation.
      */
     URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
 
-    /**
+    /** 
      * Property: url
-     * {Array(String) or String} This is either an array of url strings or
-     *                           a single url string.
+     * {Array(String) or String} This is either an array of url strings or 
+     *                           a single url string. 
      */
     url: null,
 
-    /**
+    /** 
      * Property: params
      * {Object} Hashtable of key/value parameters
      */
     params: null,
-
-    /**
+    
+    /** 
      * APIProperty: reproject
      * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
-     * for information on the replacement for this functionality.
-     * {Boolean} Whether layer should reproject itself based on base layer
-     *           locations. This allows reprojection onto commercial layers.
-     *           Default is false: Most layers can't reproject, but layers
+     * for information on the replacement for this functionality. 
+     * {Boolean} Whether layer should reproject itself based on base layer 
+     *           locations. This allows reprojection onto commercial layers. 
+     *           Default is false: Most layers can't reproject, but layers 
      *           which can create non-square geographic pixels can, like WMS.
-     *
+     *           
      */
     reproject: false,
 
     /**
      * Constructor: OpenLayers.Layer.HTTPRequest
-     *
+     * 
      * Parameters:
      * name - {String}
      * url - {Array(String) or String}
@@ -24543,39 +26182,39 @@
     destroy: function() {
         this.url = null;
         this.params = null;
-        OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+        OpenLayers.Layer.prototype.destroy.apply(this, arguments); 
     },
-
+    
     /**
      * APIMethod: clone
-     *
+     * 
      * Parameters:
      * obj - {Object}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this
+     * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this 
      *                                  <OpenLayers.Layer.HTTPRequest>
      */
     clone: function (obj) {
-
+        
         if (obj == null) {
             obj = new OpenLayers.Layer.HTTPRequest(this.name,
                                                    this.url,
                                                    this.params,
-                                                   this.options);
+                                                   this.getOptions());
         }
-
+        
         //get all additions from superclasses
         obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
 
         // copy/set any non-init, non-simple values here
-
+        
         return obj;
     },
 
-    /**
+    /** 
      * APIMethod: setUrl
-     *
+     * 
      * Parameters:
      * newUrl - {String}
      */
@@ -24585,7 +26224,7 @@
 
     /**
      * APIMethod: mergeNewParams
-     *
+     * 
      * Parameters:
      * newParams - {Object}
      *
@@ -24594,7 +26233,14 @@
      */
     mergeNewParams:function(newParams) {
         this.params = OpenLayers.Util.extend(this.params, newParams);
-        return this.redraw();
+        var ret = this.redraw();
+        if(this.map != null) {
+            this.map.events.triggerEvent("changelayer", {
+                layer: this,
+                property: "params"
+            });
+        }
+        return ret;
     },
 
     /**
@@ -24607,18 +26253,18 @@
      * Returns:
      * {Boolean} The layer was redrawn.
      */
-    redraw: function(force) {
+    redraw: function(force) { 
         if (force) {
             return this.mergeNewParams({"_olSalt": Math.random()});
         } else {
             return OpenLayers.Layer.prototype.redraw.apply(this, []);
         }
     },
-
+    
     /**
      * Method: selectUrl
      * selectUrl() implements the standard floating-point multiplicative
-     *     hash function described by Knuth, and hashes the contents of the
+     *     hash function described by Knuth, and hashes the contents of the 
      *     given param string into a float between 0 and 1. This float is then
      *     scaled to the size of the provided urls array, and used to select
      *     a URL.
@@ -24626,60 +26272,60 @@
      * Parameters:
      * paramString - {String}
      * urls - {Array(String)}
-     *
+     * 
      * Returns:
      * {String} An entry from the urls array, deterministically selected based
      *          on the paramString.
      */
     selectUrl: function(paramString, urls) {
         var product = 1;
-        for (var i=0, len=paramString.length; i<len; i++) {
-            product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR;
-            product -= Math.floor(product);
+        for (var i=0, len=paramString.length; i<len; i++) { 
+            product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR; 
+            product -= Math.floor(product); 
         }
         return urls[Math.floor(product * urls.length)];
     },
 
-    /**
+    /** 
      * Method: getFullRequestString
-     * Combine url with layer's params and these newParams.
+     * Combine url with layer's params and these newParams. 
+     *   
+     *    does checking on the serverPath variable, allowing for cases when it 
+     *     is supplied with trailing ? or &, as well as cases where not. 
      *
-     *    does checking on the serverPath variable, allowing for cases when it
-     *     is supplied with trailing ? or &, as well as cases where not.
-     *
      *    return in formatted string like this:
      *        "server?key1=value1&key2=value2&key3=value3"
-     *
+     * 
      * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.
      *
      * Parameters:
      * newParams - {Object}
      * altUrl - {String} Use this as the url instead of the layer's url
-     *
-     * Returns:
+     *   
+     * Returns: 
      * {String}
      */
     getFullRequestString:function(newParams, altUrl) {
 
         // if not altUrl passed in, use layer's url
         var url = altUrl || this.url;
-
-        // create a new params hashtable with all the layer params and the
+        
+        // create a new params hashtable with all the layer params and the 
         // new params together. then convert to string
         var allParams = OpenLayers.Util.extend({}, this.params);
         allParams = OpenLayers.Util.extend(allParams, newParams);
         var paramsString = OpenLayers.Util.getParameterString(allParams);
-
-        // if url is not a string, it should be an array of strings,
-        // in which case we will deterministically select one of them in
+        
+        // if url is not a string, it should be an array of strings, 
+        // in which case we will deterministically select one of them in 
         // order to evenly distribute requests to different urls.
         //
         if (url instanceof Array) {
             url = this.selectUrl(paramsString, url);
-        }
-
+        }   
+ 
         // ignore parameters that are already in the url search string
-        var urlParams =
+        var urlParams = 
             OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));
         for(var key in allParams) {
             if(key.toUpperCase() in urlParams) {
@@ -24687,26 +26333,8 @@
             }
         }
         paramsString = OpenLayers.Util.getParameterString(allParams);
-
-        // requestString always starts with url
-        var requestString = url;
-
-        if (paramsString != "") {
-            var lastServerChar = url.charAt(url.length - 1);
-            if ((lastServerChar == "&") || (lastServerChar == "?")) {
-                requestString += paramsString;
-            } else {
-                if (url.indexOf('?') == -1) {
-                    //serverPath has no ? -- add one
-                    requestString += '?' + paramsString;
-                } else {
-                    //serverPath contains ?, so must already have
-                    // paramsString at the end
-                    requestString += '&' + paramsString;
-                }
-            }
-        }
-        return requestString;
+        
+        return OpenLayers.Util.urlAppend(url, paramsString);
     },
 
     CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
@@ -24715,8 +26343,9 @@
     OpenLayers/Layer/Markers.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -24726,49 +26355,49 @@
 
 /**
  * Class: OpenLayers.Layer.Markers
- *
+ * 
  * Inherits from:
- *  - <OpenLayers.Layer>
+ *  - <OpenLayers.Layer> 
  */
 OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, {
-
-    /**
-     * APIProperty: isBaseLayer
-     * {Boolean} Markers layer is never a base layer.
+    
+    /** 
+     * APIProperty: isBaseLayer 
+     * {Boolean} Markers layer is never a base layer.  
      */
     isBaseLayer: false,
-
-    /**
-     * APIProperty: markers
-     * {Array(<OpenLayers.Marker>)} internal marker list
+    
+    /** 
+     * APIProperty: markers 
+     * {Array(<OpenLayers.Marker>)} internal marker list 
      */
     markers: null,
 
 
-    /**
-     * Property: drawn
+    /** 
+     * Property: drawn 
      * {Boolean} internal state of drawing. This is a workaround for the fact
      * that the map does not call moveTo with a zoomChanged when the map is
      * first starting up. This lets us catch the case where we have *never*
      * drawn the layer, and draw it even if the zoom hasn't changed.
      */
     drawn: false,
-
+    
     /**
-     * Constructor: OpenLayers.Layer.Markers
+     * Constructor: OpenLayers.Layer.Markers 
      * Create a Markers layer.
      *
      * Parameters:
-     * name - {String}
+     * name - {String} 
      * options - {Object} Hashtable of extra options to tag onto the layer
      */
     initialize: function(name, options) {
         OpenLayers.Layer.prototype.initialize.apply(this, arguments);
         this.markers = [];
     },
-
+    
     /**
-     * APIMethod: destroy
+     * APIMethod: destroy 
      */
     destroy: function() {
         this.clearMarkers();
@@ -24779,7 +26408,7 @@
     /**
      * APIMethod: setOpacity
      * Sets the opacity for all the markers.
-     *
+     * 
      * Parameter:
      * opacity - {Float}
      */
@@ -24792,13 +26421,13 @@
         }
     },
 
-    /**
+    /** 
      * Method: moveTo
      *
      * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * zoomChanged - {Boolean}
-     * dragging - {Boolean}
+     * bounds - {<OpenLayers.Bounds>} 
+     * zoomChanged - {Boolean} 
+     * dragging - {Boolean} 
      */
     moveTo:function(bounds, zoomChanged, dragging) {
         OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
@@ -24815,7 +26444,7 @@
      * APIMethod: addMarker
      *
      * Parameters:
-     * marker - {<OpenLayers.Marker>}
+     * marker - {<OpenLayers.Marker>} 
      */
     addMarker: function(marker) {
         this.markers.push(marker);
@@ -24834,7 +26463,7 @@
      * APIMethod: removeMarker
      *
      * Parameters:
-     * marker - {<OpenLayers.Marker>}
+     * marker - {<OpenLayers.Marker>} 
      */
     removeMarker: function(marker) {
         if (this.markers && this.markers.length) {
@@ -24856,13 +26485,13 @@
         }
     },
 
-    /**
+    /** 
      * Method: drawMarker
-     * Calculate the pixel location for the marker, create it, and
+     * Calculate the pixel location for the marker, create it, and 
      *    add it to the layer's div
      *
      * Parameters:
-     * marker - {<OpenLayers.Marker>}
+     * marker - {<OpenLayers.Marker>} 
      */
     drawMarker: function(marker) {
         var px = this.map.getLayerPxFromLonLat(marker.lonlat);
@@ -24877,17 +26506,17 @@
             }
         }
     },
-
-    /**
+    
+    /** 
      * APIMethod: getDataExtent
      * Calculates the max extent which includes all of the markers.
-     *
+     * 
      * Returns:
      * {<OpenLayers.Bounds>}
      */
     getDataExtent: function () {
         var maxExtent = null;
-
+        
         if ( this.markers && (this.markers.length > 0)) {
             var maxExtent = new OpenLayers.Bounds();
             for(var i=0, len=this.markers.length; i<len; i++) {
@@ -24905,6 +26534,11 @@
     OpenLayers/Layer/SphericalMercator.js
    ====================================================================== */
 
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
 /**
  * @requires OpenLayers/Layer.js
  * @requires OpenLayers/Projection.js
@@ -24929,12 +26563,12 @@
  *
  * WKT:
  *     900913=PROJCS["WGS84 / Simple Mercator", GEOGCS["WGS 84",
- *     DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]],
- *     PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295],
+ *     DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]], 
+ *     PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295], 
  *     AXIS["Longitude", EAST], AXIS["Latitude", NORTH]],
- *     PROJECTION["Mercator_1SP_Google"],
- *     PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0],
- *     PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0],
+ *     PROJECTION["Mercator_1SP_Google"], 
+ *     PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0], 
+ *     PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0], 
  *     PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST],
  *     AXIS["y", NORTH], AUTHORITY["EPSG","900913"]]
  */
@@ -24958,7 +26592,39 @@
     },
 
     /**
-     * Method: initMercatorParameters
+     * Method: getLonLatFromViewPortPx
+     * Get a map location from a pixel location
+     * 
+     * Parameters:
+     * viewPortPx - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     *  {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
+     *  port OpenLayers.Pixel, translated into lon/lat by map lib
+     *  If the map lib is not loaded or not centered, returns null
+     */
+    getLonLatFromViewPortPx: function (viewPortPx) {
+        return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments);
+    },
+    
+    /**
+     * Method: getViewPortPxFromLonLat
+     * Get a pixel location from a map location
+     *
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     *
+     * Returns:
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
+     * OpenLayers.LonLat, translated into view port pixels by map lib
+     * If map lib is not loaded or not centered, returns null
+     */
+    getViewPortPxFromLonLat: function (lonlat) {
+        return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments);
+    },
+
+    /** 
+     * Method: initMercatorParameters 
      * Set up the mercator parameters on the layer: resolutions,
      *     projection, units.
      */
@@ -24970,7 +26636,7 @@
             this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom);
         }
         this.units = "m";
-        this.projection = "EPSG:900913";
+        this.projection = this.projection || "EPSG:900913";
     },
 
     /**
@@ -24978,9 +26644,9 @@
      * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator.
      *
      * Parameters:
-     * lon - {float}
+     * lon - {float} 
      * lat - {float}
-     *
+     * 
      * Returns:
      * {<OpenLayers.LonLat>} The coordinates transformed to Mercator.
      */
@@ -24989,7 +26655,7 @@
         var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
 
         y = y * 20037508.34 / 180;
-
+        
         return new OpenLayers.LonLat(x, y);
     },
 
@@ -25000,7 +26666,7 @@
      * Parameters:
      * x - {float} A map x in Spherical Mercator.
      * y - {float} A map y in Spherical Mercator.
-     *
+     * 
      * Returns:
      * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326.
      */
@@ -25010,19 +26676,19 @@
         var lat = (y / 20037508.34) * 180;
 
         lat = 180/Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
-
+        
         return new OpenLayers.LonLat(lon, lat);
     },
 
     /**
-     * Method: projectForward
+     * Method: projectForward 
      * Given an object with x and y properties in EPSG:4326, modify the x,y
      * properties on the object to be the Spherical Mercator projected
      * coordinates.
      *
      * Parameters:
-     * point - {Object} An object with x and y properties.
-     *
+     * point - {Object} An object with x and y properties. 
+     * 
      * Returns:
      * {Object} The point, with the x and y properties transformed to spherical
      * mercator.
@@ -25033,15 +26699,15 @@
         point.y = lonlat.lat;
         return point;
     },
-
+    
     /**
      * Method: projectInverse
      * Given an object with x and y properties in Spherical Mercator, modify
      * the x,y properties on the object to be the unprojected coordinates.
      *
      * Parameters:
-     * point - {Object} An object with x and y properties.
-     *
+     * point - {Object} An object with x and y properties. 
+     * 
      * Returns:
      * {Object} The point, with the x and y properties transformed from
      * spherical mercator to unprojected coordinates..
@@ -25068,8 +26734,9 @@
     OpenLayers/Control/DrawFeature.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -25087,7 +26754,7 @@
  *  - <OpenLayers.Control>
  */
 OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, {
-
+    
     /**
      * Property: layer
      * {<OpenLayers.Layer.Vector>}
@@ -25099,7 +26766,7 @@
      * {Object} The functions that are sent to the handler for callback
      */
     callbacks: null,
-
+    
     /**
      * Constant: EVENT_TYPES
      *
@@ -25107,6 +26774,13 @@
      * featureadded - Triggered when a feature is added
      */
     EVENT_TYPES: ["featureadded"],
+    
+    /**
+     * APIProperty: multi
+     * {Boolean} Cast features to multi-part geometries before passing to the
+     *     layer.  Default is false.
+     */
+    multi: false,
 
     /**
      * APIProperty: featureAdded
@@ -25119,23 +26793,23 @@
      * {Object} Used to set non-default properties on the control's handler
      */
     handlerOptions: null,
-
+    
     /**
      * Constructor: OpenLayers.Control.DrawFeature
-     *
+     * 
      * Parameters:
-     * layer - {<OpenLayers.Layer.Vector>}
-     * handler - {<OpenLayers.Handler>}
-     * options - {Object}
+     * layer - {<OpenLayers.Layer.Vector>} 
+     * handler - {<OpenLayers.Handler>} 
+     * options - {Object} 
      */
     initialize: function(layer, handler, options) {
-
+        
         // concatenate events specific to vector with those from the base
         this.EVENT_TYPES =
             OpenLayers.Control.DrawFeature.prototype.EVENT_TYPES.concat(
             OpenLayers.Control.prototype.EVENT_TYPES
         );
-
+        
         OpenLayers.Control.prototype.initialize.apply(this, [options]);
         this.callbacks = OpenLayers.Util.extend(
             {
@@ -25154,9 +26828,12 @@
             this.callbacks
         );
         this.layer = layer;
+        this.handlerOptions = this.handlerOptions || {};
+        if (!("multi" in this.handlerOptions)) {
+            this.handlerOptions.multi = this.multi;
+        }
         var sketchStyle = this.layer.styleMap && this.layer.styleMap.styles.temporary;
         if(sketchStyle) {
-            this.handlerOptions = this.handlerOptions || {};
             this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults(
                 this.handlerOptions.layerOptions,
                 {styleMap: new OpenLayers.StyleMap({"default": sketchStyle})}
@@ -25187,8 +26864,9 @@
     OpenLayers/Control/Measure.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -25231,20 +26909,20 @@
      * {Object} Used to set non-default properties on the control's handler
      */
     handlerOptions: null,
-
+    
     /**
      * Property: callbacks
      * {Object} The functions that are sent to the handler for callback
      */
     callbacks: null,
-
+    
     /**
      * Property: displaySystem
      * {String} Display system for output measurements.  Supported values
      *     are 'english', 'metric', and 'geographic'.  Default is 'metric'.
      */
     displaySystem: 'metric',
-
+    
     /**
      * Property: geodesic
      * {Boolean} Calculate geodesic metrics instead of planar metrics.  This
@@ -25252,7 +26930,7 @@
      *     (if that is not already the map projection).  Default is false.
      */
     geodesic: false,
-
+    
     /**
      * Property: displaySystemUnits
      * {Object} Units for various measurement systems.  Values are arrays
@@ -25281,7 +26959,7 @@
      * {Number} Timeout id of trigger for measurepartial.
      */
     delayedTrigger: null,
-
+    
     /**
      * APIProperty: persist
      * {Boolean} Keep the temporary measurement sketch drawn after the
@@ -25293,10 +26971,10 @@
 
     /**
      * Constructor: OpenLayers.Control.Measure
-     *
+     * 
      * Parameters:
-     * handler - {<OpenLayers.Handler>}
-     * options - {Object}
+     * handler - {<OpenLayers.Handler>} 
+     * options - {Object} 
      */
     initialize: function(handler, options) {
         // concatenate events specific to measure with those from the base
@@ -25310,14 +26988,14 @@
             this.callbacks
         );
 
-        // let the handler options override, so old code that passes 'persist'
+        // let the handler options override, so old code that passes 'persist' 
         // directly to the handler does not need an update
         this.handlerOptions = OpenLayers.Util.extend(
             {persist: this.persist}, this.handlerOptions
         );
         this.handler = new handler(this, this.callbacks, this.handlerOptions);
     },
-
+    
     /**
      * APIMethod: cancel
      * Stop the control from measuring.  If <persist> is true, the temporary
@@ -25326,7 +27004,7 @@
     cancel: function() {
         this.handler.cancel();
     },
-
+    
     /**
      * Method: updateHandler
      *
@@ -25358,7 +27036,7 @@
         }
         this.measure(geometry, "measure");
     },
-
+    
     /**
      * Method: measurePartial
      * Called each time a new point is added to the measurement sketch.
@@ -25368,12 +27046,15 @@
      * geometry - {<OpenLayers.Geometry>} The sketch geometry.
      */
     measurePartial: function(point, geometry) {
-        this.delayedTrigger = window.setTimeout(
-            OpenLayers.Function.bind(function() {
-                this.measure(geometry, "measurepartial");
-            }, this),
-            this.partialDelay
-        );
+        if (geometry.getLength() > 0) {
+            geometry = geometry.clone();
+            this.delayedTrigger = window.setTimeout(
+                OpenLayers.Function.bind(function() {
+                    this.measure(geometry, "measurepartial");
+                }, this),
+                this.partialDelay
+            );
+        }
     },
 
     /**
@@ -25399,7 +27080,7 @@
             geometry: geometry
         });
     },
-
+    
     /**
      * Method: getBestArea
      * Based on the <displaySystem> returns the area of a geometry.
@@ -25423,7 +27104,7 @@
         }
         return [area, unit];
     },
-
+    
     /**
      * Method: getArea
      *
@@ -25450,7 +27131,7 @@
         }
         return area;
     },
-
+    
     /**
      * Method: getBestLength
      * Based on the <displaySystem> returns the length of a geometry.
@@ -25508,8 +27189,9 @@
     OpenLayers/Control/ZoomBox.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -25519,8 +27201,8 @@
 
 /**
  * Class: OpenLayers.Control.ZoomBox
- * The ZoomBox control enables zooming directly to a given extent, by drawing
- * a box on the map. The box is drawn by holding down shift, whilst dragging
+ * The ZoomBox control enables zooming directly to a given extent, by drawing 
+ * a box on the map. The box is drawn by holding down shift, whilst dragging 
  * the mouse.
  *
  * Inherits from:
@@ -25541,13 +27223,13 @@
 
     /**
      * Property: alwaysZoom
-     * {Boolean} Always zoom in/out, when box drawed
+     * {Boolean} Always zoom in/out, when box drawed 
      */
     alwaysZoom: false,
 
     /**
      * Method: draw
-     */
+     */    
     draw: function() {
         this.handler = new OpenLayers.Handler.Box( this,
                             {done: this.zoomBox}, {keyMask: this.keyMask} );
@@ -25561,12 +27243,13 @@
      */
     zoomBox: function (position) {
         if (position instanceof OpenLayers.Bounds) {
+            var bounds;
             if (!this.out) {
                 var minXY = this.map.getLonLatFromPixel(
                             new OpenLayers.Pixel(position.left, position.bottom));
                 var maxXY = this.map.getLonLatFromPixel(
                             new OpenLayers.Pixel(position.right, position.top));
-                var bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat,
+                bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat,
                                                maxXY.lon, maxXY.lat);
             } else {
                 var pixWidth = Math.abs(position.right-position.left);
@@ -25580,13 +27263,13 @@
                 var xmax = center.lon + (extent.getWidth()/2)*zoomFactor;
                 var ymin = center.lat - (extent.getHeight()/2)*zoomFactor;
                 var ymax = center.lat + (extent.getHeight()/2)*zoomFactor;
-                var bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax);
+                bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax);
             }
-            // always zoom in/out
-            var lastZoom = this.map.getZoom();
+            // always zoom in/out 
+            var lastZoom = this.map.getZoom(); 
             this.map.zoomToExtent(bounds);
-            if (lastZoom == this.map.getZoom() && this.alwaysZoom == true){
-                this.map.zoomTo(lastZoom + (this.out ? -1 : 1));
+            if (lastZoom == this.map.getZoom() && this.alwaysZoom == true){ 
+                this.map.zoomTo(lastZoom + (this.out ? -1 : 1)); 
             }
         } else { // it's a pixel
             if (!this.out) {
@@ -25605,8 +27288,9 @@
     OpenLayers/Format/WKT.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -25618,12 +27302,12 @@
  * Class: OpenLayers.Format.WKT
  * Class for reading and writing Well-Known Text.  Create a new instance
  * with the <OpenLayers.Format.WKT> constructor.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Format>
  */
 OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, {
-
+    
     /**
      * Constructor: OpenLayers.Format.WKT
      * Create a new parser for WKT
@@ -25670,7 +27354,7 @@
                 features = this.parse[type].apply(this, [str]);
             }
             if (this.internalProjection && this.externalProjection) {
-                if (features &&
+                if (features && 
                     features.CLASS_NAME == "OpenLayers.Feature.Vector") {
                     features.geometry.transform(this.externalProjection,
                                                 this.internalProjection);
@@ -25684,7 +27368,7 @@
                     }
                 }
             }
-        }
+        }    
         return features;
     },
 
@@ -25723,9 +27407,9 @@
             }
             if (this.internalProjection && this.externalProjection) {
                 geometry = geometry.clone();
-                geometry.transform(this.internalProjection,
+                geometry.transform(this.internalProjection, 
                                    this.externalProjection);
-            }
+            }                       
             data = this.extract[type].apply(this, [geometry]);
             pieces.push(type.toUpperCase() + '(' + data + ')');
         }
@@ -25734,7 +27418,7 @@
         }
         return pieces.join('');
     },
-
+    
     /**
      * Object with properties corresponding to the geometry types.
      * Property values are functions that do the actual data extraction.
@@ -25758,11 +27442,13 @@
         'multipoint': function(multipoint) {
             var array = [];
             for(var i=0, len=multipoint.components.length; i<len; ++i) {
-                array.push(this.extract.point.apply(this, [multipoint.components[i]]));
+                array.push('(' +
+                           this.extract.point.apply(this, [multipoint.components[i]]) +
+                           ')');
             }
             return array.join(',');
         },
-
+        
         /**
          * Return a comma delimited string of point coordinates from a line.
          * @param {<OpenLayers.Geometry.LineString>} linestring
@@ -25792,7 +27478,7 @@
             }
             return array.join(',');
         },
-
+        
         /**
          * Return a comma delimited string of linear ring arrays from a polygon.
          * @param {<OpenLayers.Geometry.Polygon>} polygon
@@ -25851,16 +27537,18 @@
          * @private
          */
         'multipoint': function(str) {
-            var points = OpenLayers.String.trim(str).split(',');
+            var point;
+            var points = OpenLayers.String.trim(str).split(this.regExes.parenComma);
             var components = [];
             for(var i=0, len=points.length; i<len; ++i) {
-                components.push(this.parse.point.apply(this, [points[i]]).geometry);
+                point = points[i].replace(this.regExes.trimParens, '$1');
+                components.push(this.parse.point.apply(this, [point]).geometry);
             }
             return new OpenLayers.Feature.Vector(
                 new OpenLayers.Geometry.MultiPoint(components)
             );
         },
-
+        
         /**
          * Return a linestring feature given a linestring WKT fragment.
          * @param {String} A WKT fragment representing the linestring
@@ -25896,7 +27584,7 @@
                 new OpenLayers.Geometry.MultiLineString(components)
             );
         },
-
+        
         /**
          * Return a polygon feature given a polygon WKT fragment.
          * @param {String} A WKT fragment representing the polygon
@@ -25956,14 +27644,15 @@
 
     },
 
-    CLASS_NAME: "OpenLayers.Format.WKT"
-});
+    CLASS_NAME: "OpenLayers.Format.WKT" 
+});     
 /* ======================================================================
     OpenLayers/Layer/Google.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -25971,59 +27660,60 @@
  * @requires OpenLayers/Layer/SphericalMercator.js
  * @requires OpenLayers/Layer/EventPane.js
  * @requires OpenLayers/Layer/FixedZoomLevels.js
- * @requires OpenLayers/Console.js
  */
 
 /**
  * Class: OpenLayers.Layer.Google
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Layer.SphericalMercator>
  *  - <OpenLayers.Layer.EventPane>
  *  - <OpenLayers.Layer.FixedZoomLevels>
  */
 OpenLayers.Layer.Google = OpenLayers.Class(
-    OpenLayers.Layer.EventPane,
+    OpenLayers.Layer.EventPane, 
     OpenLayers.Layer.FixedZoomLevels, {
-
-    /**
+    
+    /** 
      * Constant: MIN_ZOOM_LEVEL
-     * {Integer} 0
+     * {Integer} 0 
      */
     MIN_ZOOM_LEVEL: 0,
-
-    /**
+    
+    /** 
      * Constant: MAX_ZOOM_LEVEL
-     * {Integer} 19
+     * {Integer} 21
      */
-    MAX_ZOOM_LEVEL: 19,
+    MAX_ZOOM_LEVEL: 21,
 
-    /**
+    /** 
      * Constant: RESOLUTIONS
      * {Array(Float)} Hardcode these resolutions so that they are more closely
      *                tied with the standard wms projection
      */
     RESOLUTIONS: [
-        1.40625,
-        0.703125,
-        0.3515625,
-        0.17578125,
-        0.087890625,
+        1.40625, 
+        0.703125, 
+        0.3515625, 
+        0.17578125, 
+        0.087890625, 
         0.0439453125,
-        0.02197265625,
-        0.010986328125,
-        0.0054931640625,
+        0.02197265625, 
+        0.010986328125, 
+        0.0054931640625, 
         0.00274658203125,
-        0.001373291015625,
-        0.0006866455078125,
+        0.001373291015625, 
+        0.0006866455078125, 
         0.00034332275390625,
-        0.000171661376953125,
-        0.0000858306884765625,
+        0.000171661376953125, 
+        0.0000858306884765625, 
         0.00004291534423828125,
-        0.00002145767211914062,
+        0.00002145767211914062, 
         0.00001072883605957031,
-        0.00000536441802978515,
-        0.00000268220901489257
+        0.00000536441802978515, 
+        0.00000268220901489257,
+        0.0000013411045074462891,
+        0.00000067055225372314453
     ],
 
     /**
@@ -26033,147 +27723,504 @@
     type: null,
 
     /**
-     * APIProperty: sphericalMercator
-     * {Boolean} Should the map act as a mercator-projected map? This will
-     *     cause all interactions with the map to be in the actual map
-     *     projection, which allows support for vector drawing, overlaying
-     *     other maps, etc.
+     * APIProperty: wrapDateLine
+     * {Boolean} Allow user to pan forever east/west.  Default is true.  
+     *     Setting this to false only restricts panning if 
+     *     <sphericalMercator> is true. 
      */
-    sphericalMercator: false,
+    wrapDateLine: true,
 
     /**
-     * Property: dragObject
-     * {GDraggableObject} Since 2.93, Google has exposed the ability to get
-     *     the maps GDraggableObject. We can now use this for smooth panning
+     * APIProperty: sphericalMercator
+     * {Boolean} Should the map act as a mercator-projected map? This will
+     *     cause all interactions with the map to be in the actual map 
+     *     projection, which allows support for vector drawing, overlaying 
+     *     other maps, etc. 
      */
-    dragObject: null,
-
+    sphericalMercator: false, 
+    
     /**
-     * Property: termsOfUse
-     * {DOMElement} Div for Google's copyright and terms of use link
+     * Property: version
+     * {Number} The version of the Google Maps API
      */
-    termsOfUse: null,
+    version: null,
 
-    /**
-     * Property: poweredBy
-     * {DOMElement} Div for Google's powered by logo and link
-     */
-    poweredBy: null,
-
-    /**
+    /** 
      * Constructor: OpenLayers.Layer.Google
-     *
+     * 
      * Parameters:
      * name - {String} A name for the layer.
      * options - {Object} An optional object whose properties will be set
      *     on the layer.
      */
     initialize: function(name, options) {
-        OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
-        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
-                                                                    arguments);
-        this.addContainerPxFunction();
+        options = options || {};
+        if(!options.version) {
+            options.version = typeof GMap2 === "function" ? "2" : "3";
+        }
+        var mixin = OpenLayers.Layer.Google["v" +
+            options.version.replace(/\./g, "_")];
+        if (mixin) {
+            OpenLayers.Util.applyDefaults(options, mixin);
+        } else {
+            throw "Unsupported Google Maps API version: " + options.version;
+        }
+
+        OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS);
+        if (options.maxExtent) {
+            options.maxExtent = options.maxExtent.clone();
+        }
+
+        OpenLayers.Layer.EventPane.prototype.initialize.apply(this,
+            [name, options]);
+        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, 
+            [name, options]);
+
         if (this.sphericalMercator) {
             OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
             this.initMercatorParameters();
-        }
+        }    
     },
 
     /**
-     * Method: loadMapObject
-     * Load the GMap and register appropriate event listeners. If we can't
-     *     load GMap2, then display a warning message.
+     * Method: clone
+     * Create a clone of this layer
+     *
+     * Returns:
+     * {<OpenLayers.Layer.Google>} An exact clone of this layer
      */
-    loadMapObject:function() {
+    clone: function() {
+        /**
+         * This method isn't intended to be called by a subclass and it
+         * doesn't call the same method on the superclass.  We don't call
+         * the super's clone because we don't want properties that are set
+         * on this layer after initialize (i.e. this.mapObject etc.).
+         */
+        return new OpenLayers.Layer.Google(
+            this.name, this.getOptions()
+        );
+    },
 
-        //has gmaps library has been loaded?
-        try {
-            // create GMap, hide nav controls
-            this.mapObject = new GMap2( this.div );
+    /**
+     * APIMethod: setVisibility
+     * Set the visibility flag for the layer and hide/show & redraw 
+     *     accordingly. Fire event unless otherwise specified
+     * 
+     * Note that visibility is no longer simply whether or not the layer's
+     *     style.display is set to "block". Now we store a 'visibility' state 
+     *     property on the layer class, this allows us to remember whether or 
+     *     not we *desire* for a layer to be visible. In the case where the 
+     *     map's resolution is out of the layer's range, this desire may be 
+     *     subverted.
+     * 
+     * Parameters:
+     * visible - {Boolean} Display the layer (if in range)
+     */
+    setVisibility: function(visible) {
+        // sharing a map container, opacity has to be set per layer
+        var opacity = this.opacity == null ? 1 : this.opacity;
+        OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments);
+        this.setOpacity(opacity);
+    },
+    
+    /** 
+     * APIMethod: display
+     * Hide or show the Layer
+     * 
+     * Parameters:
+     * display - {Boolean}
+     */
+    display: function(visible) {
+        if (!this._dragging) {
+            this.setGMapVisibility(visible);
+        }
+        OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments);
+    },
+    
+    /**
+     * Method: moveTo
+     * 
+     * Parameters:
+     * bound - {<OpenLayers.Bounds>}
+     * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
+     *     do some init work in that case.
+     * dragging - {Boolean}
+     */
+    moveTo: function(bounds, zoomChanged, dragging) {
+        this._dragging = dragging;
+        OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments);
+        delete this._dragging;
+    },
+    
+    /**
+     * APIMethod: setOpacity
+     * Sets the opacity for the entire layer (all images)
+     * 
+     * Parameter:
+     * opacity - {Float}
+     */
+    setOpacity: function(opacity) {
+        if (opacity !== this.opacity) {
+            if (this.map != null) {
+                this.map.events.triggerEvent("changelayer", {
+                    layer: this,
+                    property: "opacity"
+                });
+            }
+            this.opacity = opacity;
+        }
+        // Though this layer's opacity may not change, we're sharing a container
+        // and need to update the opacity for the entire container.
+        if (this.getVisibility()) {
+            var container = this.getMapContainer();
+            OpenLayers.Util.modifyDOMElement(
+                container, null, null, null, null, null, null, opacity
+            );
+        }
+    },
 
-            //since v 2.93 getDragObject is now available.
-            if(typeof this.mapObject.getDragObject == "function") {
-                this.dragObject = this.mapObject.getDragObject();
-            } else {
-                this.dragPanMapObject = null;
+    /**
+     * APIMethod: destroy
+     * Clean up this layer.
+     */
+    destroy: function() {
+        /**
+         * We have to override this method because the event pane destroy
+         * deletes the mapObject reference before removing this layer from
+         * the map.
+         */
+        if (this.map) {
+            this.setGMapVisibility(false);
+            var cache = OpenLayers.Layer.Google.cache[this.map.id];
+            if (cache && cache.count <= 1) {
+                this.removeGMapElements();
+            }            
+        }
+        OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments);
+    },
+    
+    /**
+     * Method: removeGMapElements
+     * Remove all elements added to the dom.  This should only be called if
+     * this is the last of the Google layers for the given map.
+     */
+    removeGMapElements: function() {
+        var cache = OpenLayers.Layer.Google.cache[this.map.id];
+        if (cache) {
+            // remove shared elements from dom
+            var container = this.mapObject && this.getMapContainer();                
+            if (container && container.parentNode) {
+                container.parentNode.removeChild(container);
             }
+            var termsOfUse = cache.termsOfUse;
+            if (termsOfUse && termsOfUse.parentNode) {
+                termsOfUse.parentNode.removeChild(termsOfUse);
+            }
+            var poweredBy = cache.poweredBy;
+            if (poweredBy && poweredBy.parentNode) {
+                poweredBy.parentNode.removeChild(poweredBy);
+            }
+        }
+    },
 
-            // move the ToS and branding stuff up to the container div
-            this.termsOfUse = this.div.lastChild;
-            this.div.removeChild(this.termsOfUse);
-            if (this.isFixed) {
-                this.map.viewPortDiv.appendChild(this.termsOfUse);
+    /**
+     * APIMethod: removeMap
+     * On being removed from the map, also remove termsOfUse and poweredBy divs
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    removeMap: function(map) {
+        // hide layer before removing
+        if (this.visibility && this.mapObject) {
+            this.setGMapVisibility(false);
+        }
+        // check to see if last Google layer in this map
+        var cache = OpenLayers.Layer.Google.cache[map.id];
+        if (cache) {
+            if (cache.count <= 1) {
+                this.removeGMapElements();
+                delete OpenLayers.Layer.Google.cache[map.id];
             } else {
-                this.map.layerContainerDiv.appendChild(this.termsOfUse);
+                // decrement the layer count
+                --cache.count;
             }
-            this.termsOfUse.style.zIndex = "1100";
-            this.termsOfUse.style.display = this.div.style.display;
-            this.termsOfUse.style.right = "";
-            this.termsOfUse.style.bottom = "";
-            this.termsOfUse.className = "olLayerGoogleCopyright";
+        }
+        // remove references to gmap elements
+        delete this.termsOfUse;
+        delete this.poweredBy;
+        delete this.mapObject;
+        delete this.dragObject;
+        OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments);
+    },
+    
+  //
+  // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
+  //
 
-            this.poweredBy = this.div.lastChild;
-            this.div.removeChild(this.poweredBy);
-            if (this.isFixed) {
-                this.map.viewPortDiv.appendChild(this.poweredBy);
+    /**
+     * APIMethod: getOLBoundsFromMapObjectBounds
+     * 
+     * Parameters:
+     * moBounds - {Object}
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the 
+     *                       passed-in MapObject Bounds.
+     *                       Returns null if null value is passed in.
+     */
+    getOLBoundsFromMapObjectBounds: function(moBounds) {
+        var olBounds = null;
+        if (moBounds != null) {
+            var sw = moBounds.getSouthWest();
+            var ne = moBounds.getNorthEast();
+            if (this.sphericalMercator) {
+                sw = this.forwardMercator(sw.lng(), sw.lat());
+                ne = this.forwardMercator(ne.lng(), ne.lat());
             } else {
-                this.map.layerContainerDiv.appendChild(this.poweredBy);
-            }
-            this.poweredBy.style.zIndex = "1100";
-            this.poweredBy.style.display = this.div.style.display;
-            this.poweredBy.style.right = "";
-            this.poweredBy.style.bottom = "";
-            this.poweredBy.className = "olLayerGooglePoweredBy gmnoprint";
-
-        } catch (e) {
-            OpenLayers.Console.error(e);
+                sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); 
+                ne = new OpenLayers.LonLat(ne.lng(), ne.lat()); 
+            }    
+            olBounds = new OpenLayers.Bounds(sw.lon, 
+                                             sw.lat, 
+                                             ne.lon, 
+                                             ne.lat );
         }
+        return olBounds;
+    },
 
+    /** 
+     * APIMethod: getWarningHTML
+     * 
+     * Returns: 
+     * {String} String with information on why layer is broken, how to get
+     *          it working.
+     */
+    getWarningHTML:function() {
+        return OpenLayers.i18n("googleWarning");
     },
 
+
+    /************************************
+     *                                  *
+     *   MapObject Interface Controls   *
+     *                                  *
+     ************************************/
+
+
+  // Get&Set Center, Zoom
+
     /**
-     * APIMethod: setMap
-     * Overridden from EventPane because if a map type has been specified,
-     *     we need to attach a listener for the first moveend -- this is how
-     *     we will know that the map has been centered. Only once the map has
-     *     been centered is it safe to change the gmap object's map type.
-     *
+     * APIMethod: getMapObjectCenter
+     * 
+     * Returns: 
+     * {Object} The mapObject's current center in Map Object format
+     */
+    getMapObjectCenter: function() {
+        return this.mapObject.getCenter();
+    },
+
+    /** 
+     * APIMethod: getMapObjectZoom
+     * 
+     * Returns:
+     * {Integer} The mapObject's current zoom, in Map Object format
+     */
+    getMapObjectZoom: function() {
+        return this.mapObject.getZoom();
+    },
+
+  
+    /************************************
+     *                                  *
+     *       MapObject Primitives       *
+     *                                  *
+     ************************************/
+
+
+  // LonLat
+    
+    /**
+     * APIMethod: getLongitudeFromMapObjectLonLat
+     * 
      * Parameters:
-     * map - {<OpenLayers.Map>}
+     * moLonLat - {Object} MapObject LonLat format
+     * 
+     * Returns:
+     * {Float} Longitude of the given MapObject LonLat
      */
-    setMap: function(map) {
-        OpenLayers.Layer.EventPane.prototype.setMap.apply(this, arguments);
+    getLongitudeFromMapObjectLonLat: function(moLonLat) {
+        return this.sphericalMercator ? 
+          this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon :
+          moLonLat.lng();  
+    },
 
-        if (this.type != null) {
-            this.map.events.register("moveend", this, this.setMapType);
-        }
+    /**
+     * APIMethod: getLatitudeFromMapObjectLonLat
+     * 
+     * Parameters:
+     * moLonLat - {Object} MapObject LonLat format
+     * 
+     * Returns:
+     * {Float} Latitude of the given MapObject LonLat
+     */
+    getLatitudeFromMapObjectLonLat: function(moLonLat) {
+        var lat = this.sphericalMercator ? 
+          this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat :
+          moLonLat.lat(); 
+        return lat;  
     },
+    
+  // Pixel
+    
+    /**
+     * APIMethod: getXFromMapObjectPixel
+     * 
+     * Parameters:
+     * moPixel - {Object} MapObject Pixel format
+     * 
+     * Returns:
+     * {Integer} X value of the MapObject Pixel
+     */
+    getXFromMapObjectPixel: function(moPixel) {
+        return moPixel.x;
+    },
 
     /**
-     * Method: setMapType
-     * The map has been centered, and a map type was specified, so we
-     *     set the map type on the gmap object, then unregister the listener
-     *     so that we dont keep doing this every time the map moves.
+     * APIMethod: getYFromMapObjectPixel
+     * 
+     * Parameters:
+     * moPixel - {Object} MapObject Pixel format
+     * 
+     * Returns:
+     * {Integer} Y value of the MapObject Pixel
      */
-    setMapType: function() {
-        if (this.mapObject.getCenter() != null) {
+    getYFromMapObjectPixel: function(moPixel) {
+        return moPixel.y;
+    },
+    
+    CLASS_NAME: "OpenLayers.Layer.Google"
+});
 
-            // Support for custom map types.
-            if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),
-                                        this.type) == -1) {
-                this.mapObject.addMapType(this.type);
+/**
+ * Property: OpenLayers.Layer.Google.cache
+ * {Object} Cache for elements that should only be created once per map.
+ */
+OpenLayers.Layer.Google.cache = {};
+
+
+/**
+ * Constant: OpenLayers.Layer.Google.v2
+ * 
+ * Mixin providing functionality specific to the Google Maps API v2.
+ */
+OpenLayers.Layer.Google.v2 = {
+    
+    /**
+     * Property: termsOfUse
+     * {DOMElement} Div for Google's copyright and terms of use link
+     */
+    termsOfUse: null, 
+
+    /**
+     * Property: poweredBy
+     * {DOMElement} Div for Google's powered by logo and link
+     */
+    poweredBy: null, 
+
+    /**
+     * Property: dragObject
+     * {GDraggableObject} Since 2.93, Google has exposed the ability to get
+     *     the maps GDraggableObject. We can now use this for smooth panning
+     */
+    dragObject: null, 
+    
+    /** 
+     * Method: loadMapObject
+     * Load the GMap and register appropriate event listeners. If we can't 
+     *     load GMap2, then display a warning message.
+     */
+    loadMapObject:function() {
+        if (!this.type) {
+            this.type = G_NORMAL_MAP;
+        }
+        var mapObject, termsOfUse, poweredBy;
+        var cache = OpenLayers.Layer.Google.cache[this.map.id];
+        if (cache) {
+            // there are already Google layers added to this map
+            mapObject = cache.mapObject;
+            termsOfUse = cache.termsOfUse;
+            poweredBy = cache.poweredBy;
+            // increment the layer count
+            ++cache.count;
+        } else {
+            // this is the first Google layer for this map
+
+            var container = this.map.viewPortDiv;
+            var div = document.createElement("div");
+            div.id = this.map.id + "_GMap2Container";
+            div.style.position = "absolute";
+            div.style.width = "100%";
+            div.style.height = "100%";
+            container.appendChild(div);
+
+            // create GMap and shuffle elements
+            try {
+                mapObject = new GMap2(div);
+                
+                // move the ToS and branding stuff up to the container div
+                termsOfUse = div.lastChild;
+                container.appendChild(termsOfUse);
+                termsOfUse.style.zIndex = "1100";
+                termsOfUse.style.right = "";
+                termsOfUse.style.bottom = "";
+                termsOfUse.className = "olLayerGoogleCopyright";
+
+                poweredBy = div.lastChild;
+                container.appendChild(poweredBy);
+                poweredBy.style.zIndex = "1100";
+                poweredBy.style.right = "";
+                poweredBy.style.bottom = "";
+                poweredBy.className = "olLayerGooglePoweredBy gmnoprint";
+                
+            } catch (e) {
+                throw(e);
             }
+            // cache elements for use by any other google layers added to
+            // this same map
+            OpenLayers.Layer.Google.cache[this.map.id] = {
+                mapObject: mapObject,
+                termsOfUse: termsOfUse,
+                poweredBy: poweredBy,
+                count: 1
+            };
+        }
 
-            this.mapObject.setMapType(this.type);
-            this.map.events.unregister("moveend", this, this.setMapType);
+        this.mapObject = mapObject;
+        this.termsOfUse = termsOfUse;
+        this.poweredBy = poweredBy;
+        
+        // ensure this layer type is one of the mapObject types
+        if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),
+                                    this.type) === -1) {
+            this.mapObject.addMapType(this.type);
         }
+
+        //since v 2.93 getDragObject is now available.
+        if(typeof mapObject.getDragObject == "function") {
+            this.dragObject = mapObject.getDragObject();
+        } else {
+            this.dragPanMapObject = null;
+        }
+        
+        if(this.isBaseLayer === false) {
+            this.setGMapVisibility(this.div.style.display !== "none");
+        }
+
     },
 
     /**
      * APIMethod: onMapResize
-     *
-     * Parameters:
-     * evt - {Event}
      */
     onMapResize: function() {
         // workaround for resizing of invisible or not yet fully loaded layers
@@ -26191,112 +28238,69 @@
                     delete layer._resized;
                     layer.mapObject.checkResize();
                     layer.moveTo(layer.map.getCenter(), layer.map.getZoom());
-                })
+                });
             }
             this._resized = true;
         }
     },
 
     /**
-     * Method: display
-     * Hide or show the layer
-     *
+     * Method: setGMapVisibility
+     * Display the GMap container and associated elements.
+     * 
      * Parameters:
-     * display - {Boolean}
+     * visible - {Boolean} Display the GMap elements.
      */
-    display: function(display) {
-        OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments);
-        this.termsOfUse.style.display = this.div.style.display;
-        this.poweredBy.style.display = this.div.style.display;
-    },
-
-    /**
-     * APIMethod: removeMap
-     * On being removed from the map, also remove termsOfUse and poweredBy divs
-     *
-     * Parameters:
-     * map - {<OpenLayers.Map>}
-     */
-    removeMap: function(map) {
-        if (this.termsOfUse && this.termsOfUse.parentNode) {
-            this.termsOfUse.parentNode.removeChild(this.termsOfUse);
-            this.termsOfUse = null;
+    setGMapVisibility: function(visible) {
+        var cache = OpenLayers.Layer.Google.cache[this.map.id];
+        if (cache) {
+            var container = this.mapObject.getContainer();
+            if (visible === true) {
+                this.mapObject.setMapType(this.type);
+                container.style.display = "";
+                this.termsOfUse.style.left = "";
+                this.termsOfUse.style.display = "";
+                this.poweredBy.style.display = "";            
+                cache.displayed = this.id;
+            } else {
+                if (cache.displayed === this.id) {
+                    delete cache.displayed;
+                }
+                if (!cache.displayed) {
+                    container.style.display = "none";
+                    this.termsOfUse.style.display = "none";
+                    // move ToU far to the left in addition to setting display
+                    // to "none", because at the end of the GMap2 load
+                    // sequence, display: none will be unset and ToU would be
+                    // visible after loading a map with a google layer that is
+                    // initially hidden. 
+                    this.termsOfUse.style.left = "-9999px";
+                    this.poweredBy.style.display = "none";
+                }
+            }
         }
-        if (this.poweredBy && this.poweredBy.parentNode) {
-            this.poweredBy.parentNode.removeChild(this.poweredBy);
-            this.poweredBy = null;
-        }
-        OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments);
     },
-
+    
     /**
-     * APIMethod: getZoomForExtent
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     *
+     * Method: getMapContainer
+     * 
      * Returns:
-     * {Integer} Corresponding zoom level for a specified Bounds.
-     *           If mapObject is not loaded or not centered, returns null
-     *
-    getZoomForExtent: function (bounds) {
-        var zoom = null;
-        if (this.mapObject != null) {
-            var moBounds = this.getMapObjectBoundsFromOLBounds(bounds);
-            var moZoom = this.getMapObjectZoomFromMapObjectBounds(moBounds);
-
-            //make sure zoom is within bounds
-            var moZoom = Math.min(Math.max(moZoom, this.minZoomLevel),
-                                 this.maxZoomLevel);
-
-            zoom = this.getOLZoomFromMapObjectZoom(moZoom);
-        }
-        return zoom;
+     * {DOMElement} the GMap container's div
+     */
+    getMapContainer: function() {
+        return this.mapObject.getContainer();
     },
 
-    */
-
   //
   // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
   //
 
     /**
-     * APIMethod: getOLBoundsFromMapObjectBounds
-     *
-     * Parameters:
-     * moBounds - {Object}
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the
-     *                       passed-in MapObject Bounds.
-     *                       Returns null if null value is passed in.
-     */
-    getOLBoundsFromMapObjectBounds: function(moBounds) {
-        var olBounds = null;
-        if (moBounds != null) {
-            var sw = moBounds.getSouthWest();
-            var ne = moBounds.getNorthEast();
-            if (this.sphericalMercator) {
-                sw = this.forwardMercator(sw.lng(), sw.lat());
-                ne = this.forwardMercator(ne.lng(), ne.lat());
-            } else {
-                sw = new OpenLayers.LonLat(sw.lng(), sw.lat());
-                ne = new OpenLayers.LonLat(ne.lng(), ne.lat());
-            }
-            olBounds = new OpenLayers.Bounds(sw.lon,
-                                             sw.lat,
-                                             ne.lon,
-                                             ne.lat );
-        }
-        return olBounds;
-    },
-
-    /**
      * APIMethod: getMapObjectBoundsFromOLBounds
-     *
+     * 
      * Parameters:
      * olBounds - {<OpenLayers.Bounds>}
-     *
+     * 
      * Returns:
      * {Object} A MapObject Bounds, translated from olBounds
      *          Returns null if null value is passed in
@@ -26304,11 +28308,11 @@
     getMapObjectBoundsFromOLBounds: function(olBounds) {
         var moBounds = null;
         if (olBounds != null) {
-            var sw = this.sphericalMercator ?
-              this.inverseMercator(olBounds.bottom, olBounds.left) :
+            var sw = this.sphericalMercator ? 
+              this.inverseMercator(olBounds.bottom, olBounds.left) : 
               new OpenLayers.LonLat(olBounds.bottom, olBounds.left);
-            var ne = this.sphericalMercator ?
-              this.inverseMercator(olBounds.top, olBounds.right) :
+            var ne = this.sphericalMercator ? 
+              this.inverseMercator(olBounds.top, olBounds.right) : 
               new OpenLayers.LonLat(olBounds.top, olBounds.right);
             moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon),
                                          new GLatLng(ne.lat, ne.lon));
@@ -26316,49 +28320,7 @@
         return moBounds;
     },
 
-    /**
-     * Method: addContainerPxFunction
-     * Hack-on function because GMAPS does not give it to us
-     *
-     * Parameters:
-     * gLatLng - {GLatLng}
-     *
-     * Returns:
-     * {GPoint} A GPoint specifying gLatLng translated into "Container" coords
-     */
-    addContainerPxFunction: function() {
-        if ( (typeof GMap2 != "undefined") &&
-             !GMap2.prototype.fromLatLngToContainerPixel) {
 
-            GMap2.prototype.fromLatLngToContainerPixel = function(gLatLng) {
-
-                // first we translate into "DivPixel"
-                var gPoint = this.fromLatLngToDivPixel(gLatLng);
-
-                // locate the sliding "Div" div
-                var div = this.getContainer().firstChild.firstChild;
-
-                // adjust by the offset of "Div" and voila!
-                gPoint.x += div.offsetLeft;
-                gPoint.y += div.offsetTop;
-
-                return gPoint;
-            };
-        }
-    },
-
-    /**
-     * APIMethod: getWarningHTML
-     *
-     * Returns:
-     * {String} String with information on why layer is broken, how to get
-     *          it working.
-     */
-    getWarningHTML:function() {
-        return OpenLayers.i18n("googleWarning");
-    },
-
-
     /************************************
      *                                  *
      *   MapObject Interface Controls   *
@@ -26368,21 +28330,21 @@
 
   // Get&Set Center, Zoom
 
-    /**
+    /** 
      * APIMethod: setMapObjectCenter
      * Set the mapObject to the specified center and zoom
-     *
+     * 
      * Parameters:
      * center - {Object} MapObject LonLat format
      * zoom - {int} MapObject zoom format
      */
     setMapObjectCenter: function(center, zoom) {
-        this.mapObject.setCenter(center, zoom);
+        this.mapObject.setCenter(center, zoom); 
     },
-
+   
     /**
      * APIMethod: dragPanMapObject
-     *
+     * 
      * Parameters:
      * dX - {Integer}
      * dY - {Integer}
@@ -26391,35 +28353,15 @@
         this.dragObject.moveBy(new GSize(-dX, dY));
     },
 
-    /**
-     * APIMethod: getMapObjectCenter
-     *
-     * Returns:
-     * {Object} The mapObject's current center in Map Object format
-     */
-    getMapObjectCenter: function() {
-        return this.mapObject.getCenter();
-    },
 
-    /**
-     * APIMethod: getMapObjectZoom
-     *
-     * Returns:
-     * {Integer} The mapObject's current zoom, in Map Object format
-     */
-    getMapObjectZoom: function() {
-        return this.mapObject.getZoom();
-    },
-
-
   // LonLat - Pixel Translation
-
+  
     /**
      * APIMethod: getMapObjectLonLatFromMapObjectPixel
-     *
+     * 
      * Parameters:
      * moPixel - {Object} MapObject Pixel format
-     *
+     * 
      * Returns:
      * {Object} MapObject LonLat translated from MapObject Pixel
      */
@@ -26429,10 +28371,10 @@
 
     /**
      * APIMethod: getMapObjectPixelFromMapObjectLonLat
-     *
+     * 
      * Parameters:
      * moLonLat - {Object} MapObject LonLat format
-     *
+     * 
      * Returns:
      * {Object} MapObject Pixel transtlated from MapObject LonLat
      */
@@ -26440,15 +28382,15 @@
         return this.mapObject.fromLatLngToContainerPixel(moLonLat);
     },
 
-
+  
   // Bounds
-
-    /**
+  
+    /** 
      * APIMethod: getMapObjectZoomFromMapObjectBounds
-     *
+     * 
      * Parameters:
      * moBounds - {Object} MapObject Bounds format
-     *
+     * 
      * Returns:
      * {Object} MapObject Zoom for specified MapObject Bounds
      */
@@ -26464,45 +28406,14 @@
 
 
   // LonLat
-
+    
     /**
-     * APIMethod: getLongitudeFromMapObjectLonLat
-     *
-     * Parameters:
-     * moLonLat - {Object} MapObject LonLat format
-     *
-     * Returns:
-     * {Float} Longitude of the given MapObject LonLat
-     */
-    getLongitudeFromMapObjectLonLat: function(moLonLat) {
-        return this.sphericalMercator ?
-          this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon :
-          moLonLat.lng();
-    },
-
-    /**
-     * APIMethod: getLatitudeFromMapObjectLonLat
-     *
-     * Parameters:
-     * moLonLat - {Object} MapObject LonLat format
-     *
-     * Returns:
-     * {Float} Latitude of the given MapObject LonLat
-     */
-    getLatitudeFromMapObjectLonLat: function(moLonLat) {
-        var lat = this.sphericalMercator ?
-          this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat :
-          moLonLat.lat();
-        return lat;
-    },
-
-    /**
      * APIMethod: getMapObjectLonLatFromLonLat
-     *
+     * 
      * Parameters:
      * lon - {Float}
      * lat - {Float}
-     *
+     * 
      * Returns:
      * {Object} MapObject LonLat built from lon and lat params
      */
@@ -26518,55 +28429,29 @@
     },
 
   // Pixel
-
+    
     /**
-     * APIMethod: getXFromMapObjectPixel
-     *
-     * Parameters:
-     * moPixel - {Object} MapObject Pixel format
-     *
-     * Returns:
-     * {Integer} X value of the MapObject Pixel
-     */
-    getXFromMapObjectPixel: function(moPixel) {
-        return moPixel.x;
-    },
-
-    /**
-     * APIMethod: getYFromMapObjectPixel
-     *
-     * Parameters:
-     * moPixel - {Object} MapObject Pixel format
-     *
-     * Returns:
-     * {Integer} Y value of the MapObject Pixel
-     */
-    getYFromMapObjectPixel: function(moPixel) {
-        return moPixel.y;
-    },
-
-    /**
      * APIMethod: getMapObjectPixelFromXY
-     *
+     * 
      * Parameters:
      * x - {Integer}
      * y - {Integer}
-     *
+     * 
      * Returns:
      * {Object} MapObject Pixel from x and y parameters
      */
     getMapObjectPixelFromXY: function(x, y) {
         return new GPoint(x, y);
-    },
-
-    CLASS_NAME: "OpenLayers.Layer.Google"
-});
+    }
+    
+};
 /* ======================================================================
     OpenLayers/Layer/Grid.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -26584,38 +28469,38 @@
  *  - <OpenLayers.Layer.HTTPRequest>
  */
 OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
-
+    
     /**
      * APIProperty: tileSize
      * {<OpenLayers.Size>}
      */
     tileSize: null,
-
+    
     /**
      * Property: grid
-     * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is
+     * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is 
      *     an array of tiles.
      */
     grid: null,
 
     /**
      * APIProperty: singleTile
-     * {Boolean} Moves the layer into single-tile mode, meaning that one tile
+     * {Boolean} Moves the layer into single-tile mode, meaning that one tile 
      *     will be loaded. The tile's size will be determined by the 'ratio'
-     *     property. When the tile is dragged such that it does not cover the
+     *     property. When the tile is dragged such that it does not cover the 
      *     entire viewport, it is reloaded.
      */
     singleTile: false,
 
     /** APIProperty: ratio
-     *  {Float} Used only when in single-tile mode, this specifies the
+     *  {Float} Used only when in single-tile mode, this specifies the 
      *          ratio of the size of the single tile to the size of the map.
      */
     ratio: 1.5,
 
     /**
      * APIProperty: buffer
-     * {Integer} Used only when in gridded mode, this specifies the number of
+     * {Integer} Used only when in gridded mode, this specifies the number of 
      *           extra rows and colums of tiles on each side which will
      *           surround the minimum grid tiles to cover the map.
      */
@@ -26638,10 +28523,10 @@
      * options - {Object} Hashtable of extra options to tag onto the layer
      */
     initialize: function(name, url, params, options) {
-        OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,
+        OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this, 
                                                                 arguments);
-
-        //grid layers will trigger 'tileloaded' when each new tile is
+        
+        //grid layers will trigger 'tileloaded' when each new tile is 
         // loaded, as a means of progress update to listeners.
         // listeners can access 'numLoadingTiles' if they wish to keep track
         // of the loading progress
@@ -26659,7 +28544,7 @@
         this.clearGrid();
         this.grid = null;
         this.tileSize = null;
-        OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments);
+        OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); 
     },
 
     /**
@@ -26687,17 +28572,17 @@
      *
      * Parameters:
      * obj - {Object} Is this ever used?
-     *
+     * 
      * Returns:
      * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
      */
     clone: function (obj) {
-
+        
         if (obj == null) {
             obj = new OpenLayers.Layer.Grid(this.name,
                                             this.url,
                                             this.params,
-                                            this.options);
+                                            this.getOptions());
         }
 
         //get all additions from superclasses
@@ -26707,12 +28592,12 @@
         if (this.tileSize != null) {
             obj.tileSize = this.tileSize.clone();
         }
-
+        
         // we do not want to copy reference to grid, so we make a new array
         obj.grid = [];
 
         return obj;
-    },
+    },    
 
     /**
      * Method: moveTo
@@ -26727,32 +28612,32 @@
      */
     moveTo:function(bounds, zoomChanged, dragging) {
         OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
-
+        
         bounds = bounds || this.map.getExtent();
 
         if (bounds != null) {
-
+             
             // if grid is empty or zoom has changed, we *must* re-tile
             var forceReTile = !this.grid.length || zoomChanged;
 
             // total bounds of the tiles
-            var tilesBounds = this.getTilesBounds();
-
+            var tilesBounds = this.getTilesBounds();            
+      
             if (this.singleTile) {
-
-                // We want to redraw whenever even the slightest part of the
+                
+                // We want to redraw whenever even the slightest part of the 
                 //  current bounds is not contained by our tile.
                 //  (thus, we do not specify partial -- its default is false)
-                if ( forceReTile ||
+                if ( forceReTile || 
                      (!dragging && !tilesBounds.containsBounds(bounds))) {
                     this.initSingleTile(bounds);
                 }
             } else {
-
-                // if the bounds have changed such that they are not even
-                //  *partially* contained by our tiles (IE user has
-                //  programmatically panned to the other side of the earth)
-                //  then we want to reTile (thus, partial true).
+             
+                // if the bounds have changed such that they are not even 
+                //  *partially* contained by our tiles (IE user has 
+                //  programmatically panned to the other side of the earth) 
+                //  then we want to reTile (thus, partial true).  
                 //
                 if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
                     this.initGriddedTiles(bounds);
@@ -26763,32 +28648,32 @@
             }
         }
     },
-
+    
     /**
      * APIMethod: setTileSize
      * Check if we are in singleTile mode and if so, set the size as a ratio
      *     of the map size (as specified by the layer's 'ratio' property).
-     *
+     * 
      * Parameters:
      * size - {<OpenLayers.Size>}
      */
-    setTileSize: function(size) {
+    setTileSize: function(size) { 
         if (this.singleTile) {
-            size = this.map.getSize().clone();
+            size = this.map.getSize();
             size.h = parseInt(size.h * this.ratio);
             size.w = parseInt(size.w * this.ratio);
-        }
+        } 
         OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
     },
-
+        
     /**
      * Method: getGridBounds
-     * Deprecated. This function will be removed in 3.0. Please use
+     * Deprecated. This function will be removed in 3.0. Please use 
      *     getTilesBounds() instead.
-     *
+     * 
      * Returns:
      * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
-     * currently loaded tiles (including those partially or not at all seen
+     * currently loaded tiles (including those partially or not at all seen 
      * onscreen)
      */
     getGridBounds: function() {
@@ -26804,32 +28689,32 @@
      *
      * Returns:
      * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
-     *     currently loaded tiles (including those partially or not at all seen
+     *     currently loaded tiles (including those partially or not at all seen 
      *     onscreen).
      */
-    getTilesBounds: function() {
-        var bounds = null;
-
+    getTilesBounds: function() {    
+        var bounds = null; 
+        
         if (this.grid.length) {
             var bottom = this.grid.length - 1;
             var bottomLeftTile = this.grid[bottom][0];
-
-            var right = this.grid[0].length - 1;
+    
+            var right = this.grid[0].length - 1; 
             var topRightTile = this.grid[0][right];
-
-            bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left,
+    
+            bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left, 
                                            bottomLeftTile.bounds.bottom,
-                                           topRightTile.bounds.right,
+                                           topRightTile.bounds.right, 
                                            topRightTile.bounds.top);
-
-        }
+            
+        }   
         return bounds;
     },
 
     /**
      * Method: initSingleTile
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * bounds - {<OpenLayers.Bounds>}
      */
     initSingleTile: function(bounds) {
@@ -26838,13 +28723,13 @@
         var center = bounds.getCenterLonLat();
         var tileWidth = bounds.getWidth() * this.ratio;
         var tileHeight = bounds.getHeight() * this.ratio;
-
-        var tileBounds =
+                                       
+        var tileBounds = 
             new OpenLayers.Bounds(center.lon - (tileWidth/2),
                                   center.lat - (tileHeight/2),
                                   center.lon + (tileWidth/2),
                                   center.lat + (tileHeight/2));
-
+  
         var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
         var px = this.map.getLayerPxFromLonLat(ul);
 
@@ -26855,21 +28740,21 @@
         var tile = this.grid[0][0];
         if (!tile) {
             tile = this.addTile(tileBounds, px);
-
+            
             this.addTileMonitoringHooks(tile);
             tile.draw();
             this.grid[0][0] = tile;
         } else {
             tile.moveTo(tileBounds, px);
-        }
-
+        }           
+        
         //remove all but our single tile
         this.removeExcessTiles(1,1);
     },
 
-    /**
+    /** 
      * Method: calculateGridLayout
-     * Generate parameters for the grid layout. This
+     * Generate parameters for the grid layout. This  
      *
      * Parameters:
      * bounds - {<OpenLayers.Bound>}
@@ -26883,20 +28768,20 @@
     calculateGridLayout: function(bounds, extent, resolution) {
         var tilelon = resolution * this.tileSize.w;
         var tilelat = resolution * this.tileSize.h;
-
+        
         var offsetlon = bounds.left - extent.left;
         var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
         var tilecolremain = offsetlon/tilelon - tilecol;
         var tileoffsetx = -tilecolremain * this.tileSize.w;
         var tileoffsetlon = extent.left + tilecol * tilelon;
-
-        var offsetlat = bounds.top - (extent.bottom + tilelat);
+        
+        var offsetlat = bounds.top - (extent.bottom + tilelat);  
         var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
         var tilerowremain = tilerow - offsetlat/tilelat;
         var tileoffsety = -tilerowremain * this.tileSize.h;
         var tileoffsetlat = extent.bottom + tilerow * tilelat;
-
-        return {
+        
+        return { 
           tilelon: tilelon, tilelat: tilelat,
           tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
           tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
@@ -26906,24 +28791,24 @@
 
     /**
      * Method: initGriddedTiles
-     *
+     * 
      * Parameters:
      * bounds - {<OpenLayers.Bounds>}
      */
     initGriddedTiles:function(bounds) {
-
+        
         // work out mininum number of rows and columns; this is the number of
         // tiles required to cover the viewport plus at least one for panning
 
         var viewSize = this.map.getSize();
-        var minRows = Math.ceil(viewSize.h/this.tileSize.h) +
+        var minRows = Math.ceil(viewSize.h/this.tileSize.h) + 
                       Math.max(1, 2 * this.buffer);
         var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
                       Math.max(1, 2 * this.buffer);
-
-        var extent = this.maxExtent;
+        
+        var extent = this.getMaxExtent();
         var resolution = this.map.getResolution();
-
+        
         var tileLayout = this.calculateGridLayout(bounds, extent, resolution);
 
         var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us
@@ -26931,21 +28816,21 @@
 
         var tileoffsetlon = tileLayout.tileoffsetlon;
         var tileoffsetlat = tileLayout.tileoffsetlat;
-
+        
         var tilelon = tileLayout.tilelon;
         var tilelat = tileLayout.tilelat;
 
         this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
 
-        var startX = tileoffsetx;
+        var startX = tileoffsetx; 
         var startLon = tileoffsetlon;
 
         var rowidx = 0;
-
+        
         var layerContainerDivLeft = parseInt(this.map.layerContainerDiv.style.left);
         var layerContainerDivTop = parseInt(this.map.layerContainerDiv.style.top);
-
-
+        
+    
         do {
             var row = this.grid[rowidx++];
             if (!row) {
@@ -26956,11 +28841,11 @@
             tileoffsetlon = startLon;
             tileoffsetx = startX;
             var colidx = 0;
-
+ 
             do {
-                var tileBounds =
-                    new OpenLayers.Bounds(tileoffsetlon,
-                                          tileoffsetlat,
+                var tileBounds = 
+                    new OpenLayers.Bounds(tileoffsetlon, 
+                                          tileoffsetlat, 
                                           tileoffsetlon + tilelon,
                                           tileoffsetlat + tilelat);
 
@@ -26979,17 +28864,17 @@
                 } else {
                     tile.moveTo(tileBounds, px, false);
                 }
-
-                tileoffsetlon += tilelon;
+     
+                tileoffsetlon += tilelon;       
                 tileoffsetx += this.tileSize.w;
             } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
                      || colidx < minCols);
-
+             
             tileoffsetlat -= tilelat;
             tileoffsety += this.tileSize.h;
         } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
                 || rowidx < minRows);
-
+        
         //shave off exceess rows and colums
         this.removeExcessTiles(rowidx, colidx);
 
@@ -26998,25 +28883,37 @@
     },
 
     /**
-     * Method: spiralTileLoad
-     *   Starts at the top right corner of the grid and proceeds in a spiral
-     *    towards the center, adding tiles one at a time to the beginning of a
-     *    queue.
+     * Method: getMaxExtent
+     * Get this layer's maximum extent. (Implemented as a getter for
+     *     potential specific implementations in sub-classes.)
      *
-     *   Once all the grid's tiles have been added to the queue, we go back
-     *    and iterate through the queue (thus reversing the spiral order from
-     *    outside-in to inside-out), calling draw() on each tile.
+     * Returns:
+     * {OpenLayers.Bounds}
      */
+    getMaxExtent: function() {
+        return this.maxExtent;
+    },
+    
+    /**
+     * Method: spiralTileLoad
+     *   Starts at the top right corner of the grid and proceeds in a spiral 
+     *    towards the center, adding tiles one at a time to the beginning of a 
+     *    queue. 
+     * 
+     *   Once all the grid's tiles have been added to the queue, we go back 
+     *    and iterate through the queue (thus reversing the spiral order from 
+     *    outside-in to inside-out), calling draw() on each tile. 
+     */
     spiralTileLoad: function() {
         var tileQueue = [];
-
+ 
         var directions = ["right", "down", "left", "up"];
 
         var iRow = 0;
         var iCell = -1;
         var direction = OpenLayers.Util.indexOf(directions, "right");
         var directionsTried = 0;
-
+        
         while( directionsTried < directions.length) {
 
             var testRow = iRow;
@@ -27035,21 +28932,21 @@
                 case "up":
                     testRow--;
                     break;
-            }
-
-            // if the test grid coordinates are within the bounds of the
+            } 
+    
+            // if the test grid coordinates are within the bounds of the 
             //  grid, get a reference to the tile.
             var tile = null;
             if ((testRow < this.grid.length) && (testRow >= 0) &&
                 (testCell < this.grid[0].length) && (testCell >= 0)) {
                 tile = this.grid[testRow][testCell];
             }
-
+            
             if ((tile != null) && (!tile.queued)) {
                 //add tile to beginning of queue, mark it as queued.
                 tileQueue.unshift(tile);
                 tile.queued = true;
-
+                
                 //restart the directions counter and take on the new coords
                 directionsTried = 0;
                 iRow = testRow;
@@ -27059,21 +28956,21 @@
                 direction = (direction + 1) % 4;
                 directionsTried++;
             }
-        }
-
+        } 
+        
         // now we go through and draw the tiles in forward order
         for(var i=0, len=tileQueue.length; i<len; i++) {
             var tile = tileQueue[i];
             tile.draw();
             //mark tile as unqueued for the next time (since tiles are reused)
-            tile.queued = false;
+            tile.queued = false;       
         }
     },
 
     /**
      * APIMethod: addTile
-     * Gives subclasses of Grid the opportunity to create an
-     * OpenLayer.Tile of their choosing. The implementer should initialize
+     * Gives subclasses of Grid the opportunity to create an 
+     * OpenLayer.Tile of their choosing. The implementer should initialize 
      * the new tile and take whatever steps necessary to display it.
      *
      * Parameters
@@ -27086,17 +28983,17 @@
     addTile:function(bounds, position) {
         // Should be implemented by subclasses
     },
-
-    /**
+    
+    /** 
      * Method: addTileMonitoringHooks
-     * This function takes a tile as input and adds the appropriate hooks to
+     * This function takes a tile as input and adds the appropriate hooks to 
      *     the tile so that the layer can keep track of the loading tiles.
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * tile - {<OpenLayers.Tile>}
      */
     addTileMonitoringHooks: function(tile) {
-
+        
         tile.onLoadStart = function() {
             //if that was first tile then trigger a 'loadstart' on the layer
             if (this.numLoadingTiles == 0) {
@@ -27105,7 +29002,7 @@
             this.numLoadingTiles++;
         };
         tile.events.register("loadstart", this, tile.onLoadStart);
-
+      
         tile.onLoadEnd = function() {
             this.numLoadingTiles--;
             this.events.triggerEvent("tileloaded");
@@ -27118,12 +29015,12 @@
         tile.events.register("unload", this, tile.onLoadEnd);
     },
 
-    /**
+    /** 
      * Method: removeTileMonitoringHooks
-     * This function takes a tile as input and removes the tile hooks
+     * This function takes a tile as input and removes the tile hooks 
      *     that were added in addTileMonitoringHooks()
-     *
-     * Parameters:
+     * 
+     * Parameters: 
      * tile - {<OpenLayers.Tile>}
      */
     removeTileMonitoringHooks: function(tile) {
@@ -27135,10 +29032,10 @@
             scope: this
         });
     },
-
+    
     /**
      * Method: moveGriddedTiles
-     *
+     * 
      * Parameters:
      * bounds - {<OpenLayers.Bounds>}
      */
@@ -27146,7 +29043,7 @@
         var buffer = this.buffer || 1;
         while (true) {
             var tlLayer = this.grid[0][0].position;
-            var tlViewPort =
+            var tlViewPort = 
                 this.map.getViewPortPxFromLayerPx(tlLayer);
             if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
                 this.shiftColumn(true);
@@ -27215,7 +29112,7 @@
             var row = this.grid[i];
             var modelTileIndex = (prepend) ? 0 : (row.length - 1);
             var modelTile = row[modelTileIndex];
-
+            
             var bounds = modelTile.bounds.clone();
             var position = modelTile.position.clone();
             bounds.left = bounds.left + deltaLon;
@@ -27231,18 +29128,18 @@
             }
         }
     },
-
+    
     /**
      * Method: removeExcessTiles
      * When the size of the map or the buffer changes, we may need to
      *     remove some excess rows and columns.
-     *
+     * 
      * Parameters:
      * rows - {Integer} Maximum number of rows we want our grid to have.
      * colums - {Integer} Maximum number of columns we want our grid to have.
      */
     removeExcessTiles: function(rows, columns) {
-
+        
         // remove extra rows
         while (this.grid.length > rows) {
             var row = this.grid.pop();
@@ -27252,7 +29149,7 @@
                 tile.destroy();
             }
         }
-
+        
         // remove extra columns
         while (this.grid[0].length > columns) {
             for (var i=0, l=this.grid.length; i<l; i++) {
@@ -27275,7 +29172,7 @@
             this.setTileSize();
         }
     },
-
+    
     /**
      * APIMethod: getTileBounds
      * Returns The tile bounds for a layer given a pixel location.
@@ -27304,26 +29201,28 @@
                                      tileLeft + tileMapWidth,
                                      tileBottom + tileMapHeight);
     },
-
+    
     CLASS_NAME: "OpenLayers.Layer.Grid"
 });
 /* ======================================================================
     OpenLayers/Layer/VirtualEarth.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
 /**
+ * @requires OpenLayers/Layer/SphericalMercator.js
  * @requires OpenLayers/Layer/EventPane.js
  * @requires OpenLayers/Layer/FixedZoomLevels.js
  */
 
 /**
  * Class: OpenLayers.Layer.VirtualEarth
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Layer.EventPane>
  *  - <OpenLayers.Layer.FixedZoomLevels>
@@ -27331,42 +29230,44 @@
 OpenLayers.Layer.VirtualEarth = OpenLayers.Class(
     OpenLayers.Layer.EventPane,
     OpenLayers.Layer.FixedZoomLevels, {
-
-    /**
+    
+    /** 
      * Constant: MIN_ZOOM_LEVEL
-     * {Integer} 1
+     * {Integer} 1 
      */
     MIN_ZOOM_LEVEL: 1,
-
-    /**
+    
+    /** 
      * Constant: MAX_ZOOM_LEVEL
-     * {Integer} 17
+     * {Integer} 19
      */
-    MAX_ZOOM_LEVEL: 17,
+    MAX_ZOOM_LEVEL: 19,
 
-    /**
+    /** 
      * Constant: RESOLUTIONS
      * {Array(Float)} Hardcode these resolutions so that they are more closely
      *                tied with the standard wms projection
      */
     RESOLUTIONS: [
-        1.40625,
-        0.703125,
-        0.3515625,
-        0.17578125,
-        0.087890625,
+        1.40625, 
+        0.703125, 
+        0.3515625, 
+        0.17578125, 
+        0.087890625, 
         0.0439453125,
-        0.02197265625,
-        0.010986328125,
-        0.0054931640625,
+        0.02197265625, 
+        0.010986328125, 
+        0.0054931640625, 
         0.00274658203125,
-        0.001373291015625,
-        0.0006866455078125,
-        0.00034332275390625,
-        0.000171661376953125,
-        0.0000858306884765625,
+        0.001373291015625, 
+        0.0006866455078125, 
+        0.00034332275390625, 
+        0.000171661376953125, 
+        0.0000858306884765625, 
         0.00004291534423828125,
-        0.00002145767211914062
+        0.00002145767211914062, 
+        0.00001072883605957031,
+        0.00000536441802978515
     ],
 
     /**
@@ -27376,39 +29277,47 @@
     type: null,
 
     /**
+     * APIProperty: wrapDateLine
+     * {Boolean} Allow user to pan forever east/west.  Default is true.  
+     *     Setting this to false only restricts panning if 
+     *     <sphericalMercator> is true. 
+     */
+    wrapDateLine: true,
+
+    /**
      * APIProperty: sphericalMercator
      * {Boolean} Should the map act as a mercator-projected map? This will
      *     cause all interactions with the map to be in the actual map
      *     projection, which allows support for vector drawing, overlaying
-     *     other maps, etc.
+     *     other maps, etc. 
      */
     sphericalMercator: false,
-
+    
     /**
      * APIProperty: animationEnabled
      * {Boolean} If set to true, the transition between zoom levels will be
      *     animated. Set to false to match the zooming experience of other
      *     layer types. Default is true.
      */
-    animationEnabled: true,
+    animationEnabled: true, 
 
-    /**
+    /** 
      * Constructor: OpenLayers.Layer.VirtualEarth
-     *
+     * 
      * Parameters:
      * name - {String}
      * options - {Object}
      */
     initialize: function(name, options) {
         OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
-        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
+        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, 
                                                                     arguments);
         if(this.sphericalMercator) {
             OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
             this.initMercatorParameters();
         }
     },
-
+    
     /**
      * Method: loadMapObject
      */
@@ -27428,23 +29337,21 @@
         if (this.mapObject != null) {
             try { // this is to catch a Mozilla bug without falling apart
 
-                // The fourth argument is whether the map is 'fixed' -- not
-                // draggable. See:
+                // The fourth argument is whether the map is 'fixed' -- not 
+                // draggable. See: 
                 // http://blogs.msdn.com/virtualearth/archive/2007/09/28/locking-a-virtual-earth-map.aspx
                 //
                 this.mapObject.LoadMap(null, null, this.type, true);
-                this.mapObject.AttachEvent("onmousedown", function() {return true; });
+                this.mapObject.AttachEvent("onmousedown", OpenLayers.Function.True);
 
             } catch (e) { }
-            this.mapObject.AttachEvent("onresize",
-                OpenLayers.Function.bindAsEventListener(this.redrawDependentLayers, this));
             this.mapObject.HideDashboard();
             if(typeof this.mapObject.SetAnimationEnabled == "function") {
                 this.mapObject.SetAnimationEnabled(this.animationEnabled);
             }
         }
 
-        //can we do smooth panning? this is an unpublished method, so we need
+        //can we do smooth panning? this is an unpublished method, so we need 
         // to be careful
         if ( !this.mapObject ||
              !this.mapObject.vemapcontrol ||
@@ -27455,35 +29362,18 @@
         }
 
     },
-
-    /**
-     * Method: redrawDependentLayers
-     */
-    redrawDependentLayers: function(event) {
-        if(this.isBaseLayer)
-        {
-            for(var i=0, len=this.map.layers.length; i<len; i++)
-            {
-                var otherLayer = this.map.layers[i];
-                if(otherLayer != this)
-                {
-                    otherLayer.redraw();
-                }
-            }
-        }
-    },
-
-    /**
-     * Method: onMapResize
-     */
-    onMapResize: function() {
-        this.mapObject.Resize(this.map.size.w, this.map.size.h);
-    },
 
     /**
+     * Method: onMapResize
+     */
+    onMapResize: function() {
+        this.mapObject.Resize(this.map.size.w, this.map.size.h);
+    },
+
+    /** 
      * APIMethod: getWarningHTML
-     *
-     * Returns:
+     * 
+     * Returns: 
      * {String} String with information on why layer is broken, how to get
      *          it working.
      */
@@ -27504,22 +29394,22 @@
 
   // Get&Set Center, Zoom
 
-    /**
+    /** 
      * APIMethod: setMapObjectCenter
      * Set the mapObject to the specified center and zoom
-     *
+     * 
      * Parameters:
      * center - {Object} MapObject LonLat format
      * zoom - {int} MapObject zoom format
      */
     setMapObjectCenter: function(center, zoom) {
-        this.mapObject.SetCenterAndZoom(center, zoom);
+        this.mapObject.SetCenterAndZoom(center, zoom); 
     },
-
+   
     /**
      * APIMethod: getMapObjectCenter
-     *
-     * Returns:
+     * 
+     * Returns: 
      * {Object} The mapObject's current center in Map Object format
      */
     getMapObjectCenter: function() {
@@ -27528,7 +29418,7 @@
 
     /**
      * APIMethod: dragPanMapObject
-     *
+     * 
      * Parameters:
      * dX - {Integer}
      * dY - {Integer}
@@ -27537,9 +29427,9 @@
         this.mapObject.vemapcontrol.PanMap(dX, -dY);
     },
 
-    /**
+    /** 
      * APIMethod: getMapObjectZoom
-     *
+     * 
      * Returns:
      * {Integer} The mapObject's current zoom, in Map Object format
      */
@@ -27549,29 +29439,29 @@
 
 
   // LonLat - Pixel Translation
-
+  
     /**
      * APIMethod: getMapObjectLonLatFromMapObjectPixel
-     *
+     * 
      * Parameters:
      * moPixel - {Object} MapObject Pixel format
-     *
+     * 
      * Returns:
      * {Object} MapObject LonLat translated from MapObject Pixel
      */
     getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
         //the conditional here is to test if we are running the v6 of VE
-        return (typeof VEPixel != 'undefined')
+        return (typeof VEPixel != 'undefined') 
             ? this.mapObject.PixelToLatLong(moPixel)
             : this.mapObject.PixelToLatLong(moPixel.x, moPixel.y);
     },
 
     /**
      * APIMethod: getMapObjectPixelFromMapObjectLonLat
-     *
+     * 
      * Parameters:
      * moLonLat - {Object} MapObject LonLat format
-     *
+     * 
      * Returns:
      * {Object} MapObject Pixel transtlated from MapObject LonLat
      */
@@ -27588,44 +29478,44 @@
 
 
   // LonLat
-
+    
     /**
      * APIMethod: getLongitudeFromMapObjectLonLat
-     *
+     * 
      * Parameters:
      * moLonLat - {Object} MapObject LonLat format
-     *
+     * 
      * Returns:
      * {Float} Longitude of the given MapObject LonLat
      */
     getLongitudeFromMapObjectLonLat: function(moLonLat) {
-        return this.sphericalMercator ?
+        return this.sphericalMercator ? 
             this.forwardMercator(moLonLat.Longitude, moLonLat.Latitude).lon :
             moLonLat.Longitude;
     },
 
     /**
      * APIMethod: getLatitudeFromMapObjectLonLat
-     *
+     * 
      * Parameters:
      * moLonLat - {Object} MapObject LonLat format
-     *
+     * 
      * Returns:
      * {Float} Latitude of the given MapObject LonLat
      */
     getLatitudeFromMapObjectLonLat: function(moLonLat) {
-        return this.sphericalMercator ?
+        return this.sphericalMercator ? 
             this.forwardMercator(moLonLat.Longitude, moLonLat.Latitude).lat :
             moLonLat.Latitude;
     },
 
     /**
      * APIMethod: getMapObjectLonLatFromLonLat
-     *
+     * 
      * Parameters:
      * lon - {Float}
      * lat - {Float}
-     *
+     * 
      * Returns:
      * {Object} MapObject LonLat built from lon and lat params
      */
@@ -27641,13 +29531,13 @@
     },
 
   // Pixel
-
+    
     /**
      * APIMethod: getXFromMapObjectPixel
-     *
+     * 
      * Parameters:
      * moPixel - {Object} MapObject Pixel format
-     *
+     * 
      * Returns:
      * {Integer} X value of the MapObject Pixel
      */
@@ -27657,10 +29547,10 @@
 
     /**
      * APIMethod: getYFromMapObjectPixel
-     *
+     * 
      * Parameters:
      * moPixel - {Object} MapObject Pixel format
-     *
+     * 
      * Returns:
      * {Integer} Y value of the MapObject Pixel
      */
@@ -27670,11 +29560,11 @@
 
     /**
      * APIMethod: getMapObjectPixelFromXY
-     *
+     * 
      * Parameters:
      * x - {Integer}
      * y - {Integer}
-     *
+     * 
      * Returns:
      * {Object} MapObject Pixel from x and y parameters
      */
@@ -27690,59 +29580,61 @@
     OpenLayers/Layer/Yahoo.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
 /**
+ * @requires OpenLayers/Layer/SphericalMercator.js
  * @requires OpenLayers/Layer/EventPane.js
  * @requires OpenLayers/Layer/FixedZoomLevels.js
  */
 
 /**
  * Class: OpenLayers.Layer.Yahoo
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Layer.EventPane>
  *  - <OpenLayers.Layer.FixedZoomLevels>
  */
 OpenLayers.Layer.Yahoo = OpenLayers.Class(
   OpenLayers.Layer.EventPane, OpenLayers.Layer.FixedZoomLevels, {
-
-    /**
+    
+    /** 
      * Constant: MIN_ZOOM_LEVEL
-     * {Integer} 0
+     * {Integer} 0 
      */
     MIN_ZOOM_LEVEL: 0,
-
-    /**
+    
+    /** 
      * Constant: MAX_ZOOM_LEVEL
      * {Integer} 17
      */
     MAX_ZOOM_LEVEL: 17,
 
-    /**
+    /** 
      * Constant: RESOLUTIONS
      * {Array(Float)} Hardcode these resolutions so that they are more closely
      *                tied with the standard wms projection
      */
     RESOLUTIONS: [
-        1.40625,
-        0.703125,
-        0.3515625,
-        0.17578125,
-        0.087890625,
+        1.40625, 
+        0.703125, 
+        0.3515625, 
+        0.17578125, 
+        0.087890625, 
         0.0439453125,
-        0.02197265625,
-        0.010986328125,
-        0.0054931640625,
-        0.00274658203125,
-        0.001373291015625,
-        0.0006866455078125,
-        0.00034332275390625,
-        0.000171661376953125,
-        0.0000858306884765625,
+        0.02197265625, 
+        0.010986328125, 
+        0.0054931640625, 
+        0.00274658203125, 
+        0.001373291015625, 
+        0.0006866455078125, 
+        0.00034332275390625, 
+        0.000171661376953125, 
+        0.0000858306884765625, 
         0.00004291534423828125,
         0.00002145767211914062,
         0.00001072883605957031
@@ -27753,69 +29645,77 @@
      * {YahooMapType}
      */
     type: null,
+    
+    /**
+     * APIProperty: wrapDateLine
+     * {Boolean} Allow user to pan forever east/west.  Default is true.  
+     *     Setting this to false only restricts panning if 
+     *     <sphericalMercator> is true. 
+     */
+    wrapDateLine: true,
 
     /**
      * APIProperty: sphericalMercator
      * {Boolean} Should the map act as a mercator-projected map? This will
      * cause all interactions with the map to be in the actual map projection,
-     * which allows support for vector drawing, overlaying other maps, etc.
+     * which allows support for vector drawing, overlaying other maps, etc. 
      */
-    sphericalMercator: false,
+    sphericalMercator: false, 
 
-    /**
+    /** 
      * Constructor: OpenLayers.Layer.Yahoo
-     *
+     * 
      * Parameters:
      * name - {String}
      * options - {Object}
      */
     initialize: function(name, options) {
         OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
-        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
+        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, 
                                                                     arguments);
         if(this.sphericalMercator) {
             OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
             this.initMercatorParameters();
         }
     },
-
+    
     /**
      * Method: loadMapObject
      */
     loadMapObject:function() {
-        try { //do not crash!
+        try { //do not crash! 
             var size = this.getMapObjectSizeFromOLSize(this.map.getSize());
             this.mapObject = new YMap(this.div, this.type, size);
             this.mapObject.disableKeyControls();
             this.mapObject.disableDragMap();
 
             //can we do smooth panning? (moveByXY is not an API function)
-            if ( !this.mapObject.moveByXY ||
+            if ( !this.mapObject.moveByXY || 
                  (typeof this.mapObject.moveByXY != "function" ) ) {
 
                 this.dragPanMapObject = null;
-            }
+            }                
         } catch(e) {}
     },
 
     /**
      * Method: onMapResize
-     *
+     * 
      */
     onMapResize: function() {
         try {
             var size = this.getMapObjectSizeFromOLSize(this.map.getSize());
             this.mapObject.resizeTo(size);
-        } catch(e) {}
-    },
-
-
-    /**
+        } catch(e) {}     
+    },    
+    
+    
+    /** 
      * APIMethod: setMap
      * Overridden from EventPane because we need to remove this yahoo event
-     *     pane which prohibits our drag and drop, and we can only do this
+     *     pane which prohibits our drag and drop, and we can only do this 
      *     once the map has been loaded and centered.
-     *
+     * 
      * Parameters:
      * map - {<OpenLayers.Map>}
      */
@@ -27825,7 +29725,7 @@
         this.map.events.register("moveend", this, this.fixYahooEventPane);
     },
 
-    /**
+    /** 
      * Method: fixYahooEventPane
      * The map has been centered, so the mysterious yahoo eventpane has been
      *     added. we remove it so that it doesnt mess with *our* event pane.
@@ -27836,15 +29736,15 @@
             if (yahooEventPane.parentNode != null) {
                 yahooEventPane.parentNode.removeChild(yahooEventPane);
             }
-            this.map.events.unregister("moveend", this,
+            this.map.events.unregister("moveend", this, 
                                        this.fixYahooEventPane);
         }
     },
 
-    /**
+    /** 
      * APIMethod: getWarningHTML
-     *
-     * Returns:
+     * 
+     * Returns: 
      * {String} String with information on why layer is broken, how to get
      *          it working.
      */
@@ -27858,7 +29758,7 @@
   /*                                                      */
   /*             Translation Functions                    */
   /*                                                      */
-  /*    The following functions translate GMaps and OL    */
+  /*    The following functions translate GMaps and OL    */ 
   /*     formats for Pixel, LonLat, Bounds, and Zoom      */
   /*                                                      */
   /********************************************************/
@@ -27867,13 +29767,13 @@
   //
   // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
   //
-
+  
     /**
      * APIMethod: getOLZoomFromMapObjectZoom
-     *
+     * 
      * Parameters:
      * gZoom - {Integer}
-     *
+     * 
      * Returns:
      * {Integer} An OpenLayers Zoom level, translated from the passed in gZoom
      *           Returns null if null value is passed in.
@@ -27886,19 +29786,19 @@
         }
         return zoom;
     },
-
+    
     /**
      * APIMethod: getMapObjectZoomFromOLZoom
-     *
+     * 
      * Parameters:
      * olZoom - {Integer}
-     *
+     * 
      * Returns:
      * {Integer} A MapObject level, translated from the passed in olZoom
      *           Returns null if null value is passed in
      */
     getMapObjectZoomFromOLZoom: function(olZoom) {
-        var zoom = null;
+        var zoom = null; 
         if (olZoom != null) {
             zoom = OpenLayers.Layer.FixedZoomLevels.prototype.getMapObjectZoomFromOLZoom.apply(this, [olZoom]);
             zoom = 18 - zoom;
@@ -27915,22 +29815,22 @@
 
   // Get&Set Center, Zoom
 
-    /**
+    /** 
      * APIMethod: setMapObjectCenter
      * Set the mapObject to the specified center and zoom
-     *
+     * 
      * Parameters:
      * center - {Object} MapObject LonLat format
      * zoom - {int} MapObject zoom format
      */
     setMapObjectCenter: function(center, zoom) {
-        this.mapObject.drawZoomAndCenter(center, zoom);
+        this.mapObject.drawZoomAndCenter(center, zoom); 
     },
-
+   
     /**
      * APIMethod: getMapObjectCenter
-     *
-     * Returns:
+     * 
+     * Returns: 
      * {Object} The mapObject's current center in Map Object format
      */
     getMapObjectCenter: function() {
@@ -27939,7 +29839,7 @@
 
     /**
      * APIMethod: dragPanMapObject
-     *
+     * 
      * Parameters:
      * dX - {Integer}
      * dY - {Integer}
@@ -27950,10 +29850,10 @@
             'y': dY
         });
     },
-
-    /**
+    
+    /** 
      * APIMethod: getMapObjectZoom
-     *
+     * 
      * Returns:
      * {Integer} The mapObject's current zoom, in Map Object format
      */
@@ -27963,13 +29863,13 @@
 
 
   // LonLat - Pixel Translation
-
+  
     /**
      * APIMethod: getMapObjectLonLatFromMapObjectPixel
-     *
+     * 
      * Parameters:
      * moPixel - {Object} MapObject Pixel format
-     *
+     * 
      * Returns:
      * {Object} MapObject LonLat translated from MapObject Pixel
      */
@@ -27979,10 +29879,10 @@
 
     /**
      * APIMethod: getMapObjectPixelFromMapObjectLonLat
-     *
+     * 
      * Parameters:
      * moLonLat - {Object} MapObject LonLat format
-     *
+     * 
      * Returns:
      * {Object} MapObject Pixel transtlated from MapObject LonLat
      */
@@ -27999,44 +29899,44 @@
 
 
   // LonLat
-
+    
     /**
      * APIMethod: getLongitudeFromMapObjectLonLat
-     *
+     * 
      * Parameters:
      * moLonLat - {Object} MapObject LonLat format
-     *
+     * 
      * Returns:
      * {Float} Longitude of the given MapObject LonLat
      */
     getLongitudeFromMapObjectLonLat: function(moLonLat) {
-        return this.sphericalMercator ?
+        return this.sphericalMercator ? 
             this.forwardMercator(moLonLat.Lon, moLonLat.Lat).lon :
             moLonLat.Lon;
     },
 
     /**
      * APIMethod: getLatitudeFromMapObjectLonLat
-     *
+     * 
      * Parameters:
      * moLonLat - {Object} MapObject LonLat format
-     *
+     * 
      * Returns:
      * {Float} Latitude of the given MapObject LonLat
      */
     getLatitudeFromMapObjectLonLat: function(moLonLat) {
-        return this.sphericalMercator ?
+        return this.sphericalMercator ? 
             this.forwardMercator(moLonLat.Lon, moLonLat.Lat).lat :
             moLonLat.Lat;
     },
 
     /**
      * APIMethod: getMapObjectLonLatFromLonLat
-     *
+     * 
      * Parameters:
      * lon - {Float}
      * lat - {Float}
-     *
+     * 
      * Returns:
      * {Object} MapObject LonLat built from lon and lat params
      */
@@ -28052,13 +29952,13 @@
     },
 
   // Pixel
-
+    
     /**
      * APIMethod: getXFromMapObjectPixel
-     *
+     * 
      * Parameters:
      * moPixel - {Object} MapObject Pixel format
-     *
+     * 
      * Returns:
      * {Integer} X value of the MapObject Pixel
      */
@@ -28068,10 +29968,10 @@
 
     /**
      * APIMethod: getYFromMapObjectPixel
-     *
+     * 
      * Parameters:
      * moPixel - {Object} MapObject Pixel format
-     *
+     * 
      * Returns:
      * {Integer} Y value of the MapObject Pixel
      */
@@ -28081,570 +29981,46 @@
 
     /**
      * APIMethod: getMapObjectPixelFromXY
-     *
+     * 
      * Parameters:
      * x - {Integer}
      * y - {Integer}
-     *
+     * 
      * Returns:
      * {Object} MapObject Pixel from x and y parameters
      */
     getMapObjectPixelFromXY: function(x, y) {
         return new YCoordPoint(x, y);
     },
-
+    
   // Size
-
+  
     /**
      * APIMethod: getMapObjectSizeFromOLSize
-     *
+     * 
      * Parameters:
      * olSize - {<OpenLayers.Size>}
-     *
+     * 
      * Returns:
      * {Object} MapObject Size from olSize parameter
      */
     getMapObjectSizeFromOLSize: function(olSize) {
         return new YSize(olSize.w, olSize.h);
     },
-
+    
     CLASS_NAME: "OpenLayers.Layer.Yahoo"
 });
 /* ======================================================================
-    OpenLayers/Protocol/HTTP.js
+    OpenLayers/Style.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
-/**
- * @requires OpenLayers/Protocol.js
- * @requires OpenLayers/Feature/Vector.js
- */
 
 /**
- * Class: OpenLayers.Protocol.HTTP
- * A basic HTTP protocol for vector layers.  Create a new instance with the
- *     <OpenLayers.Protocol.HTTP> constructor.
- *
- * Inherits from:
- *  - <OpenLayers.Protocol>
- */
-OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
-
-    /**
-     * Property: url
-     * {String} Service URL, read-only, set through the options
-     *     passed to constructor.
-     */
-    url: null,
-
-    /**
-     * Property: headers
-     * {Object} HTTP request headers, read-only, set through the options
-     *     passed to the constructor,
-     *     Example: {'Content-Type': 'plain/text'}
-     */
-    headers: null,
-
-    /**
-     * Property: params
-     * {Object} Parameters of GET requests, read-only, set through the options
-     *     passed to the constructor,
-     *     Example: {'bbox': '5,5,5,5'}
-     */
-    params: null,
-
-    /**
-     * Property: callback
-     * {Object} Function to be called when the <read>, <create>,
-     *     <update>, <delete> or <commit> operation completes, read-only,
-     *     set through the options passed to the constructor.
-     */
-    callback: null,
-
-    /**
-     * Property: scope
-     * {Object} Callback execution scope, read-only, set through the
-     *     options passed to the constructor.
-     */
-    scope: null,
-
-    /**
-     * Property: readWithPOST
-     * {Boolean} true if read operations are done with POST requests
-     *     instead of GET, defaults to false.
-     */
-    readWithPOST: false,
-
-    /**
-     * Constructor: OpenLayers.Protocol.HTTP
-     * A class for giving layers generic HTTP protocol.
-     *
-     * Parameters:
-     * options - {Object} Optional object whose properties will be set on the
-     *     instance.
-     *
-     * Valid options include:
-     * url - {String}
-     * headers - {Object}
-     * params - {Object}
-     * format - {<OpenLayers.Format>}
-     * callback - {Function}
-     * scope - {Object}
-     */
-    initialize: function(options) {
-        this.params = {};
-        this.headers = {};
-        OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
-    },
-
-    /**
-     * APIMethod: destroy
-     * Clean up the protocol.
-     */
-    destroy: function() {
-        this.params = null;
-        this.headers = null;
-        OpenLayers.Protocol.prototype.destroy.apply(this);
-    },
-
-    /**
-     * Method: createCallback
-     * Returns a function that applies the given public method with resp and
-     *     options arguments.
-     *
-     * Parameters:
-     * method - {Function} The method to be applied by the callback.
-     * response - {<OpenLayers.Protocol.Response>} The protocol response object.
-     * options - {Object} Options sent to the protocol method (read, create,
-     *     update, or delete).
-     */
-    createCallback: function(method, response, options) {
-        return OpenLayers.Function.bind(function() {
-            method.apply(this, [response, options]);
-        }, this);
-    },
-
-    /**
-     * APIMethod: read
-     * Construct a request for reading new features.
-     *
-     * Parameters:
-     * options - {Object} Optional object for configuring the request.
-     *     This object is modified and should not be reused.
-     *
-     * Valid options:
-     * url - {String} Url for the request.
-     * params - {Object} Parameters to get serialized as a query string.
-     * headers - {Object} Headers to be set on the request.
-     * filter - {<OpenLayers.Filter.BBOX>} If a bbox filter is sent, it will be
-     *     serialized according to the OpenSearch Geo extension
-     *     (bbox=minx,miny,maxx,maxy).  Note that a BBOX filter as the child
-     *     of a logical filter will not be serialized.
-     * readWithPOST - {Boolean} If the request should be done with POST.
-     *
-     * Returns:
-     * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
-     *     references the HTTP request, this object is also passed to the
-     *     callback function when the request completes, its "features" property
-     *     is then populated with the the features received from the server.
-     */
-    read: function(options) {
-        options = OpenLayers.Util.applyDefaults(options, this.options);
-        var readWithPOST = (options.readWithPOST !== undefined) ?
-                           options.readWithPOST : this.readWithPOST;
-        var resp = new OpenLayers.Protocol.Response({requestType: "read"});
-
-        if(options.filter && options.filter instanceof OpenLayers.Filter.Spatial) {
-            if(options.filter.type == OpenLayers.Filter.Spatial.BBOX) {
-                options.params = OpenLayers.Util.extend(options.params, {
-                    bbox: options.filter.value.toArray()
-                });
-            }
-        }
-
-        if(readWithPOST) {
-            resp.priv = OpenLayers.Request.POST({
-                url: options.url,
-                callback: this.createCallback(this.handleRead, resp, options),
-                data: OpenLayers.Util.getParameterString(options.params),
-                headers: {
-                    "Content-Type": "application/x-www-form-urlencoded"
-                }
-            });
-        } else {
-            resp.priv = OpenLayers.Request.GET({
-                url: options.url,
-                callback: this.createCallback(this.handleRead, resp, options),
-                params: options.params,
-                headers: options.headers
-            });
-        }
-
-        return resp;
-    },
-
-    /**
-     * Method: handleRead
-     * Individual callbacks are created for read, create and update, should
-     *     a subclass need to override each one separately.
-     *
-     * Parameters:
-     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
-     *     the user callback.
-     * options - {Object} The user options passed to the read call.
-     */
-    handleRead: function(resp, options) {
-        this.handleResponse(resp, options);
-    },
-
-    /**
-     * APIMethod: create
-     * Construct a request for writing newly created features.
-     *
-     * Parameters:
-     * features - {Array({<OpenLayers.Feature.Vector>})} or
-     *     {<OpenLayers.Feature.Vector>}
-     * options - {Object} Optional object for configuring the request.
-     *     This object is modified and should not be reused.
-     *
-     * Returns:
-     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
-     *     object, whose "priv" property references the HTTP request, this
-     *     object is also passed to the callback function when the request
-     *     completes, its "features" property is then populated with the
-     *     the features received from the server.
-     */
-    create: function(features, options) {
-        options = OpenLayers.Util.applyDefaults(options, this.options);
-
-        var resp = new OpenLayers.Protocol.Response({
-            reqFeatures: features,
-            requestType: "create"
-        });
-
-        resp.priv = OpenLayers.Request.POST({
-            url: options.url,
-            callback: this.createCallback(this.handleCreate, resp, options),
-            headers: options.headers,
-            data: this.format.write(features)
-        });
-
-        return resp;
-    },
-
-    /**
-     * Method: handleCreate
-     * Called the the request issued by <create> is complete.  May be overridden
-     *     by subclasses.
-     *
-     * Parameters:
-     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
-     *     any user callback.
-     * options - {Object} The user options passed to the create call.
-     */
-    handleCreate: function(resp, options) {
-        this.handleResponse(resp, options);
-    },
-
-    /**
-     * APIMethod: update
-     * Construct a request updating modified feature.
-     *
-     * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>}
-     * options - {Object} Optional object for configuring the request.
-     *     This object is modified and should not be reused.
-     *
-     * Returns:
-     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
-     *     object, whose "priv" property references the HTTP request, this
-     *     object is also passed to the callback function when the request
-     *     completes, its "features" property is then populated with the
-     *     the feature received from the server.
-     */
-    update: function(feature, options) {
-        var url = options.url || feature.url || this.options.url;
-        options = OpenLayers.Util.applyDefaults(options, this.options);
-
-        var resp = new OpenLayers.Protocol.Response({
-            reqFeatures: feature,
-            requestType: "update"
-        });
-
-        resp.priv = OpenLayers.Request.PUT({
-            url: url,
-            callback: this.createCallback(this.handleUpdate, resp, options),
-            headers: options.headers,
-            data: this.format.write(feature)
-        });
-
-        return resp;
-    },
-
-    /**
-     * Method: handleUpdate
-     * Called the the request issued by <update> is complete.  May be overridden
-     *     by subclasses.
-     *
-     * Parameters:
-     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
-     *     any user callback.
-     * options - {Object} The user options passed to the update call.
-     */
-    handleUpdate: function(resp, options) {
-        this.handleResponse(resp, options);
-    },
-
-    /**
-     * APIMethod: delete
-     * Construct a request deleting a removed feature.
-     *
-     * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>}
-     * options - {Object} Optional object for configuring the request.
-     *     This object is modified and should not be reused.
-     *
-     * Returns:
-     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
-     *     object, whose "priv" property references the HTTP request, this
-     *     object is also passed to the callback function when the request
-     *     completes.
-     */
-    "delete": function(feature, options) {
-        var url = options.url || feature.url || this.options.url;
-        options = OpenLayers.Util.applyDefaults(options, this.options);
-
-        var resp = new OpenLayers.Protocol.Response({
-            reqFeatures: feature,
-            requestType: "delete"
-        });
-
-        resp.priv = OpenLayers.Request.DELETE({
-            url: url,
-            callback: this.createCallback(this.handleDelete, resp, options),
-            headers: options.headers
-        });
-
-        return resp;
-    },
-
-    /**
-     * Method: handleDelete
-     * Called the the request issued by <delete> is complete.  May be overridden
-     *     by subclasses.
-     *
-     * Parameters:
-     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
-     *     any user callback.
-     * options - {Object} The user options passed to the delete call.
-     */
-    handleDelete: function(resp, options) {
-        this.handleResponse(resp, options);
-    },
-
-    /**
-     * Method: handleResponse
-     * Called by CRUD specific handlers.
-     *
-     * Parameters:
-     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
-     *     any user callback.
-     * options - {Object} The user options passed to the create, read, update,
-     *     or delete call.
-     */
-    handleResponse: function(resp, options) {
-        var request = resp.priv;
-        if(options.callback) {
-            if(request.status >= 200 && request.status < 300) {
-                // success
-                if(resp.requestType != "delete") {
-                    resp.features = this.parseFeatures(request);
-                }
-                resp.code = OpenLayers.Protocol.Response.SUCCESS;
-            } else {
-                // failure
-                resp.code = OpenLayers.Protocol.Response.FAILURE;
-            }
-            options.callback.call(options.scope, resp);
-        }
-    },
-
-    /**
-     * Method: parseFeatures
-     * Read HTTP response body and return features.
-     *
-     * Parameters:
-     * request - {XMLHttpRequest} The request object
-     *
-     * Returns:
-     * {Array({<OpenLayers.Feature.Vector>})} or
-     *     {<OpenLayers.Feature.Vector>} Array of features or a single feature.
-     */
-    parseFeatures: function(request) {
-        var doc = request.responseXML;
-        if (!doc || !doc.documentElement) {
-            doc = request.responseText;
-        }
-        if (!doc || doc.length <= 0) {
-            return null;
-        }
-        return this.format.read(doc);
-    },
-
-    /**
-     * APIMethod: commit
-     * Iterate over each feature and take action based on the feature state.
-     *     Possible actions are create, update and delete.
-     *
-     * Parameters:
-     * features - {Array({<OpenLayers.Feature.Vector>})}
-     * options - {Object} Optional object for setting up intermediate commit
-     *     callbacks.
-     *
-     * Valid options:
-     * create - {Object} Optional object to be passed to the <create> method.
-     * update - {Object} Optional object to be passed to the <update> method.
-     * delete - {Object} Optional object to be passed to the <delete> method.
-     * callback - {Function} Optional function to be called when the commit
-     *     is complete.
-     * scope - {Object} Optional object to be set as the scope of the callback.
-     *
-     * Returns:
-     * {Array(<OpenLayers.Protocol.Response>)} An array of response objects,
-     *     one per request made to the server, each object's "priv" property
-     *     references the corresponding HTTP request.
-     */
-    commit: function(features, options) {
-        options = OpenLayers.Util.applyDefaults(options, this.options);
-        var resp = [], nResponses = 0;
-
-        // Divide up features before issuing any requests.  This properly
-        // counts requests in the event that any responses come in before
-        // all requests have been issued.
-        var types = {};
-        types[OpenLayers.State.INSERT] = [];
-        types[OpenLayers.State.UPDATE] = [];
-        types[OpenLayers.State.DELETE] = [];
-        var feature, list, requestFeatures = [];
-        for(var i=0, len=features.length; i<len; ++i) {
-            feature = features[i];
-            list = types[feature.state];
-            if(list) {
-                list.push(feature);
-                requestFeatures.push(feature);
-            }
-        }
-        // tally up number of requests
-        var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) +
-            types[OpenLayers.State.UPDATE].length +
-            types[OpenLayers.State.DELETE].length;
-
-        // This response will be sent to the final callback after all the others
-        // have been fired.
-        var success = true;
-        var finalResponse = new OpenLayers.Protocol.Response({
-            reqFeatures: requestFeatures
-        });
-
-        function insertCallback(response) {
-            var len = response.features ? response.features.length : 0;
-            var fids = new Array(len);
-            for(var i=0; i<len; ++i) {
-                fids[i] = response.features[i].fid;
-            }
-            finalResponse.insertIds = fids;
-            callback.apply(this, [response]);
-        }
-
-        function callback(response) {
-            this.callUserCallback(response, options);
-            success = success && response.success();
-            nResponses++;
-            if (nResponses >= nRequests) {
-                if (options.callback) {
-                    finalResponse.code = success ?
-                        OpenLayers.Protocol.Response.SUCCESS :
-                        OpenLayers.Protocol.Response.FAILURE;
-                    options.callback.apply(options.scope, [finalResponse]);
-                }
-            }
-        }
-
-        // start issuing requests
-        var queue = types[OpenLayers.State.INSERT];
-        if(queue.length > 0) {
-            resp.push(this.create(
-                queue, OpenLayers.Util.applyDefaults(
-                    {callback: insertCallback, scope: this}, options.create
-                )
-            ));
-        }
-        queue = types[OpenLayers.State.UPDATE];
-        for(var i=queue.length-1; i>=0; --i) {
-            resp.push(this.update(
-                queue[i], OpenLayers.Util.applyDefaults(
-                    {callback: callback, scope: this}, options.update
-                ))
-            );
-        }
-        queue = types[OpenLayers.State.DELETE];
-        for(var i=queue.length-1; i>=0; --i) {
-            resp.push(this["delete"](
-                queue[i], OpenLayers.Util.applyDefaults(
-                    {callback: callback, scope: this}, options["delete"]
-                ))
-            );
-        }
-        return resp;
-    },
-
-    /**
-     * APIMethod: abort
-     * Abort an ongoing request, the response object passed to
-     * this method must come from this HTTP protocol (as a result
-     * of a create, read, update, delete or commit operation).
-     *
-     * Parameters:
-     * response - {<OpenLayers.Protocol.Response>}
-     */
-    abort: function(response) {
-        if (response) {
-            response.priv.abort();
-        }
-    },
-
-    /**
-     * Method: callUserCallback
-     * This method is used from within the commit method each time an
-     *     an HTTP response is received from the server, it is responsible
-     *     for calling the user-supplied callbacks.
-     *
-     * Parameters:
-     * resp - {<OpenLayers.Protocol.Response>}
-     * options - {Object} The map of options passed to the commit call.
-     */
-    callUserCallback: function(resp, options) {
-        var opt = options[resp.requestType];
-        if(opt && opt.callback) {
-            opt.callback.call(opt.scope, resp);
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Protocol.HTTP"
-});
-/* ======================================================================
-    OpenLayers/Style.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
-  * full text of the license. */
-
-
-/**
  * @requires OpenLayers/Util.js
  * @requires OpenLayers/Feature/Vector.js
  */
@@ -28657,17 +30033,23 @@
 OpenLayers.Style = OpenLayers.Class({
 
     /**
+     * Property: id
+     * {String} A unique id for this session.
+     */
+    id: null,
+    
+    /**
      * APIProperty: name
      * {String}
      */
     name: null,
-
+    
     /**
      * Property: title
      * {String} Title of this style (set if included in SLD)
      */
     title: null,
-
+    
     /**
      * Property: description
      * {String} Description of this style (set if abstract is included in SLD)
@@ -28680,19 +30062,19 @@
      * according to the NamedLayer attribute of an SLD document.
      */
     layerName: null,
-
+    
     /**
      * APIProperty: isDefault
      * {Boolean}
      */
     isDefault: false,
-
-    /**
-     * Property: rules
+     
+    /** 
+     * Property: rules 
      * {Array(<OpenLayers.Rule>)}
      */
     rules: null,
-
+    
     /**
      * Property: context
      * {Object} An optional object with properties that symbolizers' property
@@ -28710,7 +30092,7 @@
      * rules defined.
      */
     defaultStyle: null,
-
+    
     /**
      * Property: defaultsPerSymbolizer
      * {Boolean} If set to true, the <defaultStyle> will extend the symbolizer
@@ -28719,16 +30101,16 @@
      * graphic set to true. Default is false.
      */
     defaultsPerSymbolizer: false,
-
+    
     /**
      * Property: propertyStyles
      * {Hash of Boolean} cache of style properties that need to be parsed for
      * propertyNames. Property names are keys, values won't be used.
      */
     propertyStyles: null,
+    
 
-
-    /**
+    /** 
      * Constructor: OpenLayers.Style
      * Creates a UserStyle.
      *
@@ -28743,7 +30125,7 @@
      * Valid options:
      * rules - {Array(<OpenLayers.Rule>)} List of rules to be added to the
      *     style.
-     *
+     * 
      * Return:
      * {<OpenLayers.Style>}
      */
@@ -28760,9 +30142,10 @@
         this.setDefaultStyle(style ||
                              OpenLayers.Feature.Vector.style["default"]);
 
+        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
     },
 
-    /**
+    /** 
      * APIMethod: destroy
      * nullify references to prevent circular references and memory leaks
      */
@@ -28774,22 +30157,22 @@
         this.rules = null;
         this.defaultStyle = null;
     },
-
+    
     /**
      * Method: createSymbolizer
      * creates a style by applying all feature-dependent rules to the base
      * style.
-     *
+     * 
      * Parameters:
      * feature - {<OpenLayers.Feature>} feature to evaluate rules for
-     *
+     * 
      * Returns:
      * {Object} symbolizer hash
      */
     createSymbolizer: function(feature) {
         var style = this.defaultsPerSymbolizer ? {} : this.createLiterals(
             OpenLayers.Util.extend({}, this.defaultStyle), feature);
-
+        
         var rules = this.rules;
 
         var rule, context;
@@ -28799,7 +30182,7 @@
             rule = rules[i];
             // does the rule apply?
             var applies = rule.evaluate(feature);
-
+            
             if(applies) {
                 if(rule instanceof OpenLayers.Rule && rule.elseFilter) {
                     elseRules.push(rule);
@@ -28809,7 +30192,7 @@
                 }
             }
         }
-
+        
         // if no other rules apply, apply the rules with else filters
         if(appliedRules == false && elseRules.length > 0) {
             appliedRules = true;
@@ -28822,10 +30205,10 @@
         if(rules.length > 0 && appliedRules == false) {
             style.display = "none";
         }
-
+        
         return style;
     },
-
+    
     /**
      * Method: applySymbolizer
      *
@@ -28843,7 +30226,7 @@
                 OpenLayers.Style.SYMBOLIZER_PREFIXES[0];
 
         var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer;
-
+        
         if(this.defaultsPerSymbolizer === true) {
             var defaults = this.defaultStyle;
             OpenLayers.Util.applyDefaults(symbolizer, {
@@ -28882,35 +30265,36 @@
         return this.createLiterals(
                 OpenLayers.Util.extend(style, symbolizer), feature);
     },
-
+    
     /**
      * Method: createLiterals
      * creates literals for all style properties that have an entry in
      * <this.propertyStyles>.
-     *
+     * 
      * Parameters:
      * style   - {Object} style to create literals for. Will be modified
      *           inline.
      * feature - {Object}
-     *
+     * 
      * Returns:
      * {Object} the modified style
      */
     createLiterals: function(style, feature) {
-        var context = this.context || feature.attributes || feature.data;
-
+        var context = OpenLayers.Util.extend({}, feature.attributes || feature.data);
+        OpenLayers.Util.extend(context, this.context);
+        
         for (var i in this.propertyStyles) {
-            style[i] = OpenLayers.Style.createLiteral(style[i], context, feature);
+            style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i);
         }
         return style;
     },
-
+    
     /**
      * Method: findPropertyStyles
      * Looks into all rules for this style and the defaultStyle to collect
      * all the style hash property names containing ${...} strings that have
      * to be replaced using the createLiteral method before returning them.
-     *
+     * 
      * Returns:
      * {Object} hash of property names that need createLiteral parsing. The
      * name of the property is the key, and the value is true;
@@ -28941,15 +30325,15 @@
         }
         return propertyStyles;
     },
-
+    
     /**
      * Method: addPropertyStyles
-     *
+     * 
      * Parameters:
      * propertyStyles - {Object} hash to add new property styles to. Will be
      *                  modified inline
      * symbolizer     - {Object} search this symbolizer for property styles
-     *
+     * 
      * Returns:
      * {Object} propertyStyles hash
      */
@@ -28964,39 +30348,39 @@
         }
         return propertyStyles;
     },
-
+    
     /**
      * APIMethod: addRules
      * Adds rules to this style.
-     *
+     * 
      * Parameters:
      * rules - {Array(<OpenLayers.Rule>)}
      */
     addRules: function(rules) {
-        this.rules = this.rules.concat(rules);
+        Array.prototype.push.apply(this.rules, rules);
         this.propertyStyles = this.findPropertyStyles();
     },
-
+    
     /**
      * APIMethod: setDefaultStyle
      * Sets the default style for this style object.
-     *
+     * 
      * Parameters:
      * style - {Object} Hash of style properties
      */
     setDefaultStyle: function(style) {
-        this.defaultStyle = style;
+        this.defaultStyle = style; 
         this.propertyStyles = this.findPropertyStyles();
     },
-
+        
     /**
      * Method: getSymbolizerPrefix
      * Returns the correct symbolizer prefix according to the
      * geometry type of the passed geometry
-     *
+     * 
      * Parameters:
      * geometry {<OpenLayers.Geometry>}
-     *
+     * 
      * Returns:
      * {String} key of the according symbolizer
      */
@@ -29008,7 +30392,30 @@
             }
         }
     },
-
+    
+    /**
+     * APIMethod: clone
+     * Clones this style.
+     * 
+     * Returns:
+     * {<OpenLayers.Style>} Clone of this style.
+     */
+    clone: function() {
+        var options = OpenLayers.Util.extend({}, this);
+        // clone rules
+        if(this.rules) {
+            options.rules = [];
+            for(var i=0, len=this.rules.length; i<len; ++i) {
+                options.rules.push(this.rules[i].clone());
+            }
+        }
+        // clone context
+        options.context = this.context && OpenLayers.Util.extend({}, this.context);
+        //clone default style
+        var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle);
+        return new OpenLayers.Style(defaultStyle, options);
+    },
+    
     CLASS_NAME: "OpenLayers.Style"
 });
 
@@ -29017,41 +30424,46 @@
  * Function: createLiteral
  * converts a style value holding a combination of PropertyName and Literal
  * into a Literal, taking the property values from the passed features.
- *
+ * 
  * Parameters:
  * value - {String} value to parse. If this string contains a construct like
  *         "foo ${bar}", then "foo " will be taken as literal, and "${bar}"
  *         will be replaced by the value of the "bar" attribute of the passed
  *         feature.
  * context - {Object} context to take attribute values from
- * feature - {OpenLayers.Feature.Vector} The feature that will be passed
- *     to <OpenLayers.String.format> for evaluating functions in the context.
- *
+ * feature - {<OpenLayers.Feature.Vector>} optional feature to pass to
+ *           <OpenLayers.String.format> for evaluating functions in the
+ *           context.
+ * property - {String} optional, name of the property for which the literal is
+ *            being created for evaluating functions in the context.
+ * 
  * Returns:
  * {String} the parsed value. In the example of the value parameter above, the
  * result would be "foo valueOfBar", assuming that the passed feature has an
  * attribute named "bar" with the value "valueOfBar".
  */
-OpenLayers.Style.createLiteral = function(value, context, feature) {
+OpenLayers.Style.createLiteral = function(value, context, feature, property) {
     if (typeof value == "string" && value.indexOf("${") != -1) {
-        value = OpenLayers.String.format(value, context, [feature]);
+        value = OpenLayers.String.format(value, context, [feature, property]);
         value = (isNaN(value) || !value) ? value : parseFloat(value);
     }
     return value;
 };
-
+    
 /**
  * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES
  * {Array} prefixes of the sld symbolizers. These are the
  * same as the main geometry types
  */
-OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text'];
+OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text',
+    'Raster'];
 /* ======================================================================
     OpenLayers/Control/Navigation.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -29064,21 +30476,21 @@
 /**
  * Class: OpenLayers.Control.Navigation
  * The navigation control handles map browsing with mouse events (dragging,
- *     double-clicking, and scrolling the wheel).  Create a new navigation
- *     control with the <OpenLayers.Control.Navigation> control.
- *
- *     Note that this control is added to the map by default (if no controls
- *     array is sent in the options object to the <OpenLayers.Map>
+ *     double-clicking, and scrolling the wheel).  Create a new navigation 
+ *     control with the <OpenLayers.Control.Navigation> control.  
+ * 
+ *     Note that this control is added to the map by default (if no controls 
+ *     array is sent in the options object to the <OpenLayers.Map> 
  *     constructor).
- *
+ * 
  * Inherits:
  *  - <OpenLayers.Control>
  */
 OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {
 
-    /**
+    /** 
      * Property: dragPan
-     * {<OpenLayers.Control.DragPan>}
+     * {<OpenLayers.Control.DragPan>} 
      */
     dragPan: null,
 
@@ -29089,16 +30501,36 @@
     dragPanOptions: null,
 
     /**
+     * APIProperty: documentDrag
+     * {Boolean} Allow panning of the map by dragging outside map viewport.
+     *     Default is false.
+     */
+    documentDrag: false,
+
+    /** 
      * Property: zoomBox
      * {<OpenLayers.Control.ZoomBox>}
      */
     zoomBox: null,
 
     /**
+     * APIProperty: zoomBoxEnabled
+     * {Boolean} Whether the user can draw a box to zoom
+     */
+    zoomBoxEnabled: true, 
+
+    /**
      * APIProperty: zoomWheelEnabled
      * {Boolean} Whether the mousewheel should zoom the map
      */
     zoomWheelEnabled: true,
+    
+    /**
+     * Property: mouseWheelOptions
+     * {Object} Options passed to the MouseWheel control (only useful if
+     *     <zoomWheelEnabled> is set to true)
+     */
+    mouseWheelOptions: null,
 
     /**
      * APIProperty: handleRightClicks
@@ -29109,18 +30541,25 @@
     /**
      * APIProperty: zoomBoxKeyMask
      * {Integer} <OpenLayers.Handler> key code of the key, which has to be
-     *    pressed, while drawing the zoom box with the mouse on the screen.
+     *    pressed, while drawing the zoom box with the mouse on the screen. 
      *    You should probably set handleRightClicks to true if you use this
      *    with MOD_CTRL, to disable the context menu for machines which use
      *    CTRL-Click as a right click.
      * Default: <OpenLayers.Handler.MOD_SHIFT
      */
     zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT,
+    
+    /**
+     * APIProperty: autoActivate
+     * {Boolean} Activate the control when it is added to a map.  Default is
+     *     true.
+     */
+    autoActivate: true,
 
     /**
      * Constructor: OpenLayers.Control.Navigation
      * Create a new navigation control
-     *
+     * 
      * Parameters:
      * options - {Object} An optional object whose properties will be set on
      *                    the control
@@ -29150,7 +30589,7 @@
         this.zoomBox = null;
         OpenLayers.Control.prototype.destroy.apply(this,arguments);
     },
-
+    
     /**
      * Method: activate
      */
@@ -29158,9 +30597,11 @@
         this.dragPan.activate();
         if (this.zoomWheelEnabled) {
             this.handlers.wheel.activate();
+        }    
+        this.handlers.click.activate();
+        if (this.zoomBoxEnabled) {
+            this.zoomBox.activate();
         }
-        this.handlers.click.activate();
-        this.zoomBox.activate();
         return OpenLayers.Control.prototype.activate.apply(this,arguments);
     },
 
@@ -29174,29 +30615,32 @@
         this.handlers.wheel.deactivate();
         return OpenLayers.Control.prototype.deactivate.apply(this,arguments);
     },
-
+    
     /**
      * Method: draw
      */
     draw: function() {
         // disable right mouse context menu for support of right click events
         if (this.handleRightClicks) {
-            this.map.viewPortDiv.oncontextmenu = function () { return false;};
+            this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False;
         }
 
-        var clickCallbacks = {
-            'dblclick': this.defaultDblClick,
-            'dblrightclick': this.defaultDblRightClick
+        var clickCallbacks = { 
+            'dblclick': this.defaultDblClick, 
+            'dblrightclick': this.defaultDblRightClick 
         };
         var clickOptions = {
-            'double': true,
+            'double': true, 
             'stopDouble': true
         };
         this.handlers.click = new OpenLayers.Handler.Click(
             this, clickCallbacks, clickOptions
         );
         this.dragPan = new OpenLayers.Control.DragPan(
-            OpenLayers.Util.extend({map: this.map}, this.dragPanOptions)
+            OpenLayers.Util.extend({
+                map: this.map,
+                documentDrag: this.documentDrag
+            }, this.dragPanOptions)
         );
         this.zoomBox = new OpenLayers.Control.ZoomBox(
                     {map: this.map, keyMask: this.zoomBoxKeyMask});
@@ -29204,42 +30648,45 @@
         this.zoomBox.draw();
         this.handlers.wheel = new OpenLayers.Handler.MouseWheel(
                                     this, {"up"  : this.wheelUp,
-                                           "down": this.wheelDown} );
-        this.activate();
+                                           "down": this.wheelDown},
+                                    this.mouseWheelOptions );
     },
 
     /**
-     * Method: defaultDblClick
-     *
+     * Method: defaultDblClick 
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     defaultDblClick: function (evt) {
-        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
+        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); 
         this.map.setCenter(newCenter, this.map.zoom + 1);
     },
 
     /**
-     * Method: defaultDblRightClick
-     *
+     * Method: defaultDblRightClick 
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     defaultDblRightClick: function (evt) {
-        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
+        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); 
         this.map.setCenter(newCenter, this.map.zoom - 1);
     },
-
+    
     /**
-     * Method: wheelChange
+     * Method: wheelChange  
      *
      * Parameters:
      * evt - {Event}
      * deltaZ - {Integer}
      */
     wheelChange: function(evt, deltaZ) {
-        var newZoom = this.map.getZoom() + deltaZ;
-        if (!this.map.isValidZoomLevel(newZoom)) {
+        var currentZoom = this.map.getZoom();
+        var newZoom = this.map.getZoom() + Math.round(deltaZ);
+        newZoom = Math.max(newZoom, 0);
+        newZoom = Math.min(newZoom, this.map.getNumZoomLevels());
+        if (newZoom === currentZoom) {
             return;
         }
         var size    = this.map.getSize();
@@ -29253,59 +30700,152 @@
         this.map.setCenter( newCenter, newZoom );
     },
 
-    /**
+    /** 
      * Method: wheelUp
      * User spun scroll wheel up
-     *
+     * 
      * Parameters:
      * evt - {Event}
+     * delta - {Integer}
      */
-    wheelUp: function(evt) {
-        this.wheelChange(evt, 1);
+    wheelUp: function(evt, delta) {
+        this.wheelChange(evt, delta || 1);
     },
 
-    /**
+    /** 
      * Method: wheelDown
      * User spun scroll wheel down
-     *
+     * 
      * Parameters:
      * evt - {Event}
+     * delta - {Integer}
      */
-    wheelDown: function(evt) {
-        this.wheelChange(evt, -1);
+    wheelDown: function(evt, delta) {
+        this.wheelChange(evt, delta || -1);
     },
-
+    
     /**
+     * Method: disableZoomBox
+     */
+    disableZoomBox : function() {
+        this.zoomBoxEnabled = false;
+        this.zoomBox.deactivate();       
+    },
+    
+    /**
+     * Method: enableZoomBox
+     */
+    enableZoomBox : function() {
+        this.zoomBoxEnabled = true;
+        if (this.active) {
+            this.zoomBox.activate();
+        }    
+    },
+    
+    /**
      * Method: disableZoomWheel
      */
-
+    
     disableZoomWheel : function() {
         this.zoomWheelEnabled = false;
-        this.handlers.wheel.deactivate();
+        this.handlers.wheel.deactivate();       
     },
-
+    
     /**
      * Method: enableZoomWheel
      */
-
+    
     enableZoomWheel : function() {
         this.zoomWheelEnabled = true;
         if (this.active) {
             this.handlers.wheel.activate();
-        }
+        }    
     },
 
     CLASS_NAME: "OpenLayers.Control.Navigation"
 });
 /* ======================================================================
-    OpenLayers/Geometry.js
+    OpenLayers/Filter.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
+
 /**
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Style.js
+ */
+
+/**
+ * Class: OpenLayers.Filter
+ * This class represents an OGC Filter.
+ */
+OpenLayers.Filter = OpenLayers.Class({
+    
+    /** 
+     * Constructor: OpenLayers.Filter
+     * This is an abstract class.  Create an instance of a filter subclass.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter>}
+     */
+    initialize: function(options) {
+        OpenLayers.Util.extend(this, options);
+    },
+
+    /** 
+     * APIMethod: destroy
+     * Remove reference to anything added.
+     */
+    destroy: function() {
+    },
+
+    /**
+     * APIMethod: evaluate
+     * Evaluates this filter in a specific context.  Should be implemented by
+     *     subclasses.
+     * 
+     * Parameters:
+     * context - {Object} Context to use in evaluating the filter.  If a vector
+     *     feature is provided, the feature.attributes will be used as context.
+     * 
+     * Returns:
+     * {Boolean} The filter applies.
+     */
+    evaluate: function(context) {
+        return true;
+    },
+    
+    /**
+     * APIMethod: clone
+     * Clones this filter. Should be implementted by subclasses.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter>} Clone of this filter.
+     */
+    clone: function() {
+        return null;
+    },
+    
+    CLASS_NAME: "OpenLayers.Filter"
+});
+/* ======================================================================
+    OpenLayers/Geometry.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+ 
+/**
  * @requires OpenLayers/Format/WKT.js
  * @requires OpenLayers/Feature/Vector.js
  */
@@ -29332,19 +30872,19 @@
     parent: null,
 
     /**
-     * Property: bounds
+     * Property: bounds 
      * {<OpenLayers.Bounds>} The bounds of this geometry
      */
     bounds: null,
 
     /**
      * Constructor: OpenLayers.Geometry
-     * Creates a geometry object.
+     * Creates a geometry object.  
      */
     initialize: function() {
         this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME+ "_");
     },
-
+    
     /**
      * Method: destroy
      * Destroy this geometry.
@@ -29353,31 +30893,31 @@
         this.id = null;
         this.bounds = null;
     },
-
+    
     /**
      * APIMethod: clone
      * Create a clone of this geometry.  Does not set any non-standard
      *     properties of the cloned geometry.
-     *
+     * 
      * Returns:
      * {<OpenLayers.Geometry>} An exact clone of this geometry.
      */
     clone: function() {
         return new OpenLayers.Geometry();
     },
-
+    
     /**
      * Set the bounds for this Geometry.
-     *
+     * 
      * Parameters:
-     * object - {<OpenLayers.Bounds>}
+     * object - {<OpenLayers.Bounds>} 
      */
     setBounds: function(bounds) {
         if (bounds) {
             this.bounds = bounds.clone();
         }
     },
-
+    
     /**
      * Method: clearBounds
      * Nullify this components bounds and that of its parent as well.
@@ -29386,16 +30926,16 @@
         this.bounds = null;
         if (this.parent) {
             this.parent.clearBounds();
-        }
+        }    
     },
-
+    
     /**
      * Method: extendBounds
-     * Extend the existing bounds to include the new bounds.
+     * Extend the existing bounds to include the new bounds. 
      * If geometry's bounds is not yet set, then set a new Bounds.
-     *
+     * 
      * Parameters:
-     * newBounds - {<OpenLayers.Bounds>}
+     * newBounds - {<OpenLayers.Bounds>} 
      */
     extendBounds: function(newBounds){
         var bounds = this.getBounds();
@@ -29405,12 +30945,12 @@
             this.bounds.extend(newBounds);
         }
     },
-
+    
     /**
      * APIMethod: getBounds
-     * Get the bounds for this Geometry. If bounds is not set, it
+     * Get the bounds for this Geometry. If bounds is not set, it 
      * is calculated again, this makes queries faster.
-     *
+     * 
      * Returns:
      * {<OpenLayers.Bounds>}
      */
@@ -29420,17 +30960,17 @@
         }
         return this.bounds;
     },
-
-    /**
+    
+    /** 
      * APIMethod: calculateBounds
-     * Recalculate the bounds for the geometry.
+     * Recalculate the bounds for the geometry. 
      */
     calculateBounds: function() {
         //
         // This should be overridden by subclasses.
         //
     },
-
+    
     /**
      * APIMethod: distanceTo
      * Calculate the closest distance between two geometries (on the x-y plane).
@@ -29441,7 +30981,7 @@
      *     calculation.
      *
      * Valid options depend on the specific geometry type.
-     *
+     * 
      * Returns:
      * {Number | Object} The distance between this geometry and the target.
      *     If details is true, the return will be an object with distance,
@@ -29452,7 +30992,7 @@
      */
     distanceTo: function(geometry, options) {
     },
-
+    
     /**
      * APIMethod: getVertices
      * Return a list of all points in this geometry.
@@ -29471,14 +31011,14 @@
 
     /**
      * Method: atPoint
-     * Note - This is only an approximation based on the bounds of the
+     * Note - This is only an approximation based on the bounds of the 
      * geometry.
-     *
+     * 
      * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
+     * lonlat - {<OpenLayers.LonLat>} 
      * toleranceLon - {float} Optional tolerance in Geometric Coords
      * toleranceLat - {float} Optional tolerance in Geographic Coords
-     *
+     * 
      * Returns:
      * {Boolean} Whether or not the geometry is at the specified location
      */
@@ -29489,8 +31029,8 @@
 
             var dX = (toleranceLon != null) ? toleranceLon : 0;
             var dY = (toleranceLat != null) ? toleranceLat : 0;
-
-            var toleranceBounds =
+    
+            var toleranceBounds = 
                 new OpenLayers.Bounds(this.bounds.left - dX,
                                       this.bounds.bottom - dY,
                                       this.bounds.right + dX,
@@ -29500,12 +31040,12 @@
         }
         return atPoint;
     },
-
+    
     /**
      * Method: getLength
      * Calculate the length of this geometry. This method is defined in
      * subclasses.
-     *
+     * 
      * Returns:
      * {Float} The length of the collection by summing its parts
      */
@@ -29518,7 +31058,7 @@
     /**
      * Method: getArea
      * Calculate the area of this geometry. This method is defined in subclasses.
-     *
+     * 
      * Returns:
      * {Float} The area of the collection by summing its parts
      */
@@ -29527,7 +31067,7 @@
         //
         return 0.0;
     },
-
+    
     /**
      * APIMethod: getCentroid
      * Calculate the centroid of this geometry. This method is defined in subclasses.
@@ -29585,7 +31125,7 @@
     }
     return geom;
 };
-
+    
 /**
  * Method: OpenLayers.Geometry.segmentsIntersect
  * Determine whether two line segments intersect.  Optionally calculates
@@ -29684,7 +31224,7 @@
                         }
                     }
                 }
-
+                
             }
         } else {
             // no calculated intersection, but segments could be within
@@ -29760,8 +31300,9 @@
     OpenLayers/Layer/MapGuide.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * licence.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -29779,52 +31320,52 @@
  */
 OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
 
-    /**
+    /** 
      * APIProperty: isBaseLayer
      * {Boolean} Treat this layer as a base layer.  Default is true.
      **/
     isBaseLayer: true,
-
+    
     /**
      * APIProperty: useHttpTile
-     * {Boolean} use a tile cache exposed directly via a webserver rather than the
-       *    via mapguide server. This does require extra configuration on the Mapguide Server,
-       *    and will only work when singleTile is false. The url for the layer must be set to the
-       *    webserver path rather than the Mapguide mapagent.
-       *    See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp
+     * {Boolean} use a tile cache exposed directly via a webserver rather than the 
+	   *    via mapguide server. This does require extra configuration on the Mapguide Server,
+	   *    and will only work when singleTile is false. The url for the layer must be set to the
+	   *    webserver path rather than the Mapguide mapagent.	  
+	   *    See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp 
      **/
     useHttpTile: false,
-
-    /**
+    
+    /** 
      * APIProperty: singleTile
-     * {Boolean} use tile server or request single tile image.
+     * {Boolean} use tile server or request single tile image. 
      **/
     singleTile: false,
-
-    /**
+    
+    /** 
      * APIProperty: useOverlay
      * {Boolean} flag to indicate if the layer should be retrieved using
      * GETMAPIMAGE (default) or using GETDYNAMICOVERLAY requests.
      **/
     useOverlay: false,
-
-    /**
+    
+    /** 
      * APIProperty: useAsyncOverlay
-     * {Boolean} indicates if the MapGuide site supports the asynchronous
+     * {Boolean} indicates if the MapGuide site supports the asynchronous 
      * GETDYNAMICOVERLAY requests which is available in MapGuide Enterprise 2010
-     * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG
-     * is called asynchronously, allows selections to be drawn separately from
+     * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG 
+     * is called asynchronously, allows selections to be drawn separately from 
      * the map and offers styling options.
-     *
+     * 
      * With older versions of MapGuide, set useAsyncOverlay=false.  Note that in
      * this case a synchronous AJAX call is issued and the mapname and session
      * parameters must be used to initialize the layer, not the mapdefinition
-     * parameter. Also note that this will issue a synchronous AJAX request
+     * parameter. Also note that this will issue a synchronous AJAX request 
      * before the image request can be issued so the users browser may lock
      * up if the MG Web tier does not respond in a timely fashion.
      **/
     useAsyncOverlay: true,
-
+    
     /**
      * Constant: TILE_PARAMS
      * {Object} Hashtable of default parameter key/value pairs for tiled layer
@@ -29845,7 +31386,7 @@
         clip: '1',
         version: '1.0.0'
     },
-
+    
     /**
      * Constant: OVERLAY_PARAMS
      * {Object} Hashtable of default parameter key/value pairs for untiled layer
@@ -29857,11 +31398,11 @@
         clip: '1',
         version: '2.0.0'
     },
-
-    /**
+    
+    /** 
      * Constant: FOLDER_PARAMS
-     * {Object} Hashtable of parameter key/value pairs which describe
-     * the folder structure for tiles as configured in the mapguide
+     * {Object} Hashtable of parameter key/value pairs which describe 
+     * the folder structure for tiles as configured in the mapguide 
      * serverconfig.ini section [TileServiceProperties]
      */
     FOLDER_PARAMS: {
@@ -29869,9 +31410,9 @@
         tileRowsPerFolder: 30,
         format: 'png',
         querystring: null
-    },
+    },	
 
-    /**
+    /** 
      * Property: defaultSize
      * {<OpenLayers.Size>} Tile size as produced by MapGuide server
      **/
@@ -29879,21 +31420,21 @@
 
     /**
      * Constructor: OpenLayers.Layer.MapGuide
-     * Create a new Mapguide layer, either tiled or untiled.
+     * Create a new Mapguide layer, either tiled or untiled.  
      *
-     * For tiled layers, the 'groupName' and 'mapDefinition' values
+     * For tiled layers, the 'groupName' and 'mapDefinition' values 
      * must be specified as parameters in the constructor.
      *
      * For untiled base layers, specify either combination of 'mapName' and
-     * 'session', or 'mapDefinition' and 'locale'.
+     * 'session', or 'mapDefinition' and 'locale'.  
      *
-     * For older versions of MapGuide and overlay layers, set useAsyncOverlay
-     * to false and in this case mapName and session are required parameters
+     * For older versions of MapGuide and overlay layers, set useAsyncOverlay 
+     * to false and in this case mapName and session are required parameters 
      * for the constructor.
      *
-     * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion
-     * factor that are different than the defaults used in OpenLayers,
-     * so these must be adjusted accordingly in your application.
+     * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion 
+     * factor that are different than the defaults used in OpenLayers, 
+     * so these must be adjusted accordingly in your application.  
      * See the MapGuide example for how to set these values for MGOS.
      *
      * Parameters:
@@ -29902,14 +31443,14 @@
      *            (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi)
      * params - {Object} hashtable of additional parameters to use. Some
      *     parameters may require additional code on the server. The ones that
-     *     you may want to use are:
+     *     you may want to use are: 
      *   - mapDefinition - {String} The MapGuide resource definition
      *            (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition)
-     *   - locale - Locale setting
+     *   - locale - Locale setting 
      *            (for untiled overlays layers only)
      *   - mapName - {String} Name of the map as stored in the MapGuide session.
      *          (for untiled layers with a session parameter only)
-     *   - session - { String} MapGuide session ID
+     *   - session - { String} MapGuide session ID 
      *            (for untiled overlays layers only)
      *   - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only
      *   - format - Image format to be returned (for untiled overlay layers only)
@@ -29923,24 +31464,24 @@
      *       groups to hide eg: 'cvc-xcv34,453-345-345sdf'
      *   - selectionXml - {String} A selection xml string Some server plumbing
      *       is required to read such a value.
-     * options - {Ojbect} Hashtable of extra options to tag onto the layer;
+     * options - {Ojbect} Hashtable of extra options to tag onto the layer; 
      *          will vary depending if tiled or untiled maps are being requested
      */
     initialize: function(name, url, params, options) {
-
+        
         OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments);
-
-        // unless explicitly set in options, if the layer is transparent,
+        
+        // unless explicitly set in options, if the layer is transparent, 
         // it will be an overlay
         if (options == null || options.isBaseLayer == null) {
-            this.isBaseLayer = ((this.transparent != "true") &&
+            this.isBaseLayer = ((this.transparent != "true") && 
                                 (this.transparent != true));
         }
 
         if (options && options.useOverlay!=null) {
           this.useOverlay = options.useOverlay;
         }
-
+        
         //initialize for untiled layers
         if (this.singleTile) {
           if (this.useOverlay) {
@@ -29956,7 +31497,7 @@
                            this.params,
                            this.SINGLE_TILE_PARAMS
                            );
-          }
+          }         
         } else {
             //initialize for tiled layers
             if (this.useHttpTile) {
@@ -29970,7 +31511,7 @@
                                this.TILE_PARAMS
                                );
             }
-            this.setTileSize(this.defaultSize);
+            this.setTileSize(this.defaultSize); 
         }
     },
 
@@ -29986,7 +31527,7 @@
             obj = new OpenLayers.Layer.MapGuide(this.name,
                                            this.url,
                                            this.params,
-                                           this.options);
+                                           this.getOptions());
       }
       //get all additions from superclasses
       obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
@@ -29996,17 +31537,17 @@
 
     /**
      * Method: addTile
-     * Creates a tile, initializes it, and adds it to the layer div.
+     * Creates a tile, initializes it, and adds it to the layer div. 
      *
      * Parameters:
      * bounds - {<OpenLayers.Bounds>}
      * position - {<OpenLayers.Pixel>}
-     *
+     * 
      * Returns:
      * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
      */
     addTile:function(bounds,position) {
-        return new OpenLayers.Tile.Image(this, position, bounds,
+        return new OpenLayers.Tile.Image(this, position, bounds, 
                                          null, this.tileSize);
     },
 
@@ -30015,18 +31556,18 @@
      * Return a query string for this layer
      *
      * Parameters:
-     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
+     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox 
      *                                for the request
      *
      * Returns:
-     * {String} A string with the layer's url and parameters and also
-     *          the passed-in bounds and appropriate tile size specified
+     * {String} A string with the layer's url and parameters and also 
+     *          the passed-in bounds and appropriate tile size specified 
      *          as parameters.
      */
     getURL: function (bounds) {
         var url;
         var center = bounds.getCenterLonLat();
-        var mapSize = this.map.getCurrentSize();
+        var mapSize = this.map.getSize();
 
         if (this.singleTile) {
           //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY with
@@ -30039,7 +31580,7 @@
             setviewcentery: center.lat,
             setviewscale: this.map.getScale()
           };
-
+          
           if (this.useOverlay && !this.useAsyncOverlay) {
             //first we need to call GETVISIBLEMAPEXTENT to set the extent
             var getVisParams = {};
@@ -30050,7 +31591,7 @@
             getVisParams.mapName = this.params.mapName;
             getVisParams.format = 'text/xml';
             url = this.getFullRequestString( getVisParams );
-
+            
             OpenLayers.Request.GET({url: url, async: false});
           }
           //construct the full URL
@@ -30065,13 +31606,13 @@
           rowidx = Math.round(rowidx/this.tileSize.h);
 
           if (this.useHttpTile){
-              url = this.getImageFilePath(
+	          url = this.getImageFilePath(
                    {
                        tilecol: colidx,
                        tilerow: rowidx,
                        scaleindex: this.resolutions.length - this.map.zoom - 1
                     });
-
+		  
           } else {
             url = this.getFullRequestString(
                    {
@@ -30086,7 +31627,7 @@
 
     /**
      * Method: getFullRequestString
-     * getFullRequestString on MapGuide layers is special, because we
+     * getFullRequestString on MapGuide layers is special, because we 
      * do a regular expression replace on ',' in parameters to '+'.
      * This is why it is subclassed here.
      *
@@ -30099,30 +31640,30 @@
     getFullRequestString:function(newParams, altUrl) {
         // use layer's url unless altUrl passed in
         var url = (altUrl == null) ? this.url : altUrl;
-
-        // if url is not a string, it should be an array of strings,
+        
+        // if url is not a string, it should be an array of strings, 
         //  in which case we will randomly select one of them in order
         //  to evenly distribute requests to different urls.
         if (typeof url == "object") {
             url = url[Math.floor(Math.random()*url.length)];
-        }
+        }   
         // requestString always starts with url
-        var requestString = url;
+        var requestString = url;        
 
-        // create a new params hashtable with all the layer params and the
+        // create a new params hashtable with all the layer params and the 
         // new params together. then convert to string
         var allParams = OpenLayers.Util.extend({}, this.params);
         allParams = OpenLayers.Util.extend(allParams, newParams);
         // ignore parameters that are already in the url search string
         var urlParams = OpenLayers.Util.upperCaseObject(
-                            OpenLayers.Util.getArgs(url));
+                            OpenLayers.Util.getParameters(url));
         for(var key in allParams) {
             if(key.toUpperCase() in urlParams) {
                 delete allParams[key];
             }
         }
         var paramsString = OpenLayers.Util.getParameterString(allParams);
-
+        
         /* MapGuide needs '+' seperating things like bounds/height/width.
            Since typically this is URL encoded, we use a slight hack: we
            depend on the list-like functionality of getParameterString to
@@ -30130,7 +31671,7 @@
            encoded) then do a regular expression replace on the , characters
            to '+' */
         paramsString = paramsString.replace(/,/g, "+");
-
+        
         if (paramsString != "") {
             var lastServerChar = url.charAt(url.length - 1);
             if ((lastServerChar == "&") || (lastServerChar == "?")) {
@@ -30148,9 +31689,9 @@
         return requestString;
     },
 
-     /**
+     /** 
      * Method: getImageFilePath
-     * special handler to request mapguide tiles from an http exposed tilecache
+     * special handler to request mapguide tiles from an http exposed tilecache 
      *
      * Parameters:
      * altUrl - {String} Alternative base URL to use.
@@ -30161,58 +31702,58 @@
     getImageFilePath:function(newParams, altUrl) {
         // use layer's url unless altUrl passed in
         var url = (altUrl == null) ? this.url : altUrl;
-
-        // if url is not a string, it should be an array of strings,
+        
+        // if url is not a string, it should be an array of strings, 
         //  in which case we will randomly select one of them in order
         //  to evenly distribute requests to different urls.
         if (typeof url == "object") {
             url = url[Math.floor(Math.random()*url.length)];
-        }
+        }   
         // requestString always starts with url
-        var requestString = url;
+        var requestString = url;        
 
         var tileRowGroup = "";
         var tileColGroup = "";
-
+        
         if (newParams.tilerow < 0) {
           tileRowGroup =  '-';
         }
-
+          
         if (newParams.tilerow == 0 ) {
           tileRowGroup += '0';
         } else {
           tileRowGroup += Math.floor(Math.abs(newParams.tilerow/this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder;
         }
-
+          
         if (newParams.tilecol < 0) {
           tileColGroup =  '-';
         }
-
+        
         if (newParams.tilecol == 0) {
           tileColGroup += '0';
         } else {
           tileColGroup += Math.floor(Math.abs(newParams.tilecol/this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder;
-        }
-
+        }					
+        
         var tilePath = '/S' + Math.floor(newParams.scaleindex)
                 + '/' + this.params.basemaplayergroupname
                 + '/R' + tileRowGroup
                 + '/C' + tileColGroup
-                + '/' + (newParams.tilerow % this.params.tileRowsPerFolder)
-                + '_' + (newParams.tilecol % this.params.tileColumnsPerFolder)
+                + '/' + (newParams.tilerow % this.params.tileRowsPerFolder) 
+                + '_' + (newParams.tilecol % this.params.tileColumnsPerFolder) 
                 + '.' + this.params.format;
-
+    
         if (this.params.querystring) {
                tilePath += "?" + this.params.querystring;
         }
-
+        
         requestString += tilePath;
         return requestString;
     },
-
-    /**
+    
+    /** 
      * Method: calculateGridLayout
-     * Generate parameters for the grid layout. This
+     * Generate parameters for the grid layout. This  
      *
      * Parameters:
      * bounds - {<OpenLayers.Bound>}
@@ -30226,34 +31767,35 @@
     calculateGridLayout: function(bounds, extent, resolution) {
         var tilelon = resolution * this.tileSize.w;
         var tilelat = resolution * this.tileSize.h;
-
+        
         var offsetlon = bounds.left - extent.left;
         var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
         var tilecolremain = offsetlon/tilelon - tilecol;
         var tileoffsetx = -tilecolremain * this.tileSize.w;
         var tileoffsetlon = extent.left + tilecol * tilelon;
-
-        var offsetlat = extent.top - bounds.top + tilelat;
+        
+        var offsetlat = extent.top - bounds.top + tilelat; 
         var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
         var tilerowremain = tilerow - offsetlat/tilelat;
         var tileoffsety = tilerowremain * this.tileSize.h;
         var tileoffsetlat = extent.top - tilelat*tilerow;
-
-        return {
+        
+        return { 
           tilelon: tilelon, tilelat: tilelat,
           tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
           tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
         };
     },
-
+    
     CLASS_NAME: "OpenLayers.Layer.MapGuide"
 });
 /* ======================================================================
     OpenLayers/Layer/MapServer.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -30272,7 +31814,7 @@
 
     /**
      * Constant: DEFAULT_PARAMS
-     * {Object} Hashtable of default parameter key/value pairs
+     * {Object} Hashtable of default parameter key/value pairs 
      */
     DEFAULT_PARAMS: {
         mode: "map",
@@ -30300,10 +31842,10 @@
             this.params, this.DEFAULT_PARAMS
         );
 
-        // unless explicitly set in options, if the layer is transparent,
+        // unless explicitly set in options, if the layer is transparent, 
         // it will be an overlay
         if (options == null || options.isBaseLayer == null) {
-            this.isBaseLayer = ((this.params.transparent != "true") &&
+            this.isBaseLayer = ((this.params.transparent != "true") && 
                                 (this.params.transparent != true));
         }
     },
@@ -30320,7 +31862,7 @@
             obj = new OpenLayers.Layer.MapServer(this.name,
                                            this.url,
                                            this.params,
-                                           this.options);
+                                           this.getOptions());
         }
         //get all additions from superclasses
         obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
@@ -30332,41 +31874,41 @@
 
     /**
      * Method: addTile
-     * Creates a tile, initializes it, and adds it to the layer div.
+     * Creates a tile, initializes it, and adds it to the layer div. 
      *
      * Parameters:
      * bounds - {<OpenLayers.Bounds>}
      * position - {<OpenLayers.Pixel>}
-     *
+     * 
      * Returns:
      * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
      */
     addTile:function(bounds,position) {
-        return new OpenLayers.Tile.Image(this, position, bounds,
+        return new OpenLayers.Tile.Image(this, position, bounds, 
                                          null, this.tileSize);
     },
-
+    
     /**
      * Method: getURL
      * Return a query string for this layer
      *
      * Parameters:
-     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
+     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox 
      *                                for the request
      *
      * Returns:
-     * {String} A string with the layer's url and parameters and also
-     *          the passed-in bounds and appropriate tile size specified
+     * {String} A string with the layer's url and parameters and also 
+     *          the passed-in bounds and appropriate tile size specified 
      *          as parameters.
      */
     getURL: function (bounds) {
         bounds = this.adjustBounds(bounds);
-        // Make a list, so that getFullRequestString uses literal ","
+        // Make a list, so that getFullRequestString uses literal "," 
         var extent = [bounds.left, bounds. bottom, bounds.right, bounds.top];
 
-        var imageSize = this.getImageSize();
-
-        // make lists, so that literal ','s are used
+        var imageSize = this.getImageSize(); 
+        
+        // make lists, so that literal ','s are used 
         var url = this.getFullRequestString(
                      {mapext:   extent,
                       imgext:   extent,
@@ -30375,40 +31917,40 @@
                       imgy:     imageSize.h / 2,
                       imgxy:    [imageSize.w, imageSize.h]
                       });
-
+        
         return url;
     },
-
-    /**
+    
+    /** 
      * Method: getFullRequestString
-     * combine the layer's url with its params and these newParams.
-     *
+     * combine the layer's url with its params and these newParams. 
+     *   
      * Parameter:
-     * newParams - {Object} New parameters that should be added to the
+     * newParams - {Object} New parameters that should be added to the 
      *                      request string.
-     * altUrl - {String} (optional) Replace the URL in the full request
+     * altUrl - {String} (optional) Replace the URL in the full request  
      *                              string with the provided URL.
-     *
-     * Returns:
+     * 
+     * Returns: 
      * {String} A string with the layer's url and parameters embedded in it.
      */
     getFullRequestString:function(newParams, altUrl) {
         // use layer's url unless altUrl passed in
         var url = (altUrl == null) ? this.url : altUrl;
-
-        // create a new params hashtable with all the layer params and the
+        
+        // create a new params hashtable with all the layer params and the 
         // new params together. then convert to string
         var allParams = OpenLayers.Util.extend({}, this.params);
         allParams = OpenLayers.Util.extend(allParams, newParams);
         var paramsString = OpenLayers.Util.getParameterString(allParams);
-
-        // if url is not a string, it should be an array of strings,
-        // in which case we will deterministically select one of them in
+        
+        // if url is not a string, it should be an array of strings, 
+        // in which case we will deterministically select one of them in 
         // order to evenly distribute requests to different urls.
         if (url instanceof Array) {
             url = this.selectUrl(paramsString, url);
-        }
-
+        }   
+        
         // ignore parameters that are already in the url search string
         var urlParams = OpenLayers.Util.upperCaseObject(
                             OpenLayers.Util.getParameters(url));
@@ -30418,9 +31960,9 @@
             }
         }
         paramsString = OpenLayers.Util.getParameterString(allParams);
-
+        
         // requestString always starts with url
-        var requestString = url;
+        var requestString = url;        
 
         // MapServer needs '+' seperating things like bounds/height/width.
         //   Since typically this is URL encoded, we use a slight hack: we
@@ -30430,7 +31972,7 @@
         //  to '+'
         //
         paramsString = paramsString.replace(/,/g, "+");
-
+        
         if (paramsString != "") {
             var lastServerChar = url.charAt(url.length - 1);
             if ((lastServerChar == "&") || (lastServerChar == "?")) {
@@ -30454,8 +31996,9 @@
     OpenLayers/Layer/WMS.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -30469,7 +32012,7 @@
  * Instances of OpenLayers.Layer.WMS are used to display data from OGC Web
  *     Mapping Services. Create a new WMS layer with the <OpenLayers.Layer.WMS>
  *     constructor.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Layer.Grid>
  */
@@ -30477,7 +32020,7 @@
 
     /**
      * Constant: DEFAULT_PARAMS
-     * {Object} Hashtable of default parameter key/value pairs
+     * {Object} Hashtable of default parameter key/value pairs 
      */
     DEFAULT_PARAMS: { service: "WMS",
                       version: "1.1.1",
@@ -30486,40 +32029,48 @@
                       exceptions: "application/vnd.ogc.se_inimage",
                       format: "image/jpeg"
                      },
-
+    
     /**
      * Property: reproject
      * *Deprecated*. See http://trac.openlayers.org/wiki/SphericalMercator
-     * for information on the replacement for this functionality.
+     * for information on the replacement for this functionality. 
      * {Boolean} Try to reproject this layer if its coordinate reference system
-     *           is different than that of the base layer.  Default is true.
-     *           Set this in the layer options.  Should be set to false in
+     *           is different than that of the base layer.  Default is true.  
+     *           Set this in the layer options.  Should be set to false in 
      *           most cases.
      */
     reproject: false,
-
+ 
     /**
      * APIProperty: isBaseLayer
      * {Boolean} Default is true for WMS layer
      */
     isBaseLayer: true,
-
+    
     /**
      * APIProperty: encodeBBOX
-     * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no',
+     * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no', 
      * but some services want it that way. Default false.
      */
     encodeBBOX: false,
-
+    
+    /** 
+     * APIProperty: noMagic 
+     * {Boolean} If true, the image format will not be automagicaly switched 
+     *     from image/jpeg to image/png or image/gif when using 
+     *     TRANSPARENT=TRUE. Also isBaseLayer will not changed by the  
+     *     constructor. Default false. 
+     */ 
+    noMagic: false,
+    
     /**
-     * APIProperty: noMagic
-     * {Boolean} If true, the image format will not be automagicaly switched
-     *     from image/jpeg to image/png or image/gif when using
-     *     TRANSPARENT=TRUE. Also isBaseLayer will not changed by the
-     *     constructor. Default false.
+     * Property: yx
+     * {Object} Keys in this object are EPSG codes for which the axis order
+     *     is to be reversed (yx instead of xy, LatLon instead of LonLat), with
+     *     true as value. This is only relevant for WMS versions >= 1.3.0.
      */
-    noMagic: false,
-
+    yx: {'EPSG:4326': true},
+    
     /**
      * Constructor: OpenLayers.Layer.WMS
      * Create a new WMS layer object
@@ -30527,7 +32078,7 @@
      * Example:
      * (code)
      * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
-     *                                    "http://wms.jpl.nasa.gov/wms.cgi",
+     *                                    "http://wms.jpl.nasa.gov/wms.cgi", 
      *                                    {layers: "modis,global_mosaic"});
      * (end)
      *
@@ -30543,24 +32094,27 @@
         var newArguments = [];
         //uppercase params
         params = OpenLayers.Util.upperCaseObject(params);
+        if (parseFloat(params.VERSION) >= 1.3 && !params.EXCEPTIONS) {
+            params.EXCEPTIONS = "INIMAGE";
+        } 
         newArguments.push(name, url, params, options);
         OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
         OpenLayers.Util.applyDefaults(
-                       this.params,
+                       this.params, 
                        OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
                        );
 
 
-        //layer is transparent
-        if (!this.noMagic && this.params.TRANSPARENT &&
+        //layer is transparent        
+        if (!this.noMagic && this.params.TRANSPARENT && 
             this.params.TRANSPARENT.toString().toLowerCase() == "true") {
-
+            
             // unless explicitly set in options, make layer an overlay
             if ( (options == null) || (!options.isBaseLayer) ) {
                 this.isBaseLayer = false;
-            }
-
-            // jpegs can never be transparent, so intelligently switch the
+            } 
+            
+            // jpegs can never be transparent, so intelligently switch the 
             //  format, depending on teh browser's capabilities
             if (this.params.FORMAT == "image/jpeg") {
                 this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
@@ -30568,18 +32122,18 @@
             }
         }
 
-    },
+    },    
 
     /**
      * Method: destroy
      * Destroy this layer
      */
     destroy: function() {
-        // for now, nothing special to do here.
-        OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);
+        // for now, nothing special to do here. 
+        OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);  
     },
 
-
+    
     /**
      * Method: clone
      * Create a clone of this layer
@@ -30588,12 +32142,12 @@
      * {<OpenLayers.Layer.WMS>} An exact clone of this layer
      */
     clone: function (obj) {
-
+        
         if (obj == null) {
             obj = new OpenLayers.Layer.WMS(this.name,
                                            this.url,
                                            this.params,
-                                           this.options);
+                                           this.getOptions());
         }
 
         //get all additions from superclasses
@@ -30602,8 +32156,21 @@
         // copy/set any non-init, non-simple values here
 
         return obj;
+    },    
+    
+    /**
+     * APIMethod: reverseAxisOrder
+     * Returns true if the axis order is reversed for the WMS version and
+     * projection of the layer.
+     * 
+     * Returns:
+     * {Boolean} true if the axis order is reversed, false otherwise.
+     */
+    reverseAxisOrder: function() {
+        return (parseFloat(this.params.VERSION) >= 1.3 && 
+            !!this.yx[this.map.getProjectionObject().getCode()]);
     },
-
+    
     /**
      * Method: getURL
      * Return a GetMap query string for this layer
@@ -30614,35 +32181,38 @@
      *
      * Returns:
      * {String} A string with the layer's url and parameters and also the
-     *          passed-in bounds and appropriate tile size specified as
+     *          passed-in bounds and appropriate tile size specified as 
      *          parameters.
      */
     getURL: function (bounds) {
         bounds = this.adjustBounds(bounds);
-
+        
         var imageSize = this.getImageSize();
-        var newParams = {
-            'BBOX': this.encodeBBOX ?  bounds.toBBOX() : bounds.toArray(),
-            'WIDTH': imageSize.w,
-            'HEIGHT': imageSize.h
-        };
+        var newParams = {};
+        // WMS 1.3 introduced axis order
+        var reverseAxisOrder = this.reverseAxisOrder();
+        newParams.BBOX = this.encodeBBOX ?
+            bounds.toBBOX(null, reverseAxisOrder) :
+            bounds.toArray(reverseAxisOrder);
+        newParams.WIDTH = imageSize.w;
+        newParams.HEIGHT = imageSize.h;
         var requestString = this.getFullRequestString(newParams);
         return requestString;
     },
 
     /**
      * Method: addTile
-     * addTile creates a tile, initializes it, and adds it to the layer div.
+     * addTile creates a tile, initializes it, and adds it to the layer div. 
      *
      * Parameters:
      * bounds - {<OpenLayers.Bounds>}
      * position - {<OpenLayers.Pixel>}
-     *
+     * 
      * Returns:
      * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
      */
     addTile:function(bounds,position) {
-        return new OpenLayers.Tile.Image(this, position, bounds,
+        return new OpenLayers.Tile.Image(this, position, bounds, 
                                          null, this.tileSize);
     },
 
@@ -30650,38 +32220,43 @@
      * APIMethod: mergeNewParams
      * Catch changeParams and uppercase the new params to be merged in
      *     before calling changeParams on the super class.
-     *
+     * 
      *     Once params have been changed, the tiles will be reloaded with
      *     the new parameters.
-     *
+     * 
      * Parameters:
      * newParams - {Object} Hashtable of new params to use
      */
     mergeNewParams:function(newParams) {
         var upperParams = OpenLayers.Util.upperCaseObject(newParams);
         var newArguments = [upperParams];
-        return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,
+        return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, 
                                                              newArguments);
     },
 
-    /**
+    /** 
      * APIMethod: getFullRequestString
-     * Combine the layer's url with its params and these newParams.
-     *
+     * Combine the layer's url with its params and these newParams. 
+     *   
      *     Add the SRS parameter from projection -- this is probably
-     *     more eloquently done via a setProjection() method, but this
+     *     more eloquently done via a setProjection() method, but this 
      *     works for now and always.
      *
      * Parameters:
      * newParams - {Object}
      * altUrl - {String} Use this as the url instead of the layer's url
-     *
+     * 
      * Returns:
-     * {String}
+     * {String} 
      */
     getFullRequestString:function(newParams, altUrl) {
         var projectionCode = this.map.getProjection();
-        this.params.SRS = (projectionCode == "none") ? null : projectionCode;
+        var value = (projectionCode == "none") ? null : projectionCode
+        if (parseFloat(this.params.VERSION) >= 1.3) {
+            this.params.CRS = value;
+        } else {
+            this.params.SRS = value;
+        }
 
         return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
                                                     this, arguments);
@@ -30690,17 +32265,223 @@
     CLASS_NAME: "OpenLayers.Layer.WMS"
 });
 /* ======================================================================
+    OpenLayers/Layer/XYZ.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Tile/Image.js
+ */
+
+/** 
+ * Class: OpenLayers.Layer.XYZ
+ * The XYZ class is designed to make it easier for people who have tiles
+ * arranged by a standard XYZ grid. 
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, {
+    
+    /**
+     * APIProperty: isBaseLayer
+     * Default is true, as this is designed to be a base tile source. 
+     */
+    isBaseLayer: true,
+    
+    /**
+     * APIProperty: sphericalMecator
+     * Whether the tile extents should be set to the defaults for 
+     *    spherical mercator. Useful for things like OpenStreetMap.
+     *    Default is false, except for the OSM subclass.
+     */
+    sphericalMercator: false,
+
+    /**
+     * APIProperty: zoomOffset
+     * {Number} If your cache has more zoom levels than you want to provide
+     *     access to with this layer, supply a zoomOffset.  This zoom offset
+     *     is added to the current map zoom level to determine the level
+     *     for a requested tile.  For example, if you supply a zoomOffset
+     *     of 3, when the map is at the zoom 0, tiles will be requested from
+     *     level 3 of your cache.  Default is 0 (assumes cache level and map
+     *     zoom are equivalent).
+     */
+    zoomOffset: 0,
+    
+    /**
+     * Constructor: OpenLayers.Layer.XYZ
+     *
+     * Parameters:
+     * name - {String}
+     * url - {String}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, options) {
+        if (options && options.sphericalMercator || this.sphericalMercator) {
+            options = OpenLayers.Util.extend({
+                maxExtent: new OpenLayers.Bounds(
+                    -128 * 156543.0339,
+                    -128 * 156543.0339,
+                    128 * 156543.0339,
+                    128 * 156543.0339
+                ),
+                maxResolution: 156543.0339,
+                numZoomLevels: 19,
+                units: "m",
+                projection: "EPSG:900913"
+            }, options);
+        }
+        url = url || this.url;
+        name = name || this.name;
+        var newArguments = [name, url, {}, options];
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+    },
+    
+    /**
+     * APIMethod: clone
+     * Create a clone of this layer
+     *
+     * Parameters:
+     * obj - {Object} Is this ever used?
+     * 
+     * Returns:
+     * {<OpenLayers.Layer.XYZ>} An exact clone of this OpenLayers.Layer.XYZ
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.XYZ(this.name,
+                                            this.url,
+                                            this.getOptions());
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+        return obj;
+    },    
+
+    /**
+     * Method: getUrl
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     *
+     * Returns:
+     * {String} A string with the layer's url and parameters and also the
+     *          passed-in bounds and appropriate tile size specified as
+     *          parameters
+     */
+    getURL: function (bounds) {
+        var res = this.map.getResolution();
+        var x = Math.round((bounds.left - this.maxExtent.left) 
+            / (res * this.tileSize.w));
+        var y = Math.round((this.maxExtent.top - bounds.top) 
+            / (res * this.tileSize.h));
+        var z = this.map.getZoom() + this.zoomOffset;
+
+        var url = this.url;
+        var s = '' + x + y + z;
+        if (url instanceof Array)
+        {
+            url = this.selectUrl(s, url);
+        }
+        
+        var path = OpenLayers.String.format(url, {'x': x, 'y': y, 'z': z});
+
+        return path;
+    },
+    
+    /**
+     * Method: addTile
+     * addTile creates a tile, initializes it, and adds it to the layer div. 
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+     */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(this, position, bounds, 
+                                         null, this.tileSize);
+    },
+     
+    /* APIMethod: setMap
+     * When the layer is added to a map, then we can fetch our origin 
+     *    (if we don't have one.) 
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    setMap: function(map) {
+        OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments);
+        if (!this.tileOrigin) { 
+            this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left,
+                                                this.maxExtent.bottom);
+        }                                       
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.XYZ"
+});
+
+
+/**
+ * Class: OpenLayers.Layer.OSM
+ * A class to access OpenStreetMap tiles. By default, uses the OpenStreetMap
+ *    hosted tile.openstreetmap.org 'Mapnik' tileset. If you wish to use
+ *    tiles at home / osmarender layer instead, you can pass a layer like:
+ * 
+ * (code)
+ *     new OpenLayers.Layer.OSM("t at h", 
+ *       "http://tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png"); 
+ * (end)
+ *
+ * This layer defaults to Spherical Mercator.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.XYZ>
+ */
+OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
+     name: "OpenStreetMap",
+     attribution: "Data CC-By-SA by <a href='http://openstreetmap.org/'>OpenStreetMap</a>",
+     sphericalMercator: true,
+     url: 'http://tile.openstreetmap.org/${z}/${x}/${y}.png',
+     clone: function(obj) {
+         if (obj == null) {
+             obj = new OpenLayers.Layer.OSM(
+                 this.name, this.url, this.getOptions());
+         }
+         obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]);
+         return obj;
+     },
+     CLASS_NAME: "OpenLayers.Layer.OSM"
+});
+/* ======================================================================
     OpenLayers/Rule.js
    ====================================================================== */
 
-/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
 
 
 /**
  * @requires OpenLayers/Util.js
  * @requires OpenLayers/Style.js
+ * @requires OpenLayers/Symbolizer/Point.js
+ * @requires OpenLayers/Symbolizer/Line.js
+ * @requires OpenLayers/Symbolizer/Polygon.js
+ * @requires OpenLayers/Symbolizer/Text.js
+ * @requires OpenLayers/Symbolizer/Raster.js
  */
 
 /**
@@ -30708,25 +32489,25 @@
  * This class represents an SLD Rule, as being used for rule-based SLD styling.
  */
 OpenLayers.Rule = OpenLayers.Class({
-
+    
     /**
      * Property: id
      * {String} A unique id for this session.
      */
     id: null,
-
+    
     /**
      * APIProperty: name
      * {String} name of this rule
      */
-    name: 'default',
-
+    name: null,
+    
     /**
      * Property: title
      * {String} Title of this rule (set if included in SLD)
      */
     title: null,
-
+    
     /**
      * Property: description
      * {String} Description of this rule (set if abstract is included in SLD)
@@ -30740,7 +32521,7 @@
      * be used.
      */
     context: null,
-
+    
     /**
      * Property: filter
      * {<OpenLayers.Filter>} Optional filter for the rule.
@@ -30750,13 +32531,13 @@
     /**
      * Property: elseFilter
      * {Boolean} Determines whether this rule is only to be applied only if
-     * no other rules match (ElseFilter according to the SLD specification).
+     * no other rules match (ElseFilter according to the SLD specification). 
      * Default is false.  For instances of OpenLayers.Rule, if elseFilter is
-     * false, the rule will always apply.  For subclasses, the else property is
+     * false, the rule will always apply.  For subclasses, the else property is 
      * ignored.
      */
     elseFilter: false,
-
+    
     /**
      * Property: symbolizer
      * {Object} Symbolizer or hash of symbolizers for this rule. If hash of
@@ -30767,8 +32548,19 @@
      * SLD.
      */
     symbolizer: null,
-
+    
     /**
+     * Property: symbolizers
+     * {Array} Collection of symbolizers associated with this rule.  If 
+     *     provided at construction, the symbolizers array has precedence
+     *     over the deprecated symbolizer property.  Note that multiple 
+     *     symbolizers are not currently supported by the vector renderers.
+     *     Rules with multiple symbolizers are currently only useful for
+     *     maintaining elements in an SLD document.
+     */
+    symbolizers: null,
+    
+    /**
      * APIProperty: minScaleDenominator
      * {Number} or {String} minimum scale at which to draw the feature.
      * In the case of a String, this can be a combination of text and
@@ -30783,25 +32575,28 @@
      * propertyNames in the form "literal ${propertyName}"
      */
     maxScaleDenominator: null,
-
-    /**
+    
+    /** 
      * Constructor: OpenLayers.Rule
      * Creates a Rule.
      *
      * Parameters:
      * options - {Object} An optional object with properties to set on the
      *           rule
-     *
+     * 
      * Returns:
      * {<OpenLayers.Rule>}
      */
     initialize: function(options) {
         this.symbolizer = {};
         OpenLayers.Util.extend(this, options);
+        if (this.symbolizers) {
+            delete this.symbolizer;
+        }
         this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
     },
 
-    /**
+    /** 
      * APIMethod: destroy
      * nullify references to prevent circular references and memory leaks
      */
@@ -30810,15 +32605,16 @@
             this.symbolizer[i] = null;
         }
         this.symbolizer = null;
+        delete this.symbolizers;
     },
-
+    
     /**
      * APIMethod: evaluate
      * evaluates this rule for a specific feature
-     *
+     * 
      * Parameters:
      * feature - {<OpenLayers.Feature>} feature to apply the rule to.
-     *
+     * 
      * Returns:
      * {Boolean} true if the rule applies, false if it does not.
      * This rule is the default rule and always returns true.
@@ -30830,7 +32626,7 @@
         if (this.minScaleDenominator || this.maxScaleDenominator) {
             var scale = feature.layer.map.getScale();
         }
-
+        
         // check if within minScale/maxScale bounds
         if (this.minScaleDenominator) {
             applies = scale >= OpenLayers.Style.createLiteral(
@@ -30840,7 +32636,7 @@
             applies = scale < OpenLayers.Style.createLiteral(
                     this.maxScaleDenominator, context);
         }
-
+        
         // check if optional filter applies
         if(applies && this.filter) {
             // feature id filters get the feature, others get the context
@@ -30853,11 +32649,11 @@
 
         return applies;
     },
-
+    
     /**
      * Method: getContext
      * Gets the context for evaluating this rule
-     *
+     * 
      * Paramters:
      * feature - {<OpenLayers.Feature>} feature to take the context from if
      *           none is specified.
@@ -30872,26 +32668,36 @@
         }
         return context;
     },
-
+    
     /**
      * APIMethod: clone
      * Clones this rule.
-     *
+     * 
      * Returns:
      * {<OpenLayers.Rule>} Clone of this rule.
      */
     clone: function() {
         var options = OpenLayers.Util.extend({}, this);
-        // clone symbolizer
-        options.symbolizer = {};
-        for(var key in this.symbolizer) {
-            value = this.symbolizer[key];
-            type = typeof value;
-            if(type === "object") {
-                options.symbolizer[key] = OpenLayers.Util.extend({}, value);
-            } else if(type === "string") {
-                options.symbolizer[key] = value;
+        if (this.symbolizers) {
+            // clone symbolizers
+            var len = this.symbolizers.length;
+            options.symbolizers = new Array(len);
+            for (var i=0; i<len; ++i) {
+                options.symbolizers[i] = this.symbolizers[i].clone();
             }
+        } else {
+            // clone symbolizer
+            options.symbolizer = {};
+            var value, type;
+            for(var key in this.symbolizer) {
+                value = this.symbolizer[key];
+                type = typeof value;
+                if(type === "object") {
+                    options.symbolizer[key] = OpenLayers.Util.extend({}, value);
+                } else if(type === "string") {
+                    options.symbolizer[key] = value;
+                }
+            }
         }
         // clone filter
         options.filter = this.filter && this.filter.clone();
@@ -30899,34 +32705,35 @@
         options.context = this.context && OpenLayers.Util.extend({}, this.context);
         return new OpenLayers.Rule(options);
     },
-
+        
     CLASS_NAME: "OpenLayers.Rule"
 });
 /* ======================================================================
     OpenLayers/StyleMap.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
  * @requires OpenLayers/Style.js
  * @requires OpenLayers/Feature/Vector.js
  */
-
+ 
 /**
  * Class: OpenLayers.StyleMap
  */
 OpenLayers.StyleMap = OpenLayers.Class({
-
+    
     /**
      * Property: styles
      * Hash of {<OpenLayers.Style>}, keyed by names of well known
      * rendering intents (e.g. "default", "temporary", "select", "delete").
      */
     styles: null,
-
+    
     /**
      * Property: extendDefault
      * {Boolean} if true, every render intent will extend the symbolizers
@@ -30934,10 +32741,10 @@
      * rendering intent will be treated as a completely independent style.
      */
     extendDefault: true,
-
+    
     /**
      * Constructor: OpenLayers.StyleMap
-     *
+     * 
      * Parameters:
      * style   - {Object} Optional. Either a style hash, or a style object, or
      *           a hash of style objects (style hashes) keyed by rendering
@@ -30958,7 +32765,7 @@
             "delete": new OpenLayers.Style(
                 OpenLayers.Feature.Vector.style["delete"])
         };
-
+        
         // take whatever the user passed as style parameter and convert it
         // into parts of stylemap.
         if(style instanceof OpenLayers.Style) {
@@ -30997,11 +32804,11 @@
         }
         this.styles = null;
     },
-
+    
     /**
      * Method: createSymbolizer
      * Creates the symbolizer for a feature for a render intent.
-     *
+     * 
      * Parameters:
      * feature - {<OpenLayers.Feature>} The feature to evaluate the rules
      *           of the intended style against.
@@ -31009,7 +32816,7 @@
      *           used to draw the feature. Well known intents are "default"
      *           (for just drawing the features), "select" (for selected
      *           features) and "temporary" (for drawing features).
-     *
+     * 
      * Returns:
      * {Object} symbolizer hash
      */
@@ -31028,20 +32835,20 @@
         return OpenLayers.Util.extend(defaultSymbolizer,
             this.styles[intent].createSymbolizer(feature));
     },
-
+    
     /**
      * Method: addUniqueValueRules
      * Convenience method to create comparison rules for unique values of a
      * property. The rules will be added to the style object for a specified
      * rendering intent. This method is a shortcut for creating something like
      * the "unique value legends" familiar from well known desktop GIS systems
-     *
+     * 
      * Parameters:
      * renderIntent - {String} rendering intent to add the rules to
      * property     - {String} values of feature attributes to create the
      *                rules for
      * symbolizers  - {Object} Hash of symbolizers, keyed by the desired
-     *                property values
+     *                property values 
      * context      - {Object} An optional object with properties that
      *                symbolizers' property values should be evaluated
      *                against. If no context is specified, feature.attributes
@@ -31066,11 +32873,529 @@
     CLASS_NAME: "OpenLayers.StyleMap"
 });
 /* ======================================================================
+    OpenLayers/Filter/Comparison.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Filter.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.Comparison
+ * This class represents a comparison filter.
+ * 
+ * Inherits from
+ * - <OpenLayers.Filter>
+ */
+OpenLayers.Filter.Comparison = OpenLayers.Class(OpenLayers.Filter, {
+
+    /**
+     * APIProperty: type
+     * {String} type: type of the comparison. This is one of
+     * - OpenLayers.Filter.Comparison.EQUAL_TO                 = "==";
+     * - OpenLayers.Filter.Comparison.NOT_EQUAL_TO             = "!=";
+     * - OpenLayers.Filter.Comparison.LESS_THAN                = "<";
+     * - OpenLayers.Filter.Comparison.GREATER_THAN             = ">";
+     * - OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO    = "<=";
+     * - OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO = ">=";
+     * - OpenLayers.Filter.Comparison.BETWEEN                  = "..";
+     * - OpenLayers.Filter.Comparison.LIKE                     = "~"; 
+     */
+    type: null,
+    
+    /**
+     * APIProperty: property
+     * {String}
+     * name of the context property to compare
+     */
+    property: null,
+    
+    /**
+     * APIProperty: value
+     * {Number} or {String}
+     * comparison value for binary comparisons. In the case of a String, this
+     * can be a combination of text and propertyNames in the form
+     * "literal ${propertyName}"
+     */
+    value: null,
+    
+    /**
+     * Property: matchCase
+     * {Boolean} Force case sensitive searches for EQUAL_TO and NOT_EQUAL_TO
+     *     comparisons.  The Filter Encoding 1.1 specification added a matchCase
+     *     attribute to ogc:PropertyIsEqualTo and ogc:PropertyIsNotEqualTo
+     *     elements.  This property will be serialized with those elements only
+     *     if using the v1.1.0 filter format. However, when evaluating filters
+     *     here, the matchCase property will always be respected (for EQUAL_TO
+     *     and NOT_EQUAL_TO).  Default is true.
+     */
+    matchCase: true,
+    
+    /**
+     * APIProperty: lowerBoundary
+     * {Number} or {String}
+     * lower boundary for between comparisons. In the case of a String, this
+     * can be a combination of text and propertyNames in the form
+     * "literal ${propertyName}"
+     */
+    lowerBoundary: null,
+    
+    /**
+     * APIProperty: upperBoundary
+     * {Number} or {String}
+     * upper boundary for between comparisons. In the case of a String, this
+     * can be a combination of text and propertyNames in the form
+     * "literal ${propertyName}"
+     */
+    upperBoundary: null,
+
+    /** 
+     * Constructor: OpenLayers.Filter.Comparison
+     * Creates a comparison rule.
+     *
+     * Parameters:
+     * options - {Object} An optional object with properties to set on the
+     *           rule
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Comparison>}
+     */
+    initialize: function(options) {
+        OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * APIMethod: evaluate
+     * Evaluates this filter in a specific context.
+     * 
+     * Parameters:
+     * context - {Object} Context to use in evaluating the filter.  If a vector
+     *     feature is provided, the feature.attributes will be used as context.
+     * 
+     * Returns:
+     * {Boolean} The filter applies.
+     */
+    evaluate: function(context) {
+        if (context instanceof OpenLayers.Feature.Vector) {
+            context = context.attributes;
+        }
+        var result = false;
+        var got = context[this.property];
+        switch(this.type) {
+            case OpenLayers.Filter.Comparison.EQUAL_TO:
+                var exp = this.value;
+                if(!this.matchCase &&
+                   typeof got == "string" && typeof exp == "string") {
+                    result = (got.toUpperCase() == exp.toUpperCase());
+                } else {
+                    result = (got == exp);
+                }
+                break;
+            case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:
+                var exp = this.value;
+                if(!this.matchCase &&
+                   typeof got == "string" && typeof exp == "string") {
+                    result = (got.toUpperCase() != exp.toUpperCase());
+                } else {
+                    result = (got != exp);
+                }
+                break;
+            case OpenLayers.Filter.Comparison.LESS_THAN:
+                result = got < this.value;
+                break;
+            case OpenLayers.Filter.Comparison.GREATER_THAN:
+                result = got > this.value;
+                break;
+            case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:
+                result = got <= this.value;
+                break;
+            case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:
+                result = got >= this.value;
+                break;
+            case OpenLayers.Filter.Comparison.BETWEEN:
+                result = (got >= this.lowerBoundary) &&
+                    (got <= this.upperBoundary);
+                break;
+            case OpenLayers.Filter.Comparison.LIKE:
+                var regexp = new RegExp(this.value, "gi");
+                result = regexp.test(got);
+                break;
+        }
+        return result;
+    },
+    
+    /**
+     * APIMethod: value2regex
+     * Converts the value of this rule into a regular expression string,
+     * according to the wildcard characters specified. This method has to
+     * be called after instantiation of this class, if the value is not a
+     * regular expression already.
+     * 
+     * Parameters:
+     * wildCard   - {<Char>} wildcard character in the above value, default
+     *              is "*"
+     * singleChar - {<Char>) single-character wildcard in the above value
+     *              default is "."
+     * escape     - {<Char>) escape character in the above value, default is
+     *              "!"
+     * 
+     * Returns:
+     * {String} regular expression string
+     */
+    value2regex: function(wildCard, singleChar, escapeChar) {
+        if (wildCard == ".") {
+            var msg = "'.' is an unsupported wildCard character for "+
+                    "OpenLayers.Filter.Comparison";
+            OpenLayers.Console.error(msg);
+            return null;
+        }
+        
+
+        // set UMN MapServer defaults for unspecified parameters
+        wildCard = wildCard ? wildCard : "*";
+        singleChar = singleChar ? singleChar : ".";
+        escapeChar = escapeChar ? escapeChar : "!";
+        
+        this.value = this.value.replace(
+                new RegExp("\\"+escapeChar+"(.|$)", "g"), "\\$1");
+        this.value = this.value.replace(
+                new RegExp("\\"+singleChar, "g"), ".");
+        this.value = this.value.replace(
+                new RegExp("\\"+wildCard, "g"), ".*");
+        this.value = this.value.replace(
+                new RegExp("\\\\.\\*", "g"), "\\"+wildCard);
+        this.value = this.value.replace(
+                new RegExp("\\\\\\.", "g"), "\\"+singleChar);
+        
+        return this.value;
+    },
+    
+    /**
+     * Method: regex2value
+     * Convert the value of this rule from a regular expression string into an
+     *     ogc literal string using a wildCard of *, a singleChar of ., and an
+     *     escape of !.  Leaves the <value> property unmodified.
+     * 
+     * Returns:
+     * {String} A string value.
+     */
+    regex2value: function() {
+        
+        var value = this.value;
+        
+        // replace ! with !!
+        value = value.replace(/!/g, "!!");
+
+        // replace \. with !. (watching out for \\.)
+        value = value.replace(/(\\)?\\\./g, function($0, $1) {
+            return $1 ? $0 : "!.";
+        });
+        
+        // replace \* with #* (watching out for \\*)
+        value = value.replace(/(\\)?\\\*/g, function($0, $1) {
+            return $1 ? $0 : "!*";
+        });
+        
+        // replace \\ with \
+        value = value.replace(/\\\\/g, "\\");
+
+        // convert .* to * (the sequence #.* is not allowed)
+        value = value.replace(/\.\*/g, "*");
+        
+        return value;
+    },
+    
+    /**
+     * APIMethod: clone
+     * Clones this filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Comparison>} Clone of this filter.
+     */
+    clone: function() {
+        return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison(), this);
+    },
+    
+    CLASS_NAME: "OpenLayers.Filter.Comparison"
+});
+
+
+OpenLayers.Filter.Comparison.EQUAL_TO                 = "==";
+OpenLayers.Filter.Comparison.NOT_EQUAL_TO             = "!=";
+OpenLayers.Filter.Comparison.LESS_THAN                = "<";
+OpenLayers.Filter.Comparison.GREATER_THAN             = ">";
+OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO    = "<=";
+OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO = ">=";
+OpenLayers.Filter.Comparison.BETWEEN                  = "..";
+OpenLayers.Filter.Comparison.LIKE                     = "~";
+/* ======================================================================
+    OpenLayers/Filter/Logical.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Filter.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.Logical
+ * This class represents ogc:And, ogc:Or and ogc:Not rules.
+ * 
+ * Inherits from
+ * - <OpenLayers.Filter>
+ */
+OpenLayers.Filter.Logical = OpenLayers.Class(OpenLayers.Filter, {
+
+    /**
+     * APIProperty: filters
+     * {Array(<OpenLayers.Filter>)} Child filters for this filter.
+     */
+    filters: null, 
+     
+    /**
+     * APIProperty: type
+     * {String} type of logical operator. Available types are:
+     * - OpenLayers.Filter.Logical.AND = "&&";
+     * - OpenLayers.Filter.Logical.OR  = "||";
+     * - OpenLayers.Filter.Logical.NOT = "!";
+     */
+    type: null,
+
+    /** 
+     * Constructor: OpenLayers.Filter.Logical
+     * Creates a logical filter (And, Or, Not).
+     *
+     * Parameters:
+     * options - {Object} An optional object with properties to set on the
+     *     filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Logical>}
+     */
+    initialize: function(options) {
+        this.filters = [];
+        OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+    },
+    
+    /** 
+     * APIMethod: destroy
+     * Remove reference to child filters.
+     */
+    destroy: function() {
+        this.filters = null;
+        OpenLayers.Filter.prototype.destroy.apply(this);
+    },
+
+    /**
+     * APIMethod: evaluate
+     * Evaluates this filter in a specific context.
+     * 
+     * Parameters:
+     * context - {Object} Context to use in evaluating the filter.  A vector
+     *     feature may also be provided to evaluate feature attributes in 
+     *     comparison filters or geometries in spatial filters.
+     * 
+     * Returns:
+     * {Boolean} The filter applies.
+     */
+    evaluate: function(context) {
+        switch(this.type) {
+            case OpenLayers.Filter.Logical.AND:
+                for (var i=0, len=this.filters.length; i<len; i++) {
+                    if (this.filters[i].evaluate(context) == false) {
+                        return false;
+                    }
+                }
+                return true;
+                
+            case OpenLayers.Filter.Logical.OR:
+                for (var i=0, len=this.filters.length; i<len; i++) {
+                    if (this.filters[i].evaluate(context) == true) {
+                        return true;
+                    }
+                }
+                return false;
+            
+            case OpenLayers.Filter.Logical.NOT:
+                return (!this.filters[0].evaluate(context));
+        }
+    },
+    
+    /**
+     * APIMethod: clone
+     * Clones this filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Logical>} Clone of this filter.
+     */
+    clone: function() {
+        var filters = [];        
+        for(var i=0, len=this.filters.length; i<len; ++i) {
+            filters.push(this.filters[i].clone());
+        }
+        return new OpenLayers.Filter.Logical({
+            type: this.type,
+            filters: filters
+        });
+    },
+    
+    CLASS_NAME: "OpenLayers.Filter.Logical"
+});
+
+
+OpenLayers.Filter.Logical.AND = "&&";
+OpenLayers.Filter.Logical.OR  = "||";
+OpenLayers.Filter.Logical.NOT = "!";
+/* ======================================================================
+    OpenLayers/Filter/Spatial.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Filter.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.Spatial
+ * This class represents a spatial filter.
+ * Currently implemented: BBOX, DWithin and Intersects
+ * 
+ * Inherits from
+ * - <OpenLayers.Filter>
+ */
+OpenLayers.Filter.Spatial = OpenLayers.Class(OpenLayers.Filter, {
+
+    /**
+     * APIProperty: type
+     * {String} Type of spatial filter.
+     *
+     * The type should be one of:
+     * - OpenLayers.Filter.Spatial.BBOX
+     * - OpenLayers.Filter.Spatial.INTERSECTS
+     * - OpenLayers.Filter.Spatial.DWITHIN
+     * - OpenLayers.Filter.Spatial.WITHIN
+     * - OpenLayers.Filter.Spatial.CONTAINS
+     */
+    type: null,
+    
+    /**
+     * APIProperty: property
+     * {String} Name of the context property to compare.
+     */
+    property: null,
+    
+    /**
+     * APIProperty: value
+     * {<OpenLayers.Bounds> || <OpenLayers.Geometry>} The bounds or geometry
+     *     to be used by the filter.  Use bounds for BBOX filters and geometry
+     *     for INTERSECTS or DWITHIN filters.
+     */
+    value: null,
+
+    /**
+     * APIProperty: distance
+     * {Number} The distance to use in a DWithin spatial filter.
+     */
+    distance: null,
+
+    /**
+     * APIProperty: distanceUnits
+     * {String} The units to use for the distance, e.g. 'm'.
+     */
+    distanceUnits: null,
+    
+    /** 
+     * Constructor: OpenLayers.Filter.Spatial
+     * Creates a spatial filter.
+     *
+     * Parameters:
+     * options - {Object} An optional object with properties to set on the
+     *     filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Spatial>}
+     */
+    initialize: function(options) {
+        OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+    },
+
+   /**
+    * Method: evaluate
+    * Evaluates this filter for a specific feature.
+    * 
+    * Parameters:
+    * feature - {<OpenLayers.Feature.Vector>} feature to apply the filter to.
+    * 
+    * Returns:
+    * {Boolean} The feature meets filter criteria.
+    */
+    evaluate: function(feature) {
+        var intersect = false;
+        switch(this.type) {
+            case OpenLayers.Filter.Spatial.BBOX:
+            case OpenLayers.Filter.Spatial.INTERSECTS:
+                if(feature.geometry) {
+                    var geom = this.value;
+                    if(this.value.CLASS_NAME == "OpenLayers.Bounds") {
+                        geom = this.value.toGeometry();
+                    }
+                    if(feature.geometry.intersects(geom)) {
+                        intersect = true;
+                    }
+                }
+                break;
+            default:
+                OpenLayers.Console.error(
+                    OpenLayers.i18n("filterEvaluateNotImplemented"));
+                break;
+        }
+        return intersect;
+    },
+
+    /**
+     * APIMethod: clone
+     * Clones this filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Spatial>} Clone of this filter.
+     */
+    clone: function() {
+        var options = OpenLayers.Util.applyDefaults({
+            value: this.value && this.value.clone && this.value.clone()
+        }, this);
+        return new OpenLayers.Filter.Spatial(options);
+    },
+    CLASS_NAME: "OpenLayers.Filter.Spatial"
+});
+
+OpenLayers.Filter.Spatial.BBOX = "BBOX";
+OpenLayers.Filter.Spatial.INTERSECTS = "INTERSECTS";
+OpenLayers.Filter.Spatial.DWITHIN = "DWITHIN";
+OpenLayers.Filter.Spatial.WITHIN = "WITHIN";
+OpenLayers.Filter.Spatial.CONTAINS = "CONTAINS";
+/* ======================================================================
     OpenLayers/Geometry/Collection.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -31079,21 +33404,21 @@
 
 /**
  * Class: OpenLayers.Geometry.Collection
- * A Collection is exactly what it sounds like: A collection of different
+ * A Collection is exactly what it sounds like: A collection of different 
  * Geometries. These are stored in the local parameter <components> (which
- * can be passed as a parameter to the constructor).
- *
- * As new geometries are added to the collection, they are NOT cloned.
- * When removing geometries, they need to be specified by reference (ie you
+ * can be passed as a parameter to the constructor). 
+ * 
+ * As new geometries are added to the collection, they are NOT cloned. 
+ * When removing geometries, they need to be specified by reference (ie you 
  * have to pass in the *exact* geometry to be removed).
- *
+ * 
  * The <getArea> and <getLength> functions here merely iterate through
  * the components, summing their respective areas and lengths.
  *
  * Create a new instance with the <OpenLayers.Geometry.Collection> constructor.
  *
  * Inerhits from:
- *  - <OpenLayers.Geometry>
+ *  - <OpenLayers.Geometry> 
  */
 OpenLayers.Geometry.Collection = OpenLayers.Class(OpenLayers.Geometry, {
 
@@ -31102,7 +33427,7 @@
      * {Array(<OpenLayers.Geometry>)} The component parts of this geometry
      */
     components: null,
-
+    
     /**
      * Property: componentTypes
      * {Array(String)} An array of class names representing the types of
@@ -31115,7 +33440,7 @@
      * Constructor: OpenLayers.Geometry.Collection
      * Creates a Geometry Collection -- a list of geoms.
      *
-     * Parameters:
+     * Parameters: 
      * components - {Array(<OpenLayers.Geometry>)} Optional array of geometries
      *
      */
@@ -31134,6 +33459,7 @@
     destroy: function () {
         this.components.length = 0;
         this.components = null;
+        OpenLayers.Geometry.prototype.destroy.apply(this, arguments);
     },
 
     /**
@@ -31148,31 +33474,31 @@
         for(var i=0, len=this.components.length; i<len; i++) {
             geometry.addComponent(this.components[i].clone());
         }
-
+        
         // catch any randomly tagged-on properties
         OpenLayers.Util.applyDefaults(geometry, this);
-
+        
         return geometry;
     },
 
     /**
      * Method: getComponentsString
      * Get a string representing the components for this collection
-     *
+     * 
      * Returns:
      * {String} A string representation of the components of this geometry
      */
     getComponentsString: function(){
         var strings = [];
         for(var i=0, len=this.components.length; i<len; i++) {
-            strings.push(this.components[i].toShortString());
+            strings.push(this.components[i].toShortString()); 
         }
         return strings.join(",");
     },
 
     /**
      * APIMethod: calculateBounds
-     * Recalculate the bounds by iterating through the components and
+     * Recalculate the bounds by iterating through the components and 
      * calling calling extendBounds() on each item.
      */
     calculateBounds: function() {
@@ -31207,14 +33533,14 @@
      * is set, then the component class name must be in the componentTypes array.
      *
      * The bounds cache is reset.
-     *
+     * 
      * Parameters:
      * component - {<OpenLayers.Geometry>} A geometry to add
      * index - {int} Optional index into the array to insert the component
      *
      * Returns:
      * {Boolean} The component geometry was successfully added
-     */
+     */    
     addComponent: function(component, index) {
         var added = false;
         if(component) {
@@ -31224,7 +33550,7 @@
 
                 if(index != null && (index < this.components.length)) {
                     var components1 = this.components.slice(0, index);
-                    var components2 = this.components.slice(index,
+                    var components2 = this.components.slice(index, 
                                                            this.components.length);
                     components1.push(component);
                     this.components = components1.concat(components2);
@@ -31238,7 +33564,7 @@
         }
         return added;
     },
-
+    
     /**
      * APIMethod: removeComponents
      * Remove components from this geometry.
@@ -31254,18 +33580,18 @@
             this.removeComponent(components[i]);
         }
     },
-
+    
     /**
      * Method: removeComponent
      * Remove a component from this geometry.
      *
      * Parameters:
-     * component - {<OpenLayers.Geometry>}
+     * component - {<OpenLayers.Geometry>} 
      */
     removeComponent: function(component) {
-
+        
         OpenLayers.Util.removeItem(this.components, component);
-
+        
         // clearBounds() so that it gets recalculated on the next call
         // to this.getBounds();
         this.clearBounds();
@@ -31285,7 +33611,7 @@
         }
         return length;
     },
-
+    
     /**
      * APIMethod: getArea
      * Calculate the area of this geometry. Note how this function is overridden
@@ -31302,7 +33628,7 @@
         return area;
     },
 
-    /**
+    /** 
      * APIMethod: getGeodesicArea
      * Calculate the approximate area of the polygon were it projected onto
      *     the earth.
@@ -31311,7 +33637,7 @@
      * projection - {<OpenLayers.Projection>} The spatial reference system
      *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
      *     assumed.
-     *
+     * 
      * Reference:
      * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
      *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
@@ -31327,26 +33653,71 @@
         }
         return area;
     },
-
+    
     /**
      * APIMethod: getCentroid
      *
+     * Compute the centroid for this geometry collection.
+     *
+     * Parameters:
+     * weighted - {Boolean} Perform the getCentroid computation recursively,
+     * returning an area weighted average of all geometries in this collection.
+     *
      * Returns:
      * {<OpenLayers.Geometry.Point>} The centroid of the collection
      */
-    getCentroid: function() {
-        return this.components.length && this.components[0].getCentroid();
-        /*
-        var centroid;
-        for (var i=0, len=this.components.length; i<len; i++) {
-            if (!centroid) {
-                centroid = this.components[i].getCentroid();
-            } else {
-                centroid.resize(this.components[i].getCentroid(), 0.5);
+    getCentroid: function(weighted) {
+        if (!weighted) {
+            return this.components.length && this.components[0].getCentroid();
+        }
+        var len = this.components.length;
+        if (!len) {
+            return false;
+        }
+        
+        var areas = [];
+        var centroids = [];
+        var areaSum = 0;
+        var minArea = Number.MAX_VALUE;
+        var component;
+        for (var i=0; i<len; ++i) {
+            component = this.components[i];
+            var area = component.getArea();
+            var centroid = component.getCentroid(true);
+            if (isNaN(area) || isNaN(centroid.x) || isNaN(centroid.y)) {
+                continue;
             }
+            areas.push(area);
+            areaSum += area;
+            minArea = (area < minArea && area > 0) ? area : minArea;
+            centroids.push(centroid);
         }
-        return centroid;
-        */
+        len = areas.length;
+        if (areaSum === 0) {
+            // all the components in this collection have 0 area
+            // probably a collection of points -- weight all the points the same
+            for (var i=0; i<len; ++i) {
+                areas[i] = 1;
+            }
+            areaSum = areas.length;
+        } else {
+            // normalize all the areas where the smallest area will get
+            // a value of 1
+            for (var i=0; i<len; ++i) {
+                areas[i] /= minArea;
+            }
+            areaSum /= minArea;
+        }
+        
+        var xSum = 0, ySum = 0, centroid, area;
+        for (var i=0; i<len; ++i) {
+            centroid = centroids[i];
+            area = areas[i];
+            xSum += centroid.x * area;
+            ySum += centroid.y * area;
+        }
+        
+        return new OpenLayers.Geometry.Point(xSum/areaSum, ySum/areaSum);
     },
 
     /**
@@ -31357,7 +33728,7 @@
      * projection - {<OpenLayers.Projection>} The spatial reference system
      *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
      *     assumed.
-     *
+     * 
      * Returns:
      * {Float} The appoximate geodesic length of the geometry in meters.
      */
@@ -31376,7 +33747,7 @@
      *     bounds.
      *
      * Parameters:
-     * x - {Float} Distance to move geometry in positive x direction.
+     * x - {Float} Distance to move geometry in positive x direction. 
      * y - {Float} Distance to move geometry in positive y direction.
      */
     move: function(x, y) {
@@ -31412,9 +33783,9 @@
      *                 will have four times the area).
      * origin - {<OpenLayers.Geometry.Point>} Point of origin for resizing
      * ratio - {Float} Optional x:y ratio for resizing.  Default ratio is 1.
-     *
+     * 
      * Returns:
-     * {OpenLayers.Geometry} - The current geometry.
+     * {OpenLayers.Geometry} - The current geometry. 
      */
     resize: function(scale, origin, ratio) {
         for(var i=0; i<this.components.length; ++i) {
@@ -31453,7 +33824,7 @@
     distanceTo: function(geometry, options) {
         var edge = !(options && options.edge === false);
         var details = edge && options && options.details;
-        var result, best;
+        var result, best, distance;
         var min = Number.POSITIVE_INFINITY;
         for(var i=0, len=this.components.length; i<len; ++i) {
             result = this.components[i].distanceTo(geometry, options);
@@ -31469,13 +33840,13 @@
         return best;
     },
 
-    /**
+    /** 
      * APIMethod: equals
      * Determine whether another geometry is equivalent to this one.  Geometries
      *     are considered equivalent if all components have the same coordinates.
-     *
+     * 
      * Parameters:
-     * geom - {<OpenLayers.Geometry>} The geometry to test.
+     * geom - {<OpenLayers.Geometry>} The geometry to test. 
      *
      * Returns:
      * {Boolean} The supplied geometry is equivalent to this geometry.
@@ -31502,17 +33873,17 @@
     /**
      * APIMethod: transform
      * Reproject the components geometry from source to dest.
-     *
+     * 
      * Parameters:
-     * source - {<OpenLayers.Projection>}
+     * source - {<OpenLayers.Projection>} 
      * dest - {<OpenLayers.Projection>}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Geometry>}
+     * {<OpenLayers.Geometry>} 
      */
     transform: function(source, dest) {
         if (source && dest) {
-            for (var i=0, len=this.components.length; i<len; i++) {
+            for (var i=0, len=this.components.length; i<len; i++) {  
                 var component = this.components[i];
                 component.transform(source, dest);
             }
@@ -31572,8 +33943,9 @@
     OpenLayers/Geometry/Point.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -31582,22 +33954,22 @@
 
 /**
  * Class: OpenLayers.Geometry.Point
- * Point geometry class.
- *
+ * Point geometry class. 
+ * 
  * Inherits from:
- *  - <OpenLayers.Geometry>
+ *  - <OpenLayers.Geometry> 
  */
 OpenLayers.Geometry.Point = OpenLayers.Class(OpenLayers.Geometry, {
 
-    /**
-     * APIProperty: x
-     * {float}
+    /** 
+     * APIProperty: x 
+     * {float} 
      */
     x: null,
 
-    /**
-     * APIProperty: y
-     * {float}
+    /** 
+     * APIProperty: y 
+     * {float} 
      */
     y: null,
 
@@ -31606,20 +33978,20 @@
      * Construct a point geometry.
      *
      * Parameters:
-     * x - {float}
+     * x - {float} 
      * y - {float}
-     *
+     * 
      */
     initialize: function(x, y) {
         OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
-
+        
         this.x = parseFloat(x);
         this.y = parseFloat(y);
     },
 
     /**
      * APIMethod: clone
-     *
+     * 
      * Returns:
      * {<OpenLayers.Geometry.Point>} An exact clone of this OpenLayers.Geometry.Point
      */
@@ -31634,7 +34006,7 @@
         return obj;
     },
 
-    /**
+    /** 
      * Method: calculateBounds
      * Create a new Bounds based on the lon/lat
      */
@@ -31695,14 +34067,14 @@
         }
         return result;
     },
-
-    /**
+    
+    /** 
      * APIMethod: equals
      * Determine whether another geometry is equivalent to this one.  Geometries
      *     are considered equivalent if all components have the same coordinates.
-     *
+     * 
      * Parameters:
-     * geom - {<OpenLayers.Geometry.Point>} The geometry to test.
+     * geom - {<OpenLayers.Geometry.Point>} The geometry to test. 
      *
      * Returns:
      * {Boolean} The supplied geometry is equivalent to this geometry.
@@ -31715,18 +34087,18 @@
         }
         return equals;
     },
-
+    
     /**
      * Method: toShortString
      *
      * Returns:
-     * {String} Shortened String representation of Point object.
+     * {String} Shortened String representation of Point object. 
      *         (ex. <i>"5, 42"</i>)
      */
     toShortString: function() {
         return (this.x + ", " + this.y);
     },
-
+    
     /**
      * APIMethod: move
      * Moves a geometry by the given displacement along positive x and y axes.
@@ -31734,7 +34106,7 @@
      *     bounds.
      *
      * Parameters:
-     * x - {Float} Distance to move geometry in positive x direction.
+     * x - {Float} Distance to move geometry in positive x direction. 
      * y - {Float} Distance to move geometry in positive y direction.
      */
     move: function(x, y) {
@@ -31760,7 +34132,7 @@
         this.y = origin.y + (radius * Math.sin(theta));
         this.clearBounds();
     },
-
+    
     /**
      * APIMethod: getCentroid
      *
@@ -31783,9 +34155,9 @@
      *                 distance between the point and origin.
      * origin - {<OpenLayers.Geometry.Point>} Point of origin for resizing
      * ratio - {Float} Optional x:y ratio for resizing.  Default ratio is 1.
-     *
+     * 
      * Returns:
-     * {OpenLayers.Geometry} - The current geometry.
+     * {OpenLayers.Geometry} - The current geometry. 
      */
     resize: function(scale, origin, ratio) {
         ratio = (ratio == undefined) ? 1 : ratio;
@@ -31794,7 +34166,7 @@
         this.clearBounds();
         return this;
     },
-
+    
     /**
      * APIMethod: intersects
      * Determine if the input geometry intersects this one.
@@ -31814,24 +34186,24 @@
         }
         return intersect;
     },
-
+    
     /**
      * APIMethod: transform
      * Translate the x,y properties of the point from source to dest.
-     *
+     * 
      * Parameters:
-     * source - {<OpenLayers.Projection>}
+     * source - {<OpenLayers.Projection>} 
      * dest - {<OpenLayers.Projection>}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Geometry>}
+     * {<OpenLayers.Geometry>} 
      */
     transform: function(source, dest) {
         if ((source && dest)) {
             OpenLayers.Projection.transform(
-                this, source, dest);
+                this, source, dest); 
             this.bounds = null;
-        }
+        }       
         return this;
     },
 
@@ -31858,8 +34230,9 @@
     OpenLayers/Layer/Vector.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -31914,6 +34287,9 @@
      * beforefeatureremoved - Triggered before a feature is removed. Listeners
      *      will receive an object with a *feature* property referencing the
      *      feature to be removed.
+     * beforefeaturesremoved - Triggered before multiple features are removed. 
+     *      Listeners will receive an object with a *features* property
+     *      referencing the features to be removed.
      * featureremoved - Triggerd after a feature is removed. The event
      *      object passed to listeners will have a *feature* property with a
      *      reference to the removed feature.
@@ -31926,14 +34302,14 @@
      * featureunselected - Triggered after a feature is unselected.
      *      Listeners will receive an object with a *feature* property
      *      referencing the unselected feature.
-     * beforefeaturemodified - Triggered when a feature is selected to
-     *      be modified.  Listeners will receive an object with a *feature*
+     * beforefeaturemodified - Triggered when a feature is selected to 
+     *      be modified.  Listeners will receive an object with a *feature* 
      *      property referencing the selected feature.
      * featuremodified - Triggered when a feature has been modified.
-     *      Listeners will receive an object with a *feature* property referencing
+     *      Listeners will receive an object with a *feature* property referencing 
      *      the modified feature.
      * afterfeaturemodified - Triggered when a feature is finished being modified.
-     *      Listeners will receive an object with a *feature* property referencing
+     *      Listeners will receive an object with a *feature* property referencing 
      *      the modified feature.
      * vertexmodified - Triggered when a vertex within any feature geometry
      *      has been modified.  Listeners will receive an object with a
@@ -31957,45 +34333,53 @@
      *      for a new set of features.
      */
     EVENT_TYPES: ["beforefeatureadded", "beforefeaturesadded",
-                  "featureadded", "featuresadded",
-                  "beforefeatureremoved", "featureremoved", "featuresremoved",
-                  "beforefeatureselected", "featureselected", "featureunselected",
+                  "featureadded", "featuresadded", "beforefeatureremoved",
+                  "beforefeaturesremoved", "featureremoved", "featuresremoved",
+                  "beforefeatureselected", "featureselected", "featureunselected", 
                   "beforefeaturemodified", "featuremodified", "afterfeaturemodified",
                   "vertexmodified", "sketchstarted", "sketchmodified",
                   "sketchcomplete", "refresh"],
 
     /**
      * APIProperty: isBaseLayer
-     * {Boolean} The layer is a base layer.  Default is true.  Set this property
-     * in the layer options
+     * {Boolean} The layer is a base layer.  Default is false.  Set this property
+     * in the layer options.
      */
     isBaseLayer: false,
 
-    /**
+    /** 
      * APIProperty: isFixed
      * {Boolean} Whether the layer remains in one place while dragging the
      * map.
      */
     isFixed: false,
 
-    /**
+    /** 
      * APIProperty: isVector
      * {Boolean} Whether the layer is a vector layer.
      */
     isVector: true,
-
-    /**
+    
+    /** 
      * APIProperty: features
-     * {Array(<OpenLayers.Feature.Vector>)}
+     * {Array(<OpenLayers.Feature.Vector>)} 
      */
     features: null,
-
-    /**
+    
+    /** 
+     * Property: filter
+     * {<OpenLayers.Filter>} The filter set in this layer,
+     *     a strategy launching read requests can combined
+     *     this filter with its own filter.
+     */
+    filter: null,
+    
+    /** 
      * Property: selectedFeatures
-     * {Array(<OpenLayers.Feature.Vector>)}
+     * {Array(<OpenLayers.Feature.Vector>)} 
      */
     selectedFeatures: null,
-
+    
     /**
      * Property: unrenderedFeatures
      * {Object} hash of features, keyed by feature.id, that the renderer
@@ -32008,32 +34392,32 @@
      * {Boolean} report friendly error message when loading of renderer
      * fails.
      */
-    reportError: true,
+    reportError: true, 
 
-    /**
+    /** 
      * APIProperty: style
      * {Object} Default style for the layer
      */
     style: null,
-
+    
     /**
      * Property: styleMap
      * {<OpenLayers.StyleMap>}
      */
     styleMap: null,
-
+    
     /**
      * Property: strategies
      * {Array(<OpenLayers.Strategy>})} Optional list of strategies for the layer.
      */
     strategies: null,
-
+    
     /**
      * Property: protocol
      * {<OpenLayers.Protocol>} Optional protocol for the layer.
      */
     protocol: null,
-
+    
     /**
      * Property: renderers
      * {Array(String)} List of supported Renderer classes. Add to this list to
@@ -32042,21 +34426,21 @@
      * method will be used, if not defined in the 'renderer' option.
      */
     renderers: ['SVG', 'VML', 'Canvas'],
-
-    /**
+    
+    /** 
      * Property: renderer
      * {<OpenLayers.Renderer>}
      */
     renderer: null,
-
+    
     /**
      * APIProperty: rendererOptions
      * {Object} Options for the renderer. See {<OpenLayers.Renderer>} for
      *     supported options.
      */
     rendererOptions: null,
-
-    /**
+    
+    /** 
      * APIProperty: geometryType
      * {String} geometryType allows you to limit the types of geometries this
      * layer supports. This should be set to something like
@@ -32064,7 +34448,7 @@
      */
     geometryType: null,
 
-    /**
+    /** 
      * Property: drawn
      * {Boolean} Whether the Vector Layer features have been drawn yet.
      */
@@ -32083,7 +34467,7 @@
      * {<OpenLayers.Layer.Vector>} A new vector layer
      */
     initialize: function(name, options) {
-
+        
         // concatenate events specific to vector with those from the base
         this.EVENT_TYPES =
             OpenLayers.Layer.Vector.prototype.EVENT_TYPES.concat(
@@ -32093,7 +34477,7 @@
         OpenLayers.Layer.prototype.initialize.apply(this, arguments);
 
         // allow user-set renderer, otherwise assign one
-        if (!this.renderer || !this.renderer.supported()) {
+        if (!this.renderer || !this.renderer.supported()) {  
             this.assignRenderer();
         }
 
@@ -32101,7 +34485,7 @@
         if (!this.renderer || !this.renderer.supported()) {
             this.renderer = null;
             this.displayError();
-        }
+        } 
 
         if (!this.styleMap) {
             this.styleMap = new OpenLayers.StyleMap();
@@ -32110,7 +34494,7 @@
         this.features = [];
         this.selectedFeatures = [];
         this.unrenderedFeatures = {};
-
+        
         // Allow for custom layer behavior
         if(this.strategies){
             for(var i=0, len=this.strategies.length; i<len; i++) {
@@ -32151,10 +34535,40 @@
         this.renderer = null;
         this.geometryType = null;
         this.drawn = null;
-        OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+        OpenLayers.Layer.prototype.destroy.apply(this, arguments);  
     },
 
     /**
+     * Method: clone
+     * Create a clone of this layer.
+     * 
+     * Note: Features of the layer are also cloned.
+     *
+     * Returns:
+     * {<OpenLayers.Layer.Vector>} An exact clone of this layer
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.Vector(this.name, this.getOptions());
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+        var features = this.features;
+        var len = features.length;
+        var clonedFeatures = new Array(len);
+        for(var i=0; i<len; ++i) {
+            clonedFeatures[i] = features[i].clone();
+        }
+        obj.features = clonedFeatures;
+
+        return obj;
+    },    
+    
+    /**
      * Method: refresh
      * Ask the layer to request features again and redraw them.  Triggers
      *     the refresh event if the layer is in range and visible.
@@ -32169,44 +34583,46 @@
         }
     },
 
-    /**
+    /** 
      * Method: assignRenderer
-     * Iterates through the available renderer implementations and selects
+     * Iterates through the available renderer implementations and selects 
      * and assigns the first one whose "supported()" function returns true.
-     */
+     */    
     assignRenderer: function()  {
         for (var i=0, len=this.renderers.length; i<len; i++) {
-            var rendererClass = OpenLayers.Renderer[this.renderers[i]];
-            if (rendererClass && rendererClass.prototype.supported()) {
-                this.renderer = new rendererClass(this.div,
-                    this.rendererOptions);
+            var rendererClass = this.renderers[i];
+            var renderer = (typeof rendererClass == "function") ?
+                rendererClass :
+                OpenLayers.Renderer[rendererClass];
+            if (renderer && renderer.prototype.supported()) {
+                this.renderer = new renderer(this.div, this.rendererOptions);
                 break;
-            }
-        }
+            }  
+        }  
     },
 
-    /**
-     * Method: displayError
+    /** 
+     * Method: displayError 
      * Let the user know their browser isn't supported.
      */
     displayError: function() {
         if (this.reportError) {
-            OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",
+            OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported", 
                                      {'renderers':this.renderers.join("\n")}));
-        }
+        }    
     },
 
-    /**
+    /** 
      * Method: setMap
-     * The layer has been added to the map.
-     *
+     * The layer has been added to the map. 
+     * 
      * If there is no renderer set, the layer can't be used. Remove it.
      * Otherwise, give the renderer a reference to the map and set its size.
-     *
+     * 
      * Parameters:
-     * map - {<OpenLayers.Map>}
+     * map - {<OpenLayers.Map>} 
      */
-    setMap: function(map) {
+    setMap: function(map) {        
         OpenLayers.Layer.prototype.setMap.apply(this, arguments);
 
         if (!this.renderer) {
@@ -32243,6 +34659,7 @@
      * map - {<OpenLayers.Map>}
      */
     removeMap: function(map) {
+        this.drawn = false;
         if(this.strategies) {
             var strategy, i, len;
             for(i=0, len=this.strategies.length; i<len; i++) {
@@ -32253,11 +34670,11 @@
             }
         }
     },
-
+    
     /**
      * Method: onMapResize
-     * Notify the renderer of the change in size.
-     *
+     * Notify the renderer of the change in size. 
+     * 
      */
     onMapResize: function() {
         OpenLayers.Layer.prototype.onMapResize.apply(this, arguments);
@@ -32266,32 +34683,32 @@
 
     /**
      * Method: moveTo
-     *  Reset the vector layer's div so that it once again is lined up with
+     *  Reset the vector layer's div so that it once again is lined up with 
      *   the map. Notify the renderer of the change of extent, and in the
-     *   case of a change of zoom level (resolution), have the
+     *   case of a change of zoom level (resolution), have the 
      *   renderer redraw features.
-     *
-     *  If the layer has not yet been drawn, cycle through the layer's
+     * 
+     *  If the layer has not yet been drawn, cycle through the layer's 
      *   features and draw each one.
-     *
+     * 
      * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * zoomChanged - {Boolean}
-     * dragging - {Boolean}
+     * bounds - {<OpenLayers.Bounds>} 
+     * zoomChanged - {Boolean} 
+     * dragging - {Boolean} 
      */
     moveTo: function(bounds, zoomChanged, dragging) {
         OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
-
+        
         var coordSysUnchanged = true;
 
         if (!dragging) {
             this.renderer.root.style.visibility = "hidden";
-
+            
             this.div.style.left = -parseInt(this.map.layerContainerDiv.style.left) + "px";
             this.div.style.top = -parseInt(this.map.layerContainerDiv.style.top) + "px";
             var extent = this.map.getExtent();
             coordSysUnchanged = this.renderer.setExtent(extent, zoomChanged);
-
+            
             this.renderer.root.style.visibility = "visible";
 
             // Force a reflow on gecko based browsers to prevent jump/flicker.
@@ -32300,7 +34717,7 @@
             if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) {
                 this.div.scrollLeft = this.div.scrollLeft;
             }
-
+            
             if(!zoomChanged && coordSysUnchanged) {
                 for(var i in this.unrenderedFeatures) {
                     var feature = this.unrenderedFeatures[i];
@@ -32308,7 +34725,7 @@
                 }
             }
         }
-
+        
         if (!this.drawn || zoomChanged || !coordSysUnchanged) {
             this.drawn = true;
             var feature;
@@ -32317,13 +34734,13 @@
                 feature = this.features[i];
                 this.drawFeature(feature);
             }
-        }
+        }    
     },
-
-    /**
+    
+    /** 
      * APIMethod: display
      * Hide or show the Layer
-     *
+     * 
      * Parameters:
      * display - {Boolean}
      */
@@ -32342,14 +34759,14 @@
      * Add Features to the layer.
      *
      * Parameters:
-     * features - {Array(<OpenLayers.Feature.Vector>)}
+     * features - {Array(<OpenLayers.Feature.Vector>)} 
      * options - {Object}
      */
     addFeatures: function(features, options) {
         if (!(features instanceof Array)) {
             features = [features];
         }
-
+        
         var notify = !options || !options.silent;
         if(notify) {
             var event = {features: features};
@@ -32359,16 +34776,18 @@
             }
             features = event.features;
         }
-
-
+        
+        // Track successfully added features for featuresadded event, since
+        // beforefeatureadded can veto single features.
+        var featuresAdded = [];
         for (var i=0, len=features.length; i<len; i++) {
             if (i != (features.length - 1)) {
                 this.renderer.locked = true;
             } else {
                 this.renderer.locked = false;
-            }
+            }    
             var feature = features[i];
-
+            
             if (this.geometryType &&
               !(feature.geometry instanceof this.geometryType)) {
                 var throwStr = OpenLayers.i18n('componentShouldBe',
@@ -32376,8 +34795,6 @@
                 throw throwStr;
               }
 
-            this.features.push(feature);
-
             //give feature reference to its layer
             feature.layer = this;
 
@@ -32393,8 +34810,10 @@
                 this.preFeatureInsert(feature);
             }
 
+            featuresAdded.push(feature);
+            this.features.push(feature);
             this.drawFeature(feature);
-
+            
             if (notify) {
                 this.events.triggerEvent("featureadded", {
                     feature: feature
@@ -32402,9 +34821,9 @@
                 this.onFeatureInsert(feature);
             }
         }
-
+        
         if(notify) {
-            this.events.triggerEvent("featuresadded", {features: features});
+            this.events.triggerEvent("featuresadded", {features: featuresAdded});
         }
     },
 
@@ -32416,7 +34835,7 @@
      *     and featureremoved events will be triggered for each feature.  The
      *     featuresremoved event will be triggered after all features have
      *     been removed.  To supress event triggering, use the silent option.
-     *
+     * 
      * Parameters:
      * features - {Array(<OpenLayers.Feature.Vector>)} List of features to be
      *     removed.
@@ -32430,14 +34849,23 @@
         if(!features || features.length === 0) {
             return;
         }
+        if (features === this.features) {
+            return this.removeAllFeatures(options);
+        }
         if (!(features instanceof Array)) {
             features = [features];
         }
-        if (features === this.features) {
+        if (features === this.selectedFeatures) {
             features = features.slice();
         }
 
         var notify = !options || !options.silent;
+        
+        if (notify) {
+            this.events.triggerEvent(
+                "beforefeaturesremoved", {features: features}
+            );
+        }
 
         for (var i = features.length - 1; i >= 0; i--) {
             // We remain locked so long as we're not at 0
@@ -32445,15 +34873,15 @@
             // because if all the features after the current one are 'null', we
             // won't call eraseGeometry, so we break the 'renderer functions
             // will always be called with locked=false *last*' rule. The end result
-            // is a possible gratiutious unlocking to save a loop through the rest
+            // is a possible gratiutious unlocking to save a loop through the rest 
             // of the list checking the remaining features every time. So long as
-            // null geoms are rare, this is probably okay.
+            // null geoms are rare, this is probably okay.    
             if (i != 0 && features[i-1].geometry) {
                 this.renderer.locked = true;
             } else {
                 this.renderer.locked = false;
             }
-
+    
             var feature = features[i];
             delete this.unrenderedFeatures[feature.id];
 
@@ -32470,8 +34898,8 @@
             if (feature.geometry) {
                 this.renderer.eraseFeatures(feature);
             }
-
-            //in the case that this feature is one of the selected features,
+                    
+            //in the case that this feature is one of the selected features, 
             // remove it from that array as well.
             if (OpenLayers.Util.indexOf(this.selectedFeatures, feature) != -1){
                 OpenLayers.Util.removeItem(this.selectedFeatures, feature);
@@ -32488,6 +34916,49 @@
             this.events.triggerEvent("featuresremoved", {features: features});
         }
     },
+    
+    /** 
+     * APIMethod: removeAllFeatures
+     * Remove all features from the layer.
+     *
+     * Parameters:
+     * options - {Object} Optional properties for changing behavior of the
+     *     removal.
+     *
+     * Valid options:
+     * silent - {Boolean} Supress event triggering.  Default is false.
+     */
+    removeAllFeatures: function(options) {
+        var notify = !options || !options.silent;
+        var features = this.features;
+        if (notify) {
+            this.events.triggerEvent(
+                "beforefeaturesremoved", {features: features}
+            );
+        }
+        var feature;
+        for (var i = features.length-1; i >= 0; i--) {
+            feature = features[i];
+            if (notify) {
+                this.events.triggerEvent("beforefeatureremoved", {
+                    feature: feature
+                });
+            }
+            feature.layer = null;
+            if (notify) {
+                this.events.triggerEvent("featureremoved", {
+                    feature: feature
+                });
+            }
+        }
+        this.renderer.clear();
+        this.features = [];
+        this.unrenderedFeatures = {};
+        this.selectedFeatures = [];
+        if (notify) {
+            this.events.triggerEvent("featuresremoved", {features: features});
+        }
+    },
 
     /**
      * APIMethod: destroyFeatures
@@ -32519,20 +34990,20 @@
      * is included, this style will be used.  If no style is included, the
      * feature's style will be used.  If the feature doesn't have a style,
      * the layer's style will be used.
-     *
-     * This function is not designed to be used when adding features to
+     * 
+     * This function is not designed to be used when adding features to 
      * the layer (use addFeatures instead). It is meant to be used when
-     * the style of a feature has changed, or in some other way needs to
+     * the style of a feature has changed, or in some other way needs to 
      * visually updated *after* it has already been added to a layer. You
-     * must add the feature to the layer for most layer-related events to
+     * must add the feature to the layer for most layer-related events to 
      * happen.
      *
-     * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>}
-     * style - {Object} Symbolizer hash or {String} renderIntent
+     * Parameters: 
+     * feature - {<OpenLayers.Feature.Vector>} 
+     * style - {String | Object} Named render intent or full symbolizer object.
      */
     drawFeature: function(feature, style) {
-        // don't try to draw the feature with the renderer if the layer is not
+        // don't try to draw the feature with the renderer if the layer is not 
         // drawn itself
         if (!this.drawn) {
             return
@@ -32547,20 +35018,20 @@
                 style = this.styleMap.createSymbolizer(feature, renderIntent);
             }
         }
-
+        
         if (!this.renderer.drawFeature(feature, style)) {
             this.unrenderedFeatures[feature.id] = feature;
         } else {
             delete this.unrenderedFeatures[feature.id];
         };
     },
-
+    
     /**
      * Method: eraseFeatures
      * Erase features from the layer.
      *
      * Parameters:
-     * features - {Array(<OpenLayers.Feature.Vector>)}
+     * features - {Array(<OpenLayers.Feature.Vector>)} 
      */
     eraseFeatures: function(features) {
         this.renderer.eraseFeatures(features);
@@ -32572,36 +35043,37 @@
      * Otherwise, return null.
      *
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      *
      * Returns:
      * {<OpenLayers.Feature.Vector>} A feature if one was under the event.
      */
     getFeatureFromEvent: function(evt) {
         if (!this.renderer) {
-            OpenLayers.Console.error(OpenLayers.i18n("getFeatureError"));
+            OpenLayers.Console.error(OpenLayers.i18n("getFeatureError")); 
             return null;
-        }
+        }    
         var featureId = this.renderer.getFeatureIdFromEvent(evt);
         return this.getFeatureById(featureId);
     },
 
     /**
-     * APIMethod: getFeatureById
-     * Given a feature id, return the feature if it exists in the features array
+     * APIMethod: getFeatureBy
+     * Given a property value, return the feature if it exists in the features array
      *
      * Parameters:
-     * featureId - {String}
+     * property - {String}
+     * value - {String}
      *
      * Returns:
      * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
-     * featureId
+     * property value or null if there is no such feature.
      */
-    getFeatureById: function(featureId) {
+    getFeatureBy: function(property, value) {
         //TBD - would it be more efficient to use a hash for this.features?
         var feature = null;
         for(var i=0, len=this.features.length; i<len; ++i) {
-            if(this.features[i].id == featureId) {
+            if(this.features[i][property] == value) {
                 feature = this.features[i];
                 break;
             }
@@ -32610,6 +35082,36 @@
     },
 
     /**
+     * APIMethod: getFeatureById
+     * Given a feature id, return the feature if it exists in the features array
+     *
+     * Parameters:
+     * featureId - {String}
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
+     * featureId or null if there is no such feature.
+     */
+    getFeatureById: function(featureId) {
+        return this.getFeatureBy('id', featureId);
+    },
+
+    /**
+     * APIMethod: getFeatureByFid
+     * Given a feature fid, return the feature if it exists in the features array
+     *
+     * Parameters:
+     * featureFid - {String}
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
+     * featureFid or null if there is no such feature.
+     */
+    getFeatureByFid: function(featureFid) {
+        return this.getFeatureBy('fid', featureFid);
+    },
+
+    /**
      * Unselect the selected features
      * i.e. clears the featureSelection array
      * change the style back
@@ -32631,12 +35133,12 @@
      * Does nothing by default. Override this if you
      * need to do something on feature updates.
      *
-     * Paarameters:
-     * feature - {<OpenLayers.Feature.Vector>}
+     * Paarameters: 
+     * feature - {<OpenLayers.Feature.Vector>} 
      */
     onFeatureInsert: function(feature) {
     },
-
+    
     /**
      * APIMethod: preFeatureInsert
      * method called before a feature is inserted.
@@ -32645,28 +35147,31 @@
      * layer, but before they are drawn, such as adjust the style.
      *
      * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>}
+     * feature - {<OpenLayers.Feature.Vector>} 
      */
     preFeatureInsert: function(feature) {
     },
 
-    /**
+    /** 
      * APIMethod: getDataExtent
      * Calculates the max extent which includes all of the features.
-     *
+     * 
      * Returns:
      * {<OpenLayers.Bounds>}
      */
     getDataExtent: function () {
         var maxExtent = null;
-
-        if(this.features && (this.features.length > 0)) {
+        var features = this.features;
+        if(features && (features.length > 0)) {
             maxExtent = new OpenLayers.Bounds();
-            for(var i=0, len=this.features.length; i<len; i++) {
-                maxExtent.extend(this.features[i].geometry.getBounds());
+            var geometry = null;
+            for(var i=0, len=features.length; i<len; i++) {
+                geometry = features[i].geometry;
+                if (geometry) {
+                    maxExtent.extend(geometry.getBounds());
+                }
             }
         }
-
         return maxExtent;
     },
 
@@ -32676,8 +35181,9 @@
     OpenLayers/Geometry/MultiPoint.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -32710,13 +35216,13 @@
      * Create a new MultiPoint Geometry
      *
      * Parameters:
-     * components - {Array(<OpenLayers.Geometry.Point>)}
+     * components - {Array(<OpenLayers.Geometry.Point>)} 
      *
      * Returns:
      * {<OpenLayers.Geometry.MultiPoint>}
      */
     initialize: function(components) {
-        OpenLayers.Geometry.Collection.prototype.initialize.apply(this,
+        OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
                                                                   arguments);
     },
 
@@ -32731,7 +35237,7 @@
     addPoint: function(point, index) {
         this.addComponent(point, index);
     },
-
+    
     /**
      * APIMethod: removePoint
      * Wrapper for <OpenLayers.Geometry.Collection.removeComponent>
@@ -32749,8 +35255,9 @@
     OpenLayers/Handler/Point.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -32767,12 +35274,12 @@
  *     called with each change in the sketch and will receive the latest point
  *     drawn.  Create a new instance with the <OpenLayers.Handler.Point>
  *     constructor.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Handler>
  */
 OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, {
-
+    
     /**
      * Property: point
      * {<OpenLayers.Feature.Vector>} The currently drawn point
@@ -32784,20 +35291,20 @@
      * {<OpenLayers.Layer.Vector>} The temporary drawing layer
      */
     layer: null,
-
+    
     /**
-     * Property: multi
+     * APIProperty: multi
      * {Boolean} Cast features to multi-part geometries before passing to the
      *     layer.  Default is false.
      */
     multi: false,
-
+    
     /**
-     * Property: drawing
+     * Property: drawing 
      * {Boolean} A point is being drawn
      */
     drawing: false,
-
+    
     /**
      * Property: mouseDown
      * {Boolean} The mouse is down
@@ -32859,7 +35366,7 @@
 
         OpenLayers.Handler.prototype.initialize.apply(this, arguments);
     },
-
+    
     /**
      * APIMethod: activate
      * turn on the handler
@@ -32876,13 +35383,13 @@
             // without this, resolution properties must be specified at the
             // map-level for this temporary layer to init its resolutions
             // correctly
-            calculateInRange: function() { return true; }
+            calculateInRange: OpenLayers.Function.True
         }, this.layerOptions);
         this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
         this.map.addLayer(this.layer);
         return true;
     },
-
+    
     /**
      * Method: createFeature
      * Add temporary features
@@ -32924,7 +35431,7 @@
         this.layer = null;
         return true;
     },
-
+    
     /**
      * Method: destroyFeature
      * Destroy the temporary geometries
@@ -32968,11 +35475,11 @@
      * Method: click
      * Handle clicks.  Clicks are stopped from propagating to other listeners
      *     on map.events or other dom elements.
-     *
+     * 
      * Parameters:
      * evt - {Event} The browser event
      *
-     * Returns:
+     * Returns: 
      * {Boolean} Allow event propagation
      */
     click: function(evt) {
@@ -32984,18 +35491,18 @@
      * Method: dblclick
      * Handle double-clicks.  Double-clicks are stopped from propagating to other
      *     listeners on map.events or other dom elements.
-     *
+     * 
      * Parameters:
      * evt - {Event} The browser event
      *
-     * Returns:
+     * Returns: 
      * {Boolean} Allow event propagation
      */
     dblclick: function(evt) {
         OpenLayers.Event.stop(evt);
         return false;
     },
-
+    
     /**
      * Method: modifyFeature
      * Modify the existing geometry given a pixel location.
@@ -33019,7 +35526,7 @@
     drawFeature: function() {
         this.layer.drawFeature(this.point, this.style);
     },
-
+    
     /**
      * Method: getGeometry
      * Return the sketch geometry.  If <multi> is true, this will return
@@ -33047,16 +35554,16 @@
         var geom = this.getGeometry();
         return geom && geom.clone();
     },
-
+  
     /**
      * Method: mousedown
      * Handle mouse down.  Adjust the geometry and redraw.
      * Return determines whether to propagate the event on the map.
-     *
+     * 
      * Parameters:
      * evt - {Event} The browser event
      *
-     * Returns:
+     * Returns: 
      * {Boolean} Allow event propagation
      */
     mousedown: function(evt) {
@@ -33085,11 +35592,11 @@
      * Method: mousemove
      * Handle mouse move.  Adjust the geometry and redraw.
      * Return determines whether to propagate the event on the map.
-     *
+     * 
      * Parameters:
      * evt - {Event} The browser event
      *
-     * Returns:
+     * Returns: 
      * {Boolean} Allow event propagation
      */
     mousemove: function (evt) {
@@ -33107,7 +35614,7 @@
      * Parameters:
      * evt - {Event} The browser event
      *
-     * Returns:
+     * Returns: 
      * {Boolean} Allow event propagation
      */
     mouseup: function (evt) {
@@ -33122,11 +35629,671 @@
     CLASS_NAME: "OpenLayers.Handler.Point"
 });
 /* ======================================================================
+    OpenLayers/Protocol/HTTP.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Protocol.js
+ * @requires OpenLayers/Feature/Vector.js
+ * @requires OpenLayers/Filter/Spatial.js
+ * @requires OpenLayers/Filter/Comparison.js
+ * @requires OpenLayers/Filter/Logical.js
+ * @requires OpenLayers/Request/XMLHttpRequest.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.HTTP
+ * A basic HTTP protocol for vector layers.  Create a new instance with the
+ *     <OpenLayers.Protocol.HTTP> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Protocol>
+ */
+OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
+
+    /**
+     * Property: url
+     * {String} Service URL, read-only, set through the options
+     *     passed to constructor.
+     */
+    url: null,
+
+    /**
+     * Property: headers
+     * {Object} HTTP request headers, read-only, set through the options
+     *     passed to the constructor,
+     *     Example: {'Content-Type': 'plain/text'}
+     */
+    headers: null,
+
+    /**
+     * Property: params
+     * {Object} Parameters of GET requests, read-only, set through the options
+     *     passed to the constructor,
+     *     Example: {'bbox': '5,5,5,5'}
+     */
+    params: null,
+    
+    /**
+     * Property: callback
+     * {Object} Function to be called when the <read>, <create>,
+     *     <update>, <delete> or <commit> operation completes, read-only,
+     *     set through the options passed to the constructor.
+     */
+    callback: null,
+
+    /**
+     * Property: scope
+     * {Object} Callback execution scope, read-only, set through the
+     *     options passed to the constructor.
+     */
+    scope: null,
+
+    /**
+     * Property: readWithPOST
+     * {Boolean} true if read operations are done with POST requests
+     *     instead of GET, defaults to false.
+     */
+    readWithPOST: false,
+
+    /**
+     * Property: wildcarded.
+     * {Boolean} If true percent signs are added around values
+     *     read from LIKE filters, for example if the protocol
+     *     read method is passed a LIKE filter whose property
+     *     is "foo" and whose value is "bar" the string
+     *     "foo__ilike=%bar%" will be sent in the query string;
+     *     defaults to false.
+     */
+    wildcarded: false,
+
+    /**
+     * Constructor: OpenLayers.Protocol.HTTP
+     * A class for giving layers generic HTTP protocol.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     *
+     * Valid options include:
+     * url - {String}
+     * headers - {Object} 
+     * params - {Object}
+     * format - {<OpenLayers.Format>}
+     * callback - {Function}
+     * scope - {Object}
+     */
+    initialize: function(options) {
+        options = options || {};
+        this.params = {};
+        this.headers = {};
+        OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Clean up the protocol.
+     */
+    destroy: function() {
+        this.params = null;
+        this.headers = null;
+        OpenLayers.Protocol.prototype.destroy.apply(this);
+    },
+   
+    /**
+     * APIMethod: read
+     * Construct a request for reading new features.
+     *
+     * Parameters:
+     * options - {Object} Optional object for configuring the request.
+     *     This object is modified and should not be reused.
+     *
+     * Valid options:
+     * url - {String} Url for the request.
+     * params - {Object} Parameters to get serialized as a query string.
+     * headers - {Object} Headers to be set on the request.
+     * filter - {<OpenLayers.Filter>} Filter to get serialized as a
+     *     query string.
+     * readWithPOST - {Boolean} If the request should be done with POST.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
+     *     references the HTTP request, this object is also passed to the
+     *     callback function when the request completes, its "features" property
+     *     is then populated with the the features received from the server.
+     */
+    read: function(options) {
+        OpenLayers.Protocol.prototype.read.apply(this, arguments);
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+        options.params = OpenLayers.Util.applyDefaults(
+            options.params, this.options.params);
+        if(options.filter) {
+            options.params = this.filterToParams(
+                options.filter, options.params);
+        }
+        var readWithPOST = (options.readWithPOST !== undefined) ?
+                           options.readWithPOST : this.readWithPOST;
+        var resp = new OpenLayers.Protocol.Response({requestType: "read"});
+        if(readWithPOST) {
+            resp.priv = OpenLayers.Request.POST({
+                url: options.url,
+                callback: this.createCallback(this.handleRead, resp, options),
+                data: OpenLayers.Util.getParameterString(options.params),
+                headers: {
+                    "Content-Type": "application/x-www-form-urlencoded"
+                }
+            });
+        } else {
+            resp.priv = OpenLayers.Request.GET({
+                url: options.url,
+                callback: this.createCallback(this.handleRead, resp, options),
+                params: options.params,
+                headers: options.headers
+            });
+        }
+        return resp;
+    },
+
+    /**
+     * Method: handleRead
+     * Individual callbacks are created for read, create and update, should
+     *     a subclass need to override each one separately.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+     *     the user callback.
+     * options - {Object} The user options passed to the read call.
+     */
+    handleRead: function(resp, options) {
+        this.handleResponse(resp, options);
+    },
+
+    /**
+     * Method: filterToParams
+     * Convert an <OpenLayers.Filter> object to parameters.
+     *
+     * Parameters:
+     * filter - {OpenLayers.Filter} filter to convert.
+     * params - {Object} The parameters object.
+     *
+     * Returns:
+     * {Object} The resulting parameters object.
+     */
+    filterToParams: function(filter, params) {
+        params = params || {};
+        var className = filter.CLASS_NAME;
+        var filterType = className.substring(className.lastIndexOf(".") + 1);
+        switch(filterType) {
+            case "Spatial":
+                switch(filter.type) {
+                    case OpenLayers.Filter.Spatial.BBOX:
+                        params.bbox = filter.value.toArray();
+                        break;
+                    case OpenLayers.Filter.Spatial.DWITHIN:
+                        params.tolerance = filter.distance;
+                        // no break here
+                    case OpenLayers.Filter.Spatial.WITHIN:
+                        params.lon = filter.value.x;
+                        params.lat = filter.value.y;
+                        break;
+                    default:
+                        OpenLayers.Console.warn(
+                            "Unknown spatial filter type " + filter.type);
+                }
+                break;
+            case "Comparison":
+                var op = OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR[filter.type];
+                if(op !== undefined) {
+                    var value = filter.value;
+                    if(filter.type == OpenLayers.Filter.Comparison.LIKE) {
+                        value = this.regex2value(value);
+                        if(this.wildcarded) {
+                            value = "%" + value + "%";
+                        }
+                    }
+                    params[filter.property + "__" + op] = value;
+                    params.queryable = params.queryable || [];
+                    params.queryable.push(filter.property);
+                } else {
+                    OpenLayers.Console.warn(
+                        "Unknown comparison filter type " + filter.type);
+                }
+                break;
+            case "Logical":
+                if(filter.type === OpenLayers.Filter.Logical.AND) {
+                    for(var i=0,len=filter.filters.length; i<len; i++) {
+                        params = this.filterToParams(filter.filters[i], params);
+                    }
+                } else {
+                    OpenLayers.Console.warn(
+                        "Unsupported logical filter type " + filter.type);
+                }
+                break;
+            default:
+                OpenLayers.Console.warn("Unknown filter type " + filterType);
+        }
+        return params;
+    },
+
+    /**
+     * Method: regex2value
+     * Convert the value from a regular expression string to a LIKE/ILIKE
+     * string known to the web service.
+     *
+     * Parameters:
+     * value - {String} The regex string.
+     *
+     * Returns:
+     * {String} The converted string.
+     */
+    regex2value: function(value) {
+
+        // highly sensitive!! Do not change this without running the
+        // Protocol/HTTP.html unit tests
+
+        // convert % to \%
+        value = value.replace(/%/g, "\\%");
+
+        // convert \\. to \\_ (\\.* occurences converted later)
+        value = value.replace(/\\\\\.(\*)?/g, function($0, $1) {
+            return $1 ? $0 : "\\\\_";
+        });
+
+        // convert \\.* to \\%
+        value = value.replace(/\\\\\.\*/g, "\\\\%");
+
+        // convert . to _ (\. and .* occurences converted later)
+        value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) {
+            return $1 || $2 ? $0 : "_";
+        });
+
+        // convert .* to % (\.* occurnces converted later)
+        value = value.replace(/(\\)?\.\*/g, function($0, $1) {
+            return $1 ? $0 : "%";
+        });
+
+        // convert \. to .
+        value = value.replace(/\\\./g, ".");
+
+        // replace \* with * (watching out for \\*)
+        value = value.replace(/(\\)?\\\*/g, function($0, $1) {
+            return $1 ? $0 : "*";
+        });
+
+        return value;
+    },
+
+    /**
+     * APIMethod: create
+     * Construct a request for writing newly created features.
+     *
+     * Parameters:
+     * features - {Array({<OpenLayers.Feature.Vector>})} or
+     *     {<OpenLayers.Feature.Vector>}
+     * options - {Object} Optional object for configuring the request.
+     *     This object is modified and should not be reused.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *     object, whose "priv" property references the HTTP request, this 
+     *     object is also passed to the callback function when the request
+     *     completes, its "features" property is then populated with the
+     *     the features received from the server.
+     */
+    create: function(features, options) {
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+
+        var resp = new OpenLayers.Protocol.Response({
+            reqFeatures: features,
+            requestType: "create"
+        });
+
+        resp.priv = OpenLayers.Request.POST({
+            url: options.url,
+            callback: this.createCallback(this.handleCreate, resp, options),
+            headers: options.headers,
+            data: this.format.write(features)
+        });
+
+        return resp;
+    },
+
+    /**
+     * Method: handleCreate
+     * Called the the request issued by <create> is complete.  May be overridden
+     *     by subclasses.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+     *     any user callback.
+     * options - {Object} The user options passed to the create call.
+     */
+    handleCreate: function(resp, options) {
+        this.handleResponse(resp, options);
+    },
+
+    /**
+     * APIMethod: update
+     * Construct a request updating modified feature.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     * options - {Object} Optional object for configuring the request.
+     *     This object is modified and should not be reused.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *     object, whose "priv" property references the HTTP request, this 
+     *     object is also passed to the callback function when the request
+     *     completes, its "features" property is then populated with the
+     *     the feature received from the server.
+     */
+    update: function(feature, options) {
+        options = options || {};
+        var url = options.url ||
+                  feature.url ||
+                  this.options.url + "/" + feature.fid;
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+
+        var resp = new OpenLayers.Protocol.Response({
+            reqFeatures: feature,
+            requestType: "update"
+        });
+
+        resp.priv = OpenLayers.Request.PUT({
+            url: url,
+            callback: this.createCallback(this.handleUpdate, resp, options),
+            headers: options.headers,
+            data: this.format.write(feature)
+        });
+
+        return resp;
+    },
+
+    /**
+     * Method: handleUpdate
+     * Called the the request issued by <update> is complete.  May be overridden
+     *     by subclasses.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+     *     any user callback.
+     * options - {Object} The user options passed to the update call.
+     */
+    handleUpdate: function(resp, options) {
+        this.handleResponse(resp, options);
+    },
+
+    /**
+     * APIMethod: delete
+     * Construct a request deleting a removed feature.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     * options - {Object} Optional object for configuring the request.
+     *     This object is modified and should not be reused.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *     object, whose "priv" property references the HTTP request, this 
+     *     object is also passed to the callback function when the request
+     *     completes.
+     */
+    "delete": function(feature, options) {
+        options = options || {};
+        var url = options.url ||
+                  feature.url ||
+                  this.options.url + "/" + feature.fid;
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+
+        var resp = new OpenLayers.Protocol.Response({
+            reqFeatures: feature,
+            requestType: "delete"
+        });
+
+        resp.priv = OpenLayers.Request.DELETE({
+            url: url,
+            callback: this.createCallback(this.handleDelete, resp, options),
+            headers: options.headers
+        });
+
+        return resp;
+    },
+
+    /**
+     * Method: handleDelete
+     * Called the the request issued by <delete> is complete.  May be overridden
+     *     by subclasses.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+     *     any user callback.
+     * options - {Object} The user options passed to the delete call.
+     */
+    handleDelete: function(resp, options) {
+        this.handleResponse(resp, options);
+    },
+
+    /**
+     * Method: handleResponse
+     * Called by CRUD specific handlers.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+     *     any user callback.
+     * options - {Object} The user options passed to the create, read, update,
+     *     or delete call.
+     */
+    handleResponse: function(resp, options) {
+        var request = resp.priv;
+        if(options.callback) {
+            if(request.status >= 200 && request.status < 300) {
+                // success
+                if(resp.requestType != "delete") {
+                    resp.features = this.parseFeatures(request);
+                }
+                resp.code = OpenLayers.Protocol.Response.SUCCESS;
+            } else {
+                // failure
+                resp.code = OpenLayers.Protocol.Response.FAILURE;
+            }
+            options.callback.call(options.scope, resp);
+        }
+    },
+
+    /**
+     * Method: parseFeatures
+     * Read HTTP response body and return features.
+     *
+     * Parameters:
+     * request - {XMLHttpRequest} The request object
+     *
+     * Returns:
+     * {Array({<OpenLayers.Feature.Vector>})} or
+     *     {<OpenLayers.Feature.Vector>} Array of features or a single feature.
+     */
+    parseFeatures: function(request) {
+        var doc = request.responseXML;
+        if (!doc || !doc.documentElement) {
+            doc = request.responseText;
+        }
+        if (!doc || doc.length <= 0) {
+            return null;
+        }
+        return this.format.read(doc);
+    },
+
+    /**
+     * APIMethod: commit
+     * Iterate over each feature and take action based on the feature state.
+     *     Possible actions are create, update and delete.
+     *
+     * Parameters:
+     * features - {Array({<OpenLayers.Feature.Vector>})}
+     * options - {Object} Optional object for setting up intermediate commit
+     *     callbacks.
+     *
+     * Valid options:
+     * create - {Object} Optional object to be passed to the <create> method.
+     * update - {Object} Optional object to be passed to the <update> method.
+     * delete - {Object} Optional object to be passed to the <delete> method.
+     * callback - {Function} Optional function to be called when the commit
+     *     is complete.
+     * scope - {Object} Optional object to be set as the scope of the callback.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Protocol.Response>)} An array of response objects,
+     *     one per request made to the server, each object's "priv" property
+     *     references the corresponding HTTP request.
+     */
+    commit: function(features, options) {
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+        var resp = [], nResponses = 0;
+        
+        // Divide up features before issuing any requests.  This properly
+        // counts requests in the event that any responses come in before
+        // all requests have been issued.
+        var types = {};
+        types[OpenLayers.State.INSERT] = [];
+        types[OpenLayers.State.UPDATE] = [];
+        types[OpenLayers.State.DELETE] = [];
+        var feature, list, requestFeatures = [];
+        for(var i=0, len=features.length; i<len; ++i) {
+            feature = features[i];
+            list = types[feature.state];
+            if(list) {
+                list.push(feature);
+                requestFeatures.push(feature); 
+            }
+        }
+        // tally up number of requests
+        var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) +
+            types[OpenLayers.State.UPDATE].length +
+            types[OpenLayers.State.DELETE].length;
+        
+        // This response will be sent to the final callback after all the others
+        // have been fired.
+        var success = true;
+        var finalResponse = new OpenLayers.Protocol.Response({
+            reqFeatures: requestFeatures        
+        });
+        
+        function insertCallback(response) {
+            var len = response.features ? response.features.length : 0;
+            var fids = new Array(len);
+            for(var i=0; i<len; ++i) {
+                fids[i] = response.features[i].fid;
+            }   
+            finalResponse.insertIds = fids;
+            callback.apply(this, [response]);
+        }
+ 
+        function callback(response) {
+            this.callUserCallback(response, options);
+            success = success && response.success();
+            nResponses++;
+            if (nResponses >= nRequests) {
+                if (options.callback) {
+                    finalResponse.code = success ? 
+                        OpenLayers.Protocol.Response.SUCCESS :
+                        OpenLayers.Protocol.Response.FAILURE;
+                    options.callback.apply(options.scope, [finalResponse]);
+                }    
+            }
+        }
+
+        // start issuing requests
+        var queue = types[OpenLayers.State.INSERT];
+        if(queue.length > 0) {
+            resp.push(this.create(
+                queue, OpenLayers.Util.applyDefaults(
+                    {callback: insertCallback, scope: this}, options.create
+                )
+            ));
+        }
+        queue = types[OpenLayers.State.UPDATE];
+        for(var i=queue.length-1; i>=0; --i) {
+            resp.push(this.update(
+                queue[i], OpenLayers.Util.applyDefaults(
+                    {callback: callback, scope: this}, options.update
+                ))
+            );
+        }
+        queue = types[OpenLayers.State.DELETE];
+        for(var i=queue.length-1; i>=0; --i) {
+            resp.push(this["delete"](
+                queue[i], OpenLayers.Util.applyDefaults(
+                    {callback: callback, scope: this}, options["delete"]
+                ))
+            );
+        }
+        return resp;
+    },
+
+    /**
+     * APIMethod: abort
+     * Abort an ongoing request, the response object passed to
+     * this method must come from this HTTP protocol (as a result
+     * of a create, read, update, delete or commit operation).
+     *
+     * Parameters:
+     * response - {<OpenLayers.Protocol.Response>}
+     */
+    abort: function(response) {
+        if (response) {
+            response.priv.abort();
+        }
+    },
+
+    /**
+     * Method: callUserCallback
+     * This method is used from within the commit method each time an
+     *     an HTTP response is received from the server, it is responsible
+     *     for calling the user-supplied callbacks.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>}
+     * options - {Object} The map of options passed to the commit call.
+     */
+    callUserCallback: function(resp, options) {
+        var opt = options[resp.requestType];
+        if(opt && opt.callback) {
+            opt.callback.call(opt.scope, resp);
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Protocol.HTTP" 
+});
+
+/**
+ * Property: OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR
+ * {Object} A private class-level property mapping the
+ *     OpenLayers.Filter.Comparison types to the operation
+ *     strings of the protocol.
+ */
+(function() {
+    var o = OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR = {};
+    o[OpenLayers.Filter.Comparison.EQUAL_TO]                 = "eq";
+    o[OpenLayers.Filter.Comparison.NOT_EQUAL_TO]             = "ne";
+    o[OpenLayers.Filter.Comparison.LESS_THAN]                = "lt";
+    o[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO]    = "lte";
+    o[OpenLayers.Filter.Comparison.GREATER_THAN]             = "gt";
+    o[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte";
+    o[OpenLayers.Filter.Comparison.LIKE]                     = "ilike";
+})();
+
+/* ======================================================================
     OpenLayers/Geometry/Curve.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -33135,37 +36302,37 @@
 
 /**
  * Class: OpenLayers.Geometry.Curve
- * A Curve is a MultiPoint, whose points are assumed to be connected. To
- * this end, we provide a "getLength()" function, which iterates through
- * the points, summing the distances between them.
- *
- * Inherits:
+ * A Curve is a MultiPoint, whose points are assumed to be connected. To 
+ * this end, we provide a "getLength()" function, which iterates through 
+ * the points, summing the distances between them. 
+ * 
+ * Inherits: 
  *  - <OpenLayers.Geometry.MultiPoint>
  */
 OpenLayers.Geometry.Curve = OpenLayers.Class(OpenLayers.Geometry.MultiPoint, {
 
     /**
      * Property: componentTypes
-     * {Array(String)} An array of class names representing the types of
-     *                 components that the collection can include.  A null
+     * {Array(String)} An array of class names representing the types of 
+     *                 components that the collection can include.  A null 
      *                 value means the component types are not restricted.
      */
     componentTypes: ["OpenLayers.Geometry.Point"],
 
     /**
      * Constructor: OpenLayers.Geometry.Curve
-     *
+     * 
      * Parameters:
      * point - {Array(<OpenLayers.Geometry.Point>)}
      */
     initialize: function(points) {
-        OpenLayers.Geometry.MultiPoint.prototype.initialize.apply(this,
+        OpenLayers.Geometry.MultiPoint.prototype.initialize.apply(this, 
                                                                   arguments);
     },
-
+    
     /**
      * APIMethod: getLength
-     *
+     * 
      * Returns:
      * {Float} The length of the curve
      */
@@ -33187,7 +36354,7 @@
      * projection - {<OpenLayers.Projection>} The spatial reference system
      *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
      *     assumed.
-     *
+     * 
      * Returns:
      * {Float} The appoximate geodesic length of the geometry in meters.
      */
@@ -33221,8 +36388,9 @@
     OpenLayers/Geometry/LineString.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -33231,9 +36399,9 @@
 
 /**
  * Class: OpenLayers.Geometry.LineString
- * A LineString is a Curve which, once two points have been added to it, can
+ * A LineString is a Curve which, once two points have been added to it, can 
  * never be less than two points long.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Geometry.Curve>
  */
@@ -33249,24 +36417,24 @@
      *
      */
     initialize: function(points) {
-        OpenLayers.Geometry.Curve.prototype.initialize.apply(this, arguments);
+        OpenLayers.Geometry.Curve.prototype.initialize.apply(this, arguments);        
     },
 
     /**
      * APIMethod: removeComponent
-     * Only allows removal of a point if there are three or more points in
+     * Only allows removal of a point if there are three or more points in 
      * the linestring. (otherwise the result would be just a single point)
      *
-     * Parameters:
+     * Parameters: 
      * point - {<OpenLayers.Geometry.Point>} The point to be removed
      */
     removeComponent: function(point) {
         if ( this.components && (this.components.length > 2)) {
-            OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,
+            OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, 
                                                                   arguments);
         }
     },
-
+    
     /**
      * APIMethod: intersects
      * Test for instersection between two geometries.  This is a cheapo
@@ -33338,7 +36506,7 @@
         }
         return intersect;
     },
-
+    
     /**
      * Method: getSortedSegments
      *
@@ -33350,7 +36518,7 @@
      */
     getSortedSegments: function() {
         var numSeg = this.components.length - 1;
-        var segments = new Array(numSeg);
+        var segments = new Array(numSeg), point1, point2;
         for(var i=0; i<numSeg; ++i) {
             point1 = this.components[i];
             point2 = this.components[i + 1];
@@ -33376,7 +36544,7 @@
         }
         return segments.sort(byX1);
     },
-
+    
     /**
      * Method: splitWithSegment
      * Split this geometry with the given segment.
@@ -33473,7 +36641,7 @@
     /**
      * Method: split
      * Use this geometry (the source) to attempt to split a target geometry.
-     *
+     * 
      * Parameters:
      * target - {<OpenLayers.Geometry>} The target geometry.
      * options - {Object} Properties of this object will be used to determine
@@ -33488,7 +36656,7 @@
      * tolerance - {Number} If a non-null value is provided, intersections
      *     within the tolerance distance of an existing vertex on the source
      *     will be assumed to occur at the vertex.
-     *
+     * 
      * Returns:
      * {Array} A list of geometries (of this same type as the target) that
      *     result from splitting the target with the source geometry.  The
@@ -33592,7 +36760,7 @@
      * tolerance - {Number} If a non-null value is provided, intersections
      *     within the tolerance distance of an existing vertex on the source
      *     will be assumed to occur at the vertex.
-     *
+     * 
      * Returns:
      * {Array} A list of geometries (of this same type as the target) that
      *     result from splitting the target with the source geometry.  The
@@ -33698,7 +36866,7 @@
             } else {
                 best = best.distance;
             }
-        } else if(geometry instanceof OpenLayers.Geometry.LineString) {
+        } else if(geometry instanceof OpenLayers.Geometry.LineString) { 
             var segs0 = this.getSortedSegments();
             var segs1 = geometry.getSortedSegments();
             var seg0, seg1, intersection, x0, y0;
@@ -33776,8 +36944,9 @@
     OpenLayers/Geometry/LinearRing.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -33786,14 +36955,14 @@
 
 /**
  * Class: OpenLayers.Geometry.LinearRing
- *
- * A Linear Ring is a special LineString which is closed. It closes itself
+ * 
+ * A Linear Ring is a special LineString which is closed. It closes itself 
  * automatically on every addPoint/removePoint by adding a copy of the first
- * point as the last point.
- *
+ * point as the last point. 
+ * 
  * Also, as it is the first in the line family to close itself, a getArea()
  * function is defined to calculate the enclosed area of the linearRing
- *
+ * 
  * Inherits:
  *  - <OpenLayers.Geometry.LineString>
  */
@@ -33802,8 +36971,8 @@
 
     /**
      * Property: componentTypes
-     * {Array(String)} An array of class names representing the types of
-     *                 components that the collection can include.  A null
+     * {Array(String)} An array of class names representing the types of 
+     *                 components that the collection can include.  A null 
      *                 value means the component types are not restricted.
      */
     componentTypes: ["OpenLayers.Geometry.Point"],
@@ -33815,12 +36984,12 @@
      *     point does not equal the first point), the constructor will close
      *     the ring.  If the ring is already closed (the last point does equal
      *     the first point), it will be left closed.
-     *
+     * 
      * Parameters:
      * points - {Array(<OpenLayers.Geometry.Point>)} points
      */
     initialize: function(points) {
-        OpenLayers.Geometry.LineString.prototype.initialize.apply(this,
+        OpenLayers.Geometry.LineString.prototype.initialize.apply(this, 
                                                                   arguments);
     },
 
@@ -33828,16 +36997,16 @@
      * APIMethod: addComponent
      * Adds a point to geometry components.  If the point is to be added to
      *     the end of the components array and it is the same as the last point
-     *     already in that array, the duplicate point is not added.  This has
-     *     the effect of closing the ring if it is not already closed, and
-     *     doing the right thing if it is already closed.  This behavior can
-     *     be overridden by calling the method with a non-null index as the
+     *     already in that array, the duplicate point is not added.  This has 
+     *     the effect of closing the ring if it is not already closed, and 
+     *     doing the right thing if it is already closed.  This behavior can 
+     *     be overridden by calling the method with a non-null index as the 
      *     second argument.
      *
      * Parameter:
      * point - {<OpenLayers.Geometry.Point>}
      * index - {Integer} Index into the array to insert the component
-     *
+     * 
      * Returns:
      * {Boolean} Was the Point successfully added?
      */
@@ -33850,18 +37019,18 @@
         // given an index, add the point
         // without an index only add non-duplicate points
         if(index != null || !point.equals(lastPoint)) {
-            added = OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,
+            added = OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
                                                                     arguments);
         }
 
         //append copy of first point
         var firstPoint = this.components[0];
-        OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,
+        OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
                                                                 [firstPoint]);
-
+        
         return added;
     },
-
+    
     /**
      * APIMethod: removeComponent
      * Removes a point from geometry components.
@@ -33874,17 +37043,17 @@
 
             //remove last point
             this.components.pop();
-
+            
             //remove our point
-            OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,
+            OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, 
                                                                     arguments);
             //append copy of first point
             var firstPoint = this.components[0];
-            OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,
+            OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
                                                                 [firstPoint]);
         }
     },
-
+    
     /**
      * APIMethod: move
      * Moves a geometry by the given displacement along positive x and y axes.
@@ -33892,7 +37061,7 @@
      *     bounds.
      *
      * Parameters:
-     * x - {Float} Distance to move geometry in positive x direction.
+     * x - {Float} Distance to move geometry in positive x direction. 
      * y - {Float} Distance to move geometry in positive y direction.
      */
     move: function(x, y) {
@@ -33928,9 +37097,9 @@
      *                 will have four times the area).
      * origin - {<OpenLayers.Geometry.Point>} Point of origin for resizing
      * ratio - {Float} Optional x:y ratio for resizing.  Default ratio is 1.
-     *
+     * 
      * Returns:
-     * {OpenLayers.Geometry} - The current geometry.
+     * {OpenLayers.Geometry} - The current geometry. 
      */
     resize: function(scale, origin, ratio) {
         for(var i=0, len=this.components.length; i<len - 1; ++i) {
@@ -33938,7 +37107,7 @@
         }
         return this;
     },
-
+    
     /**
      * APIMethod: transform
      * Reproject the components geometry from source to dest.
@@ -33946,9 +37115,9 @@
      * Parameters:
      * source - {<OpenLayers.Projection>}
      * dest - {<OpenLayers.Projection>}
-     *
+     * 
      * Returns:
-     * {<OpenLayers.Geometry>}
+     * {<OpenLayers.Geometry>} 
      */
     transform: function(source, dest) {
         if (source && dest) {
@@ -33960,7 +37129,7 @@
         }
         return this;
     },
-
+    
     /**
      * APIMethod: getCentroid
      *
@@ -33968,7 +37137,7 @@
      * {<OpenLayers.Geometry.Point>} The centroid of the collection
      */
     getCentroid: function() {
-        if ( this.components && (this.components.length > 2)) {
+        if (this.components && (this.components.length > 2)) {
             var sumX = 0.0;
             var sumY = 0.0;
             for (var i = 0; i < this.components.length - 1; i++) {
@@ -33980,15 +37149,17 @@
             var area = -1 * this.getArea();
             var x = sumX / (6 * area);
             var y = sumY / (6 * area);
+            return new OpenLayers.Geometry.Point(x, y);
+        } else {
+            return null;
         }
-        return new OpenLayers.Geometry.Point(x, y);
     },
 
     /**
      * APIMethod: getArea
      * Note - The area is positive if the ring is oriented CW, otherwise
      *         it will be negative.
-     *
+     * 
      * Returns:
      * {Float} The signed area for a ring.
      */
@@ -34005,7 +37176,7 @@
         }
         return area;
     },
-
+    
     /**
      * APIMethod: getGeodesicArea
      * Calculate the approximate area of the polygon were it projected onto
@@ -34016,7 +37187,7 @@
      * projection - {<OpenLayers.Projection>} The spatial reference system
      *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
      *     assumed.
-     *
+     * 
      * Reference:
      * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
      *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
@@ -34049,7 +37220,7 @@
         }
         return area;
     },
-
+    
     /**
      * Method: containsPoint
      * Test if a point is inside a linear ring.  For the case where a point
@@ -34081,7 +37252,7 @@
             end = this.components[i + 1];
             x2 = approx(end.x, digs);
             y2 = approx(end.y, digs);
-
+            
             /**
              * The following conditions enforce five edge-crossing rules:
              *    1. points coincident with edges are considered contained;
@@ -34194,8 +37365,9 @@
     OpenLayers/Geometry/MultiLineString.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -34207,10 +37379,10 @@
  * Class: OpenLayers.Geometry.MultiLineString
  * A MultiLineString is a geometry with multiple <OpenLayers.Geometry.LineString>
  * components.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Geometry.Collection>
- *  - <OpenLayers.Geometry>
+ *  - <OpenLayers.Geometry> 
  */
 OpenLayers.Geometry.MultiLineString = OpenLayers.Class(
   OpenLayers.Geometry.Collection, {
@@ -34227,19 +37399,19 @@
      * Constructor: OpenLayers.Geometry.MultiLineString
      * Constructor for a MultiLineString Geometry.
      *
-     * Parameters:
-     * components - {Array(<OpenLayers.Geometry.LineString>)}
+     * Parameters: 
+     * components - {Array(<OpenLayers.Geometry.LineString>)} 
      *
      */
     initialize: function(components) {
-        OpenLayers.Geometry.Collection.prototype.initialize.apply(this,
-                                                                  arguments);
+        OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
+                                                                  arguments);        
     },
-
+    
     /**
      * Method: split
      * Use this geometry (the source) to attempt to split a target geometry.
-     *
+     * 
      * Parameters:
      * target - {<OpenLayers.Geometry>} The target geometry.
      * options - {Object} Properties of this object will be used to determine
@@ -34254,7 +37426,7 @@
      * tolerance - {Number} If a non-null value is provided, intersections
      *     within the tolerance distance of an existing vertex on the source
      *     will be assumed to occur at the vertex.
-     *
+     * 
      * Returns:
      * {Array} A list of geometries (of this same type as the target) that
      *     result from splitting the target with the source geometry.  The
@@ -34274,7 +37446,7 @@
         for(var i=0, len=this.components.length; i<len; ++i) {
             sourceLine = this.components[i];
             sourceSplit = false;
-            for(var j=0; j < targetParts.length; ++j) {
+            for(var j=0; j < targetParts.length; ++j) { 
                 splits = sourceLine.split(targetParts[j], options);
                 if(splits) {
                     if(mutual) {
@@ -34339,7 +37511,7 @@
         }
         return results;
     },
-
+    
     /**
      * Method: splitWith
      * Split this geometry (the target) with the given geometry (the source).
@@ -34359,7 +37531,7 @@
      * tolerance - {Number} If a non-null value is provided, intersections
      *     within the tolerance distance of an existing vertex on the source
      *     will be assumed to occur at the vertex.
-     *
+     * 
      * Returns:
      * {Array} A list of geometries (of this same type as the target) that
      *     result from splitting the target with the source geometry.  The
@@ -34409,7 +37581,7 @@
                                 );
                             }
                         }
-                        targetSplit = true;
+                        targetSplit = true;                    
                     }
                 }
                 if(!targetSplit) {
@@ -34427,7 +37599,7 @@
                             ])
                         ];
                     }
-
+                    
                 }
             }
         } else {
@@ -34459,8 +37631,9 @@
     OpenLayers/Handler/Path.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -34479,13 +37652,13 @@
  *  - <OpenLayers.Handler.Point>
  */
 OpenLayers.Handler.Path = OpenLayers.Class(OpenLayers.Handler.Point, {
-
+    
     /**
      * Property: line
      * {<OpenLayers.Feature.Vector>}
      */
     line: null,
-
+    
     /**
      * Property: freehand
      * {Boolean} In freehand mode, the handler starts the path on mouse down,
@@ -34494,7 +37667,7 @@
      * click and double-click finishes the path.
      */
     freehand: false,
-
+    
     /**
      * Property: freehandToggle
      * {String} If set, freehandToggle is checked on mouse events and will set
@@ -34529,7 +37702,7 @@
     initialize: function(control, callbacks, options) {
         OpenLayers.Handler.Point.prototype.initialize.apply(this, arguments);
     },
-
+        
     /**
      * Method: createFeature
      * Add temporary geometries
@@ -34550,7 +37723,7 @@
         this.point.geometry.clearBounds();
         this.layer.addFeatures([this.line, this.point], {silent: true});
     },
-
+        
     /**
      * Method: destroyFeature
      * Destroy temporary geometries
@@ -34569,7 +37742,7 @@
             this.layer.removeFeatures([this.point]);
         }
     },
-
+    
     /**
      * Method: addPoint
      * Add point to geometry.  Send the point index to override
@@ -34591,7 +37764,7 @@
         this.callback("modify", [this.point.geometry, this.getSketch()]);
         this.drawFeature();
     },
-
+    
     /**
      * Method: freehandMode
      * Determine whether to behave in freehand mode or not.
@@ -34661,11 +37834,11 @@
      * Method: mousedown
      * Handle mouse down.  Add a new point to the geometry and
      * render it. Return determines whether to propagate the event on the map.
-     *
+     * 
      * Parameters:
      * evt - {Event} The browser event
      *
-     * Returns:
+     * Returns: 
      * {Boolean} Allow event propagation
      */
     mousedown: function(evt) {
@@ -34691,15 +37864,15 @@
      * Method: mousemove
      * Handle mouse move.  Adjust the geometry and redraw.
      * Return determines whether to propagate the event on the map.
-     *
+     * 
      * Parameters:
      * evt - {Event} The browser event
      *
-     * Returns:
+     * Returns: 
      * {Boolean} Allow event propagation
      */
     mousemove: function (evt) {
-        if(this.drawing) {
+        if(this.drawing) { 
             if(this.mouseDown && this.freehandMode(evt)) {
                 this.addPoint(evt.xy);
             } else {
@@ -34708,16 +37881,16 @@
         }
         return true;
     },
-
+    
     /**
      * Method: mouseup
      * Handle mouse up.  Send the latest point in the geometry to
      * the control. Return determines whether to propagate the event on the map.
-     *
+     * 
      * Parameters:
      * evt - {Event} The browser event
      *
-     * Returns:
+     * Returns: 
      * {Boolean} Allow event propagation
      */
     mouseup: function (evt) {
@@ -34736,16 +37909,16 @@
         }
         return true;
     },
-
+  
     /**
-     * Method: dblclick
+     * Method: dblclick 
      * Handle double-clicks.  Finish the geometry and send it back
      * to the control.
-     *
+     * 
      * Parameters:
      * evt - {Event} The browser event
      *
-     * Returns:
+     * Returns: 
      * {Boolean} Allow event propagation
      */
     dblclick: function(evt) {
@@ -34764,8 +37937,9 @@
     OpenLayers/Geometry/Polygon.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -34774,12 +37948,12 @@
  */
 
 /**
- * Class: OpenLayers.Geometry.Polygon
- * Polygon is a collection of Geometry.LinearRings.
- *
+ * Class: OpenLayers.Geometry.Polygon 
+ * Polygon is a collection of Geometry.LinearRings. 
+ * 
  * Inherits from:
- *  - <OpenLayers.Geometry.Collection>
- *  - <OpenLayers.Geometry>
+ *  - <OpenLayers.Geometry.Collection> 
+ *  - <OpenLayers.Geometry> 
  */
 OpenLayers.Geometry.Polygon = OpenLayers.Class(
   OpenLayers.Geometry.Collection, {
@@ -34794,24 +37968,24 @@
 
     /**
      * Constructor: OpenLayers.Geometry.Polygon
-     * Constructor for a Polygon geometry.
-     * The first ring (this.component[0])is the outer bounds of the polygon and
+     * Constructor for a Polygon geometry. 
+     * The first ring (this.component[0])is the outer bounds of the polygon and 
      * all subsequent rings (this.component[1-n]) are internal holes.
      *
      *
      * Parameters:
-     * components - {Array(<OpenLayers.Geometry.LinearRing>)}
+     * components - {Array(<OpenLayers.Geometry.LinearRing>)} 
      */
     initialize: function(components) {
-        OpenLayers.Geometry.Collection.prototype.initialize.apply(this,
+        OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
                                                                   arguments);
     },
-
-    /**
+    
+    /** 
      * APIMethod: getArea
-     * Calculated by subtracting the areas of the internal holes from the
+     * Calculated by subtracting the areas of the internal holes from the 
      *   area of the outer hole.
-     *
+     * 
      * Returns:
      * {float} The area of the geometry
      */
@@ -34826,7 +38000,7 @@
         return area;
     },
 
-    /**
+    /** 
      * APIMethod: getGeodesicArea
      * Calculate the approximate area of the polygon were it projected onto
      *     the earth.
@@ -34835,7 +38009,7 @@
      * projection - {<OpenLayers.Projection>} The spatial reference system
      *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
      *     assumed.
-     *
+     * 
      * Reference:
      * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
      *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
@@ -34886,7 +38060,7 @@
                             } else {
                                 // in hole
                                 contained = false;
-                            }
+                            }                            
                             break;
                         }
                     }
@@ -34997,7 +38171,7 @@
 
 /**
  * APIMethod: createRegularPolygon
- * Create a regular polygon around a radius. Useful for creating circles
+ * Create a regular polygon around a radius. Useful for creating circles 
  * and the like.
  *
  * Parameters:
@@ -35006,7 +38180,7 @@
  * sides - {Integer} Number of sides. 20 approximates a circle.
  * rotation - {Float} original angle of rotation, in degrees.
  */
-OpenLayers.Geometry.Polygon.createRegularPolygon = function(origin, radius, sides, rotation) {
+OpenLayers.Geometry.Polygon.createRegularPolygon = function(origin, radius, sides, rotation) {  
     var angle = Math.PI * ((1/sides) - (1/2));
     if(rotation) {
         angle += (rotation / 180) * Math.PI;
@@ -35026,8 +38200,9 @@
     OpenLayers/Geometry/MultiPolygon.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -35040,7 +38215,7 @@
  * MultiPolygon is a geometry with multiple <OpenLayers.Geometry.Polygon>
  * components.  Create a new instance with the <OpenLayers.Geometry.MultiPolygon>
  * constructor.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Geometry.Collection>
  */
@@ -35065,7 +38240,7 @@
      *
      */
     initialize: function(components) {
-        OpenLayers.Geometry.Collection.prototype.initialize.apply(this,
+        OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
                                                                   arguments);
     },
 
@@ -35075,8 +38250,9 @@
     OpenLayers/Handler/Polygon.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 
@@ -35095,7 +38271,7 @@
  *  - <OpenLayers.Handler>
  */
 OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, {
-
+    
     /**
      * Parameter: polygon
      * {<OpenLayers.Feature.Vector>}
@@ -35127,7 +38303,7 @@
     initialize: function(control, callbacks, options) {
         OpenLayers.Handler.Path.prototype.initialize.apply(this, arguments);
     },
-
+    
     /**
      * Method: createFeature
      * Add temporary geometries
@@ -35169,7 +38345,7 @@
         this.layer.drawFeature(this.polygon, this.style);
         this.layer.drawFeature(this.point, this.style);
     },
-
+    
     /**
      * Method: getSketch
      * Return the sketch feature.
@@ -35201,9 +38377,9 @@
      * Method: dblclick
      * Handle double-clicks.  Finish the geometry and send it back
      * to the control.
-     *
+     * 
      * Parameters:
-     * evt - {Event}
+     * evt - {Event} 
      */
     dblclick: function(evt) {
         if(!this.freehandMode(evt)) {
@@ -35222,8 +38398,9 @@
     OpenLayers/Format/GML.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -35242,50 +38419,50 @@
  * Class: OpenLayers.Format.GML
  * Read/Wite GML. Create a new instance with the <OpenLayers.Format.GML>
  *     constructor.  Supports the GML simple features profile.
- *
+ * 
  * Inherits from:
  *  - <OpenLayers.Format>
  */
 OpenLayers.Format.GML = OpenLayers.Class(OpenLayers.Format.XML, {
-
+    
     /*
      * APIProperty: featureNS
      * {String} Namespace used for feature attributes.  Default is
      *     "http://mapserver.gis.umn.edu/mapserver".
      */
     featureNS: "http://mapserver.gis.umn.edu/mapserver",
-
+    
     /**
      * APIProperty: featurePrefix
      * {String} Namespace alias (or prefix) for feature nodes.  Default is
      *     "feature".
      */
     featurePrefix: "feature",
-
+    
     /*
      * APIProperty: featureName
      * {String} Element name for features. Default is "featureMember".
      */
-    featureName: "featureMember",
-
+    featureName: "featureMember", 
+    
     /*
      * APIProperty: layerName
      * {String} Name of data layer. Default is "features".
      */
     layerName: "features",
-
+    
     /**
      * APIProperty: geometryName
      * {String} Name of geometry element.  Defaults to "geometry".
      */
     geometryName: "geometry",
-
-    /**
+    
+    /** 
      * APIProperty: collectionName
      * {String} Name of featureCollection element.
      */
     collectionName: "FeatureCollection",
-
+    
     /**
      * APIProperty: gmlns
      * {String} GML Namespace.
@@ -35297,14 +38474,14 @@
      * {Boolean} Extract attributes from GML.
      */
     extractAttributes: true,
-
+    
     /**
      * APIProperty: xy
      * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
      * Changing is not recommended, a new Format should be instantiated.
-     */
+     */ 
     xy: true,
-
+    
     /**
      * Constructor: OpenLayers.Format.GML
      * Create a new parser for GML.
@@ -35326,8 +38503,8 @@
 
     /**
      * APIMethod: read
-     * Read data from a string, and return a list of features.
-     *
+     * Read data from a string, and return a list of features. 
+     * 
      * Parameters:
      * data - {String} or {DOMElement} data to read/parse.
      *
@@ -35335,7 +38512,7 @@
      * {Array(<OpenLayers.Feature.Vector>)} An array of features.
      */
     read: function(data) {
-        if(typeof data == "string") {
+        if(typeof data == "string") { 
             data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
         }
         var featureNodes = this.getElementsByTagNameNS(data.documentElement,
@@ -35350,34 +38527,36 @@
         }
         return features;
     },
-
+    
     /**
      * Method: parseFeature
      * This function is the core of the GML parsing code in OpenLayers.
      *    It creates the geometries that are then attached to the returned
      *    feature, and calls parseAttributes() to get attribute data out.
-     *
+     *    
      * Parameters:
-     * node - {DOMElement} A GML feature node.
+     * node - {DOMElement} A GML feature node. 
      */
     parseFeature: function(node) {
         // only accept one geometry per feature - look for highest "order"
         var order = ["MultiPolygon", "Polygon",
                      "MultiLineString", "LineString",
-                     "MultiPoint", "Point", "Envelope", "Box"];
+                     "MultiPoint", "Point", "Envelope"];
+        // FIXME: In case we parse a feature with no geometry, but boundedBy an Envelope,
+        // this code creates a geometry derived from the Envelope. This is not correct.
         var type, nodeList, geometry, parser;
         for(var i=0; i<order.length; ++i) {
             type = order[i];
             nodeList = this.getElementsByTagNameNS(node, this.gmlns, type);
             if(nodeList.length > 0) {
                 // only deal with first geometry of this type
-                var parser = this.parseGeometry[type.toLowerCase()];
+                parser = this.parseGeometry[type.toLowerCase()];
                 if(parser) {
                     geometry = parser.apply(this, [nodeList[0]]);
                     if (this.internalProjection && this.externalProjection) {
-                        geometry.transform(this.externalProjection,
-                                           this.internalProjection);
-                    }
+                        geometry.transform(this.externalProjection, 
+                                           this.internalProjection); 
+                    }                       
                 } else {
                     OpenLayers.Console.error(OpenLayers.i18n(
                                 "unsupportedGeometryType", {'geomType':type}));
@@ -35387,19 +38566,35 @@
             }
         }
 
+        var bounds;
+        var boxNodes = this.getElementsByTagNameNS(node, this.gmlns, "Box");
+        for(i=0; i<boxNodes.length; ++i) {
+            var boxNode = boxNodes[i];
+            var box = this.parseGeometry["box"].apply(this, [boxNode]);
+            var parentNode = boxNode.parentNode;
+            var parentName = parentNode.localName ||
+                             parentNode.nodeName.split(":").pop();
+            if(parentName === "boundedBy") {
+                bounds = box;
+            } else {
+                geometry = box.toGeometry();
+            }
+        }
+        
         // construct feature (optionally with attributes)
         var attributes;
         if(this.extractAttributes) {
             attributes = this.parseAttributes(node);
         }
         var feature = new OpenLayers.Feature.Vector(geometry, attributes);
-
+        feature.bounds = bounds;
+        
         feature.gml = {
             featureType: node.firstChild.nodeName.split(":")[1],
             featureNS: node.firstChild.namespaceURI,
             featureNSPrefix: node.firstChild.prefix
         };
-
+                
         // assign fid - this can come from a "fid" or "id" attribute
         var childNode = node.firstChild;
         var fid;
@@ -35416,14 +38611,14 @@
         feature.fid = fid;
         return feature;
     },
-
+    
     /**
      * Property: parseGeometry
      * Properties of this object are the functions that parse geometries based
      *     on their type.
      */
     parseGeometry: {
-
+        
         /**
          * Method: parseGeometry.point
          * Given a GML node representing a point geometry, create an OpenLayers
@@ -35480,12 +38675,12 @@
                     }
                 }
             }
-
+                
             // preserve third dimension
             if(coords.length == 2) {
                 coords[2] = null;
             }
-
+            
             if (this.xy) {
                 return new OpenLayers.Geometry.Point(coords[0], coords[1],
                                                  coords[2]);
@@ -35495,7 +38690,7 @@
                                                  coords[2]);
             }
         },
-
+        
         /**
          * Method: parseGeometry.multipoint
          * Given a GML node representing a multipoint geometry, create an
@@ -35522,7 +38717,7 @@
             }
             return new OpenLayers.Geometry.MultiPoint(components);
         },
-
+        
         /**
          * Method: parseGeometry.linestring
          * Given a GML node representing a linestring geometry, create an
@@ -35604,7 +38799,7 @@
             }
             return line;
         },
-
+        
         /**
          * Method: parseGeometry.multilinestring
          * Given a GML node representing a multilinestring geometry, create an
@@ -35632,7 +38827,7 @@
             }
             return new OpenLayers.Geometry.MultiLineString(components);
         },
-
+        
         /**
          * Method: parseGeometry.polygon
          * Given a GML node representing a polygon geometry, create an
@@ -35661,7 +38856,7 @@
             }
             return new OpenLayers.Geometry.Polygon(components);
         },
-
+        
         /**
          * Method: parseGeometry.multipolygon
          * Given a GML node representing a multipolygon geometry, create an
@@ -35689,22 +38884,22 @@
             }
             return new OpenLayers.Geometry.MultiPolygon(components);
         },
-
+        
         envelope: function(node) {
             var components = [];
             var coordString;
             var envelope;
-
+            
             var lpoint = this.getElementsByTagNameNS(node, this.gmlns, "lowerCorner");
             if (lpoint.length > 0) {
                 var coords = [];
-
+                
                 if(lpoint.length > 0) {
                     coordString = lpoint[0].firstChild.nodeValue;
                     coordString = coordString.replace(this.regExes.trimSpace, "");
                     coords = coordString.split(this.regExes.splitSpace);
                 }
-
+                
                 if(coords.length == 2) {
                     coords[2] = null;
                 }
@@ -35714,17 +38909,17 @@
                     var lowerPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]);
                 }
             }
-
+            
             var upoint = this.getElementsByTagNameNS(node, this.gmlns, "upperCorner");
             if (upoint.length > 0) {
                 var coords = [];
-
+                
                 if(upoint.length > 0) {
                     coordString = upoint[0].firstChild.nodeValue;
                     coordString = coordString.replace(this.regExes.trimSpace, "");
                     coords = coordString.split(this.regExes.splitSpace);
                 }
-
+                
                 if(coords.length == 2) {
                     coords[2] = null;
                 }
@@ -35734,21 +38929,54 @@
                     var upperPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]);
                 }
             }
-
+            
             if (lowerPoint && upperPoint) {
                 components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y));
                 components.push(new OpenLayers.Geometry.Point(upperPoint.x, lowerPoint.y));
                 components.push(new OpenLayers.Geometry.Point(upperPoint.x, upperPoint.y));
                 components.push(new OpenLayers.Geometry.Point(lowerPoint.x, upperPoint.y));
                 components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y));
-
+                
                 var ring = new OpenLayers.Geometry.LinearRing(components);
                 envelope = new OpenLayers.Geometry.Polygon([ring]);
             }
-            return envelope;
+            return envelope; 
+        },
+
+        /**
+         * Method: parseGeometry.box
+         * Given a GML node representing a box geometry, create an
+         *     OpenLayers.Bounds.
+         *
+         * Parameters:
+         * node - {DOMElement} A GML node.
+         *
+         * Returns:
+         * {<OpenLayers.Bounds>} A bounds representing the box.
+         */
+        box: function(node) {
+            var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
+                                                   "coordinates");
+            var coordString;
+            var coords, beginPoint = null, endPoint = null;
+            if (nodeList.length > 0) {
+                coordString = nodeList[0].firstChild.nodeValue;
+                coords = coordString.split(" ");
+                if (coords.length == 2) {
+                    beginPoint = coords[0].split(",");
+                    endPoint = coords[1].split(",");
+                }
+            }
+            if (beginPoint !== null && endPoint !== null) {
+                return new OpenLayers.Bounds(parseFloat(beginPoint[0]),
+                    parseFloat(beginPoint[1]),
+                    parseFloat(endPoint[0]),
+                    parseFloat(endPoint[1]) );
+            }
         }
+        
     },
-
+    
     /**
      * Method: parseAttributes
      *
@@ -35797,11 +39025,11 @@
         }
         return attributes;
     },
-
+    
     /**
      * APIMethod: write
-     * Generate a GML document string given a list of features.
-     *
+     * Generate a GML document string given a list of features. 
+     * 
      * Parameters:
      * features - {Array(<OpenLayers.Feature.Vector>)} List of features to
      *     serialize into a string.
@@ -35821,7 +39049,7 @@
         return OpenLayers.Format.XML.prototype.write.apply(this, [gml]);
     },
 
-    /**
+    /** 
      * Method: createFeatureXML
      * Accept an OpenLayers.Feature.Vector, and build a GML node for it.
      *
@@ -35847,27 +39075,27 @@
         featureContainer.setAttribute("fid", fid);
         featureContainer.appendChild(geomContainer);
         for(var attr in feature.attributes) {
-            var attrText = this.createTextNode(feature.attributes[attr]);
+            var attrText = this.createTextNode(feature.attributes[attr]); 
             var nodename = attr.substring(attr.lastIndexOf(":") + 1);
             var attrContainer = this.createElementNS(this.featureNS,
                                                      this.featurePrefix + ":" +
                                                      nodename);
             attrContainer.appendChild(attrText);
             featureContainer.appendChild(attrContainer);
-        }
+        }    
         featureNode.appendChild(featureContainer);
         return featureNode;
     },
-
+    
     /**
      * APIMethod: buildGeometryNode
      */
     buildGeometryNode: function(geometry) {
         if (this.externalProjection && this.internalProjection) {
             geometry = geometry.clone();
-            geometry.transform(this.internalProjection,
+            geometry.transform(this.internalProjection, 
                                this.externalProjection);
-        }
+        }    
         var className = geometry.CLASS_NAME;
         var type = className.substring(className.lastIndexOf(".") + 1);
         var builder = this.buildGeometry[type.toLowerCase()];
@@ -35900,7 +39128,7 @@
             gml.appendChild(this.buildCoordinatesNode(geometry));
             return gml;
         },
-
+        
         /**
          * Method: buildGeometry.multipoint
          * Given an OpenLayers multipoint geometry, create a GML multipoint.
@@ -35915,7 +39143,7 @@
             var gml = this.createElementNS(this.gmlns, "gml:MultiPoint");
             var points = geometry.components;
             var pointMember, pointGeom;
-            for(var i=0; i<points.length; i++) {
+            for(var i=0; i<points.length; i++) { 
                 pointMember = this.createElementNS(this.gmlns,
                                                    "gml:pointMember");
                 pointGeom = this.buildGeometry.point.apply(this,
@@ -35923,9 +39151,9 @@
                 pointMember.appendChild(pointGeom);
                 gml.appendChild(pointMember);
             }
-            return gml;
+            return gml;            
         },
-
+        
         /**
          * Method: buildGeometry.linestring
          * Given an OpenLayers linestring geometry, create a GML linestring.
@@ -35941,7 +39169,7 @@
             gml.appendChild(this.buildCoordinatesNode(geometry));
             return gml;
         },
-
+        
         /**
          * Method: buildGeometry.multilinestring
          * Given an OpenLayers multilinestring geometry, create a GML
@@ -35968,7 +39196,7 @@
             }
             return gml;
         },
-
+        
         /**
          * Method: buildGeometry.linearring
          * Given an OpenLayers linearring geometry, create a GML linearring.
@@ -35984,7 +39212,7 @@
             gml.appendChild(this.buildCoordinatesNode(geometry));
             return gml;
         },
-
+        
         /**
          * Method: buildGeometry.polygon
          * Given an OpenLayers polygon geometry, create a GML polygon.
@@ -36010,7 +39238,7 @@
             }
             return gml;
         },
-
+        
         /**
          * Method: buildGeometry.multipolygon
          * Given an OpenLayers multipolygon geometry, create a GML multipolygon.
@@ -36037,7 +39265,7 @@
             return gml;
 
         },
-
+ 
         /**
          * Method: buildGeometry.bounds
          * Given an OpenLayers bounds, create a GML box.
@@ -36061,8 +39289,8 @@
      * (code)
      * <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates>
      * (end)
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
+     * Parameters: 
+     * geometry - {<OpenLayers.Geometry>} 
      *
      * Returns:
      * {XmlNode} created xmlNode
@@ -36082,24 +39310,25 @@
         } else {
             var points = (geometry.components) ? geometry.components : [geometry];
             for(var i=0; i<points.length; i++) {
-                parts.push(points[i].x + "," + points[i].y);
-            }
+                parts.push(points[i].x + "," + points[i].y);                
+            }            
         }
 
         var txtNode = this.createTextNode(parts.join(" "));
         coordinatesNode.appendChild(txtNode);
-
+        
         return coordinatesNode;
     },
 
-    CLASS_NAME: "OpenLayers.Format.GML"
+    CLASS_NAME: "OpenLayers.Format.GML" 
 });
 /* ======================================================================
     OpenLayers/Format/GML/Base.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -36123,7 +39352,7 @@
  *  - <OpenLayers.Format.XML>
  */
 OpenLayers.Format.GML.Base = OpenLayers.Class(OpenLayers.Format.XML, {
-
+    
     /**
      * Property: namespaces
      * {Object} Mapping of namespace aliases to namespace URIs.
@@ -36134,7 +39363,7 @@
         xsi: "http://www.w3.org/2001/XMLSchema-instance",
         wfs: "http://www.opengis.net/wfs" // this is a convenience for reading wfs:FeatureCollection
     },
-
+    
     /**
      * Property: defaultPrefix
      */
@@ -36145,13 +39374,13 @@
      * {String} Schema location for a particular minor version.
      */
     schemaLocation: null,
-
+    
     /**
      * APIProperty: featureType
      * {Array(String) or String} The local (without prefix) feature typeName(s).
      */
     featureType: null,
-
+    
     /**
      * APIProperty: featureNS
      * {String} The feature namespace.  Must be set in the options at
@@ -36170,7 +39399,7 @@
      * {Boolean} Extract attributes from GML.  Default is true.
      */
     extractAttributes: true,
-
+    
     /**
      * APIProperty: srsName
      * {String} URI for spatial reference system.  This is optional for
@@ -36184,7 +39413,7 @@
      * APIProperty: xy
      * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
      * Changing is not recommended, a new Format should be instantiated.
-     */
+     */ 
     xy: true,
 
     /**
@@ -36223,7 +39452,7 @@
      *     this instance.
      *
      * Valid options properties:
-     * featureType - {Array(String) or String} Local (without prefix) feature
+     * featureType - {Array(String) or String} Local (without prefix) feature 
      *     typeName(s) (required).
      * featureNS - {String} Feature namespace (required).
      * geometryName - {String} Geometry element name.
@@ -36236,7 +39465,7 @@
         }
         this.singleFeatureType = !options || (typeof options.featureType === "string");
     },
-
+    
     /**
      * Method: read
      *
@@ -36248,7 +39477,7 @@
      * {Array(<OpenLayers.Feature.Vector>)} An array of features.
      */
     read: function(data) {
-        if(typeof data == "string") {
+        if(typeof data == "string") { 
             data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
         }
         if(data && data.nodeType == 9) {
@@ -36278,7 +39507,7 @@
         }
         return features;
     },
-
+    
     /**
      * Property: readers
      * Contains public functions, grouped by namespace prefix, that will
@@ -36293,7 +39522,7 @@
                 this.readChildNodes(node, obj);
             },
             "featureMembers": function(node, obj) {
-                this.readChildNodes(node, obj);
+                this.readChildNodes(node, obj);                
             },
             "name": function(node, obj) {
                 obj.name = this.getChildValue(node);
@@ -36431,12 +39660,17 @@
                 // geometry or attributes.
                 var name;
                 var local = node.localName || node.nodeName.split(":").pop();
-                if (!this.singleFeatureType &&
-                    (OpenLayers.Util.indexOf(this.featureType, local) != -1)) {
+                // Since an attribute can have the same name as the feature type
+                // we only want to read the node as a feature if the parent
+                // node can have feature nodes as children.  In this case, the
+                // obj.features property is set.
+                if (obj.features) {
+                    if (!this.singleFeatureType &&
+                        (OpenLayers.Util.indexOf(this.featureType, local) !== -1)) {
                         name = "_typeName";
-                }
-                else if(local == this.featureType) {
-                    name = "_typeName";
+                    } else if(local === this.featureType) {
+                        name = "_typeName";
+                    }
                 } else {
                     // Assume attribute elements have one child node and that the child
                     // is a text node.  Otherwise assume it is a geometry node.
@@ -36479,7 +39713,7 @@
                     );
                 }
                 if(container.bounds) {
-                    feature.geometry.bounds = container.bounds;
+                    feature.bounds = container.bounds;
                 }
                 obj.features.push(feature);
             },
@@ -36498,7 +39732,7 @@
             }
         }
     },
-
+    
     /**
      * Method: write
      *
@@ -36526,7 +39760,7 @@
 
         return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
     },
-
+    
     /**
      * Property: writers
      * As a compliment to the readers property, this structure contains public
@@ -36616,7 +39850,7 @@
                     geometry = geometry.clone().transform(
                         this.internalProjection, this.externalProjection
                     );
-                }
+                }    
                 var node = this.createElementNSPlus(
                     "feature:" + this.geometryName
                 );
@@ -36650,7 +39884,7 @@
             }
         }
     },
-
+    
     /**
      * Function: setGeometryTypes
      * Sets the <geometryTypes> mapping.
@@ -36667,15 +39901,16 @@
         };
     },
 
-    CLASS_NAME: "OpenLayers.Format.GML.Base"
+    CLASS_NAME: "OpenLayers.Format.GML.Base" 
 
 });
 /* ======================================================================
     OpenLayers/Format/GML/v2.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -36690,7 +39925,7 @@
  *  - <OpenLayers.Format.GML.Base>
  */
 OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
-
+    
     /**
      * Property: schemaLocation
      * {String} Schema location for a particular minor version.
@@ -36862,16 +40097,17 @@
         "feature": OpenLayers.Format.GML.Base.prototype.writers["feature"],
         "wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"]
     },
+    
+    CLASS_NAME: "OpenLayers.Format.GML.v2" 
 
-    CLASS_NAME: "OpenLayers.Format.GML.v2"
-
 });
 /* ======================================================================
     OpenLayers/Format/GML/v3.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
 
 /**
@@ -36886,7 +40122,7 @@
  *  - <OpenLayers.Format.GML.Base>
  */
 OpenLayers.Format.GML.v3 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
-
+    
     /**
      * Property: schemaLocation
      * {String} Schema location for a particular minor version.  The writers
@@ -36903,7 +40139,7 @@
      *     instantiation).
      */
     curve: false,
-
+    
     /**
      * Property: multiCurve
      * {Boolean} Write gml:MultiCurve instead of gml:MultiLineString.  Since
@@ -36913,7 +40149,7 @@
      *     instantiation).
      */
     multiCurve: true,
-
+    
     /**
      * Property: surface
      * {Boolean} Write gml:Surface instead of gml:Polygon elements.  This also
@@ -37102,11 +40338,11 @@
                 this.readers.gml.pos.apply(this, [node, obj]);
                 container.points[1] = obj.points[0];
             }
-        }, OpenLayers.Format.GML.Base.prototype.readers["gml"]),
+        }, OpenLayers.Format.GML.Base.prototype.readers["gml"]),            
         "feature": OpenLayers.Format.GML.Base.prototype.readers["feature"],
         "wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"]
     },
-
+    
     /**
      * Method: write
      *
@@ -37198,7 +40434,7 @@
                 }
                 return this.createElementNSPlus("gml:posList", {
                     value: parts.join(" ")
-                });
+                }); 
             },
             "Surface": function(geometry) {
                 var node = this.createElementNSPlus("gml:Surface");
@@ -37327,7 +40563,7 @@
             "OpenLayers.Geometry.Collection": "GeometryCollection"
         };
     },
+    
+    CLASS_NAME: "OpenLayers.Format.GML.v3" 
 
-    CLASS_NAME: "OpenLayers.Format.GML.v3"
-
 });

Modified: branches/fusion-2.2/lib/fusion.js
===================================================================
--- branches/fusion-2.2/lib/fusion.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/lib/fusion.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1365,6 +1365,7 @@
                             'lib/MGBroker.js',
                             'lib/Widget.js',
                             'lib/Map.js',
+                            'lib/MapMessage.js',
                             'layers/Layers.js',
                             'lib/Search.js',
                             'text/en.json'];
@@ -1510,11 +1511,13 @@
         if(appDefXML){
             var googleElement = appDefXML.getElementsByTagName("GoogleScript")[0]; 
             var yahooElement = appDefXML.getElementsByTagName("YahooScript")[0]; 
-            var veElement = appDefXML.getElementsByTagName("VirtualEarthScript")[0]; 
+            var veElement = appDefXML.getElementsByTagName("VirtualEarthScript")[0];
+            var osmElement = appDefXML.getElementsByTagName("OpenStreetMapScript")[0];
 
             addElement(googleElement); 
             addElement(yahooElement); 
             addElement(veElement);
+            addElement(osmElement);
         }
     }
     

Copied: branches/fusion-2.2/lib/proj4js-combined.js (from rev 2233, trunk/lib/proj4js-combined.js)
===================================================================
--- branches/fusion-2.2/lib/proj4js-combined.js	                        (rev 0)
+++ branches/fusion-2.2/lib/proj4js-combined.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,5142 @@
+/*
+  proj4js.js -- Javascript reprojection library. 
+  
+  Authors:      Mike Adair madairATdmsolutions.ca
+                Richard Greenwood richATgreenwoodmap.com
+                Didier Richard didier.richardATign.fr
+                Stephen Irons
+  License:      LGPL as per: http://www.gnu.org/copyleft/lesser.html 
+                Note: This program is an almost direct port of the C library
+                Proj4.
+*/
+/* ======================================================================
+    proj4js.js
+   ====================================================================== */
+
+/*
+Author:       Mike Adair madairATdmsolutions.ca
+              Richard Greenwood rich at greenwoodmap.com
+License:      LGPL as per: http://www.gnu.org/copyleft/lesser.html
+
+$Id: Proj.js 2956 2007-07-09 12:17:52Z steven $
+*/
+
+/**
+ * Namespace: Proj4js
+ *
+ * Proj4js is a JavaScript library to transform point coordinates from one 
+ * coordinate system to another, including datum transformations.
+ *
+ * This library is a port of both the Proj.4 and GCTCP C libraries to JavaScript. 
+ * Enabling these transformations in the browser allows geographic data stored 
+ * in different projections to be combined in browser-based web mapping 
+ * applications.
+ * 
+ * Proj4js must have access to coordinate system initialization strings (which
+ * are the same as for PROJ.4 command line).  Thes can be included in your 
+ * application using a <script> tag or Proj4js can load CS initialization 
+ * strings from a local directory or a web service such as spatialreference.org.
+ *
+ * Similarly, Proj4js must have access to projection transform code.  These can
+ * be included individually using a <script> tag in your page, built into a 
+ * custom build of Proj4js or loaded dynamically at run-time.  Using the
+ * -combined and -compressed versions of Proj4js includes all projection class
+ * code by default.
+ *
+ * Note that dynamic loading of defs and code happens ascynchrously, check the
+ * Proj.readyToUse flag before using the Proj object.  If the defs and code
+ * required by your application are loaded through script tags, dynamic loading
+ * is not required and the Proj object will be readyToUse on return from the 
+ * constructor.
+ * 
+ * All coordinates are handled as points which have a .x and a .y property
+ * which will be modified in place.
+ *
+ * Override Proj4js.reportError for output of alerts and warnings.
+ *
+ * See http://trac.osgeo.org/proj4js/wiki/UserGuide for full details.
+*/
+
+/**
+ * Global namespace object for Proj4js library
+ */
+Proj4js = {
+
+    /**
+     * Property: defaultDatum
+     * The datum to use when no others a specified
+     */
+    defaultDatum: 'WGS84',                  //default datum
+
+    /** 
+    * Method: transform(source, dest, point)
+    * Transform a point coordinate from one map projection to another.  This is
+    * really the only public method you should need to use.
+    *
+    * Parameters:
+    * source - {Proj4js.Proj} source map projection for the transformation
+    * dest - {Proj4js.Proj} destination map projection for the transformation
+    * point - {Object} point to transform, may be geodetic (long, lat) or
+    *     projected Cartesian (x,y), but should always have x,y properties.
+    */
+    transform: function(source, dest, point) {
+        if (!source.readyToUse) {
+            this.reportError("Proj4js initialization for:"+source.srsCode+" not yet complete");
+            return point;
+        }
+        if (!dest.readyToUse) {
+            this.reportError("Proj4js initialization for:"+dest.srsCode+" not yet complete");
+            return point;
+        }
+        
+        // Workaround for Spherical Mercator
+        if ((source.srsProjNumber =="900913" && dest.datumCode != "WGS84") ||
+            (dest.srsProjNumber == "900913" && source.datumCode != "WGS84")) {
+            var wgs84 = Proj4js.WGS84;
+            this.transform(source, wgs84, point);
+            source = wgs84;
+        }
+
+        // Transform source points to long/lat, if they aren't already.
+        if ( source.projName=="longlat") {
+            point.x *= Proj4js.common.D2R;  // convert degrees to radians
+            point.y *= Proj4js.common.D2R;
+        } else {
+            if (source.to_meter) {
+                point.x *= source.to_meter;
+                point.y *= source.to_meter;
+            }
+            source.inverse(point); // Convert Cartesian to longlat
+        }
+
+        // Adjust for the prime meridian if necessary
+        if (source.from_greenwich) { 
+            point.x += source.from_greenwich; 
+        }
+
+        // Convert datums if needed, and if possible.
+        point = this.datum_transform( source.datum, dest.datum, point );
+
+        // Adjust for the prime meridian if necessary
+        if (dest.from_greenwich) {
+            point.x -= dest.from_greenwich;
+        }
+
+        if( dest.projName=="longlat" ) {             
+            // convert radians to decimal degrees
+            point.x *= Proj4js.common.R2D;
+            point.y *= Proj4js.common.R2D;
+        } else  {               // else project
+            dest.forward(point);
+            if (dest.to_meter) {
+                point.x /= dest.to_meter;
+                point.y /= dest.to_meter;
+            }
+        }
+        return point;
+    }, // transform()
+
+    /** datum_transform()
+      source coordinate system definition,
+      destination coordinate system definition,
+      point to transform in geodetic coordinates (long, lat, height)
+    */
+    datum_transform : function( source, dest, point ) {
+
+      // Short cut if the datums are identical.
+      if( source.compare_datums( dest ) ) {
+          return point; // in this case, zero is sucess,
+                    // whereas cs_compare_datums returns 1 to indicate TRUE
+                    // confusing, should fix this
+      }
+
+      // Explicitly skip datum transform by setting 'datum=none' as parameter for either source or dest
+      if( source.datum_type == Proj4js.common.PJD_NODATUM
+          || dest.datum_type == Proj4js.common.PJD_NODATUM) {
+          return point;
+      }
+
+      // If this datum requires grid shifts, then apply it to geodetic coordinates.
+      if( source.datum_type == Proj4js.common.PJD_GRIDSHIFT )
+      {
+        alert("ERROR: Grid shift transformations are not implemented yet.");
+        /*
+          pj_apply_gridshift( pj_param(source.params,"snadgrids").s, 0,
+                              point_count, point_offset, x, y, z );
+          CHECK_RETURN;
+
+          src_a = SRS_WGS84_SEMIMAJOR;
+          src_es = 0.006694379990;
+        */
+      }
+
+      if( dest.datum_type == Proj4js.common.PJD_GRIDSHIFT )
+      {
+        alert("ERROR: Grid shift transformations are not implemented yet.");
+        /*
+          dst_a = ;
+          dst_es = 0.006694379990;
+        */
+      }
+
+      // Do we need to go through geocentric coordinates?
+      if( source.es != dest.es || source.a != dest.a
+          || source.datum_type == Proj4js.common.PJD_3PARAM
+          || source.datum_type == Proj4js.common.PJD_7PARAM
+          || dest.datum_type == Proj4js.common.PJD_3PARAM
+          || dest.datum_type == Proj4js.common.PJD_7PARAM)
+      {
+
+        // Convert to geocentric coordinates.
+        source.geodetic_to_geocentric( point );
+        // CHECK_RETURN;
+
+        // Convert between datums
+        if( source.datum_type == Proj4js.common.PJD_3PARAM || source.datum_type == Proj4js.common.PJD_7PARAM ) {
+          source.geocentric_to_wgs84(point);
+          // CHECK_RETURN;
+        }
+
+        if( dest.datum_type == Proj4js.common.PJD_3PARAM || dest.datum_type == Proj4js.common.PJD_7PARAM ) {
+          dest.geocentric_from_wgs84(point);
+          // CHECK_RETURN;
+        }
+
+        // Convert back to geodetic coordinates
+        dest.geocentric_to_geodetic( point );
+          // CHECK_RETURN;
+      }
+
+      // Apply grid shift to destination if required
+      if( dest.datum_type == Proj4js.common.PJD_GRIDSHIFT )
+      {
+        alert("ERROR: Grid shift transformations are not implemented yet.");
+        // pj_apply_gridshift( pj_param(dest.params,"snadgrids").s, 1, point);
+        // CHECK_RETURN;
+      }
+      return point;
+    }, // cs_datum_transform
+
+    /**
+     * Function: reportError
+     * An internal method to report errors back to user. 
+     * Override this in applications to report error messages or throw exceptions.
+     */
+    reportError: function(msg) {
+      //console.log(msg);
+    },
+
+/**
+ *
+ * Title: Private Methods
+ * The following properties and methods are intended for internal use only.
+ *
+ * This is a minimal implementation of JavaScript inheritance methods so that 
+ * Proj4js can be used as a stand-alone library.
+ * These are copies of the equivalent OpenLayers methods at v2.7
+ */
+ 
+/**
+ * Function: extend
+ * Copy all properties of a source object to a destination object.  Modifies
+ *     the passed in destination object.  Any properties on the source object
+ *     that are set to undefined will not be (re)set on the destination object.
+ *
+ * Parameters:
+ * destination - {Object} The object that will be modified
+ * source - {Object} The object with properties to be set on the destination
+ *
+ * Returns:
+ * {Object} The destination object.
+ */
+    extend: function(destination, source) {
+      destination = destination || {};
+      if(source) {
+          for(var property in source) {
+              var value = source[property];
+              if(value !== undefined) {
+                  destination[property] = value;
+              }
+          }
+      }
+      return destination;
+    },
+
+/**
+ * Constructor: Class
+ * Base class used to construct all other classes. Includes support for 
+ *     multiple inheritance. 
+ *  
+ */
+    Class: function() {
+      var Class = function() {
+          this.initialize.apply(this, arguments);
+      };
+  
+      var extended = {};
+      var parent;
+      for(var i=0; i<arguments.length; ++i) {
+          if(typeof arguments[i] == "function") {
+              // get the prototype of the superclass
+              parent = arguments[i].prototype;
+          } else {
+              // in this case we're extending with the prototype
+              parent = arguments[i];
+          }
+          Proj4js.extend(extended, parent);
+      }
+      Class.prototype = extended;
+      
+      return Class;
+    },
+
+    /**
+     * Function: bind
+     * Bind a function to an object.  Method to easily create closures with
+     *     'this' altered.
+     * 
+     * Parameters:
+     * func - {Function} Input function.
+     * object - {Object} The object to bind to the input function (as this).
+     * 
+     * Returns:
+     * {Function} A closure with 'this' set to the passed in object.
+     */
+    bind: function(func, object) {
+        // create a reference to all arguments past the second one
+        var args = Array.prototype.slice.apply(arguments, [2]);
+        return function() {
+            // Push on any additional arguments from the actual function call.
+            // These will come after those sent to the bind call.
+            var newArgs = args.concat(
+                Array.prototype.slice.apply(arguments, [0])
+            );
+            return func.apply(object, newArgs);
+        };
+    },
+    
+/**
+ * The following properties and methods handle dynamic loading of JSON objects.
+ *
+    /**
+     * Property: scriptName
+     * {String} The filename of this script without any path.
+     */
+    scriptName: "proj4js-combined.js",
+
+    /**
+     * Property: defsLookupService
+     * AJAX service to retreive projection definition parameters from
+     */
+    defsLookupService: 'http://spatialreference.org/ref',
+
+    /**
+     * Property: libPath
+     * internal: http server path to library code.
+     */
+    libPath: null,
+
+    /**
+     * Function: getScriptLocation
+     * Return the path to this script.
+     *
+     * Returns:
+     * Path to this script
+     */
+    getScriptLocation: function () {
+        if (this.libPath) return this.libPath;
+        var scriptName = this.scriptName;
+        var scriptNameLen = scriptName.length;
+
+        var scripts = document.getElementsByTagName('script');
+        for (var i = 0; i < scripts.length; i++) {
+            var src = scripts[i].getAttribute('src');
+            if (src) {
+                var index = src.lastIndexOf(scriptName);
+                // is it found, at the end of the URL?
+                if ((index > -1) && (index + scriptNameLen == src.length)) {
+                    this.libPath = src.slice(0, -scriptNameLen);
+                    break;
+                }
+            }
+        }
+        return this.libPath||"";
+    },
+
+    /**
+     * Function: loadScript
+     * Load a JS file from a URL into a <script> tag in the page.
+     * 
+     * Parameters:
+     * url - {String} The URL containing the script to load
+     * onload - {Function} A method to be executed when the script loads successfully
+     * onfail - {Function} A method to be executed when there is an error loading the script
+     * loadCheck - {Function} A boolean method that checks to see if the script 
+     *            has loaded.  Typically this just checks for the existance of
+     *            an object in the file just loaded.
+     */
+    loadScript: function(url, onload, onfail, loadCheck) {
+      var script = document.createElement('script');
+      script.defer = false;
+      script.type = "text/javascript";
+      script.id = url;
+      script.src = url;
+      script.onload = onload;
+      script.onerror = onfail;
+      script.loadCheck = loadCheck;
+      if (/MSIE/.test(navigator.userAgent)) {
+        script.onreadystatechange = this.checkReadyState;
+      }
+      document.getElementsByTagName('head')[0].appendChild(script);
+    },
+    
+    /**
+     * Function: checkReadyState
+     * IE workaround since there is no onerror handler.  Calls the user defined 
+     * loadCheck method to determine if the script is loaded.
+     * 
+     */
+    checkReadyState: function() {
+      if (this.readyState == 'loaded') {
+        if (!this.loadCheck()) {
+          this.onerror();
+        } else {
+          this.onload();
+        }
+      }
+    }
+};
+
+/**
+ * Class: Proj4js.Proj
+ *
+ * Proj objects provide transformation methods for point coordinates
+ * between geodetic latitude/longitude and a projected coordinate system. 
+ * once they have been initialized with a projection code.
+ *
+ * Initialization of Proj objects is with a projection code, usually EPSG codes,
+ * which is the key that will be used with the Proj4js.defs array.
+ * 
+ * The code passed in will be stripped of colons and converted to uppercase
+ * to locate projection definition files.
+ *
+ * A projection object has properties for units and title strings.
+ */
+Proj4js.Proj = Proj4js.Class({
+
+  /**
+   * Property: readyToUse
+   * Flag to indicate if initialization is complete for this Proj object
+   */
+  readyToUse: false,   
+  
+  /**
+   * Property: title
+   * The title to describe the projection
+   */
+  title: null,  
+  
+  /**
+   * Property: projName
+   * The projection class for this projection, e.g. lcc (lambert conformal conic,
+   * or merc for mercator).  These are exactly equivalent to their Proj4 
+   * counterparts.
+   */
+  projName: null,
+  /**
+   * Property: units
+   * The units of the projection.  Values include 'm' and 'degrees'
+   */
+  units: null,
+  /**
+   * Property: datum
+   * The datum specified for the projection
+   */
+  datum: null,
+  /**
+   * Property: x0
+   * The x coordinate origin
+   */
+  x0: 0,
+  /**
+   * Property: y0
+   * The y coordinate origin
+   */
+  y0: 0,
+  /**
+   * Property: localCS
+   * Flag to indicate if the projection is a local one in which no transforms
+   * are required.
+   */
+  localCS: false,
+
+  /**
+   * Constructor: initialize
+   * Constructor for Proj4js.Proj objects
+  *
+  * Parameters:
+  * srsCode - a code for map projection definition parameters.  These are usually
+  * (but not always) EPSG codes.
+  */
+  initialize: function(srsCode) {
+      this.srsCodeInput = srsCode;
+      
+      //check to see if this is a WKT string
+      if ((srsCode.indexOf('GEOGCS') >= 0) ||
+          (srsCode.indexOf('GEOCCS') >= 0) ||
+          (srsCode.indexOf('PROJCS') >= 0) ||
+          (srsCode.indexOf('LOCAL_CS') >= 0)) {
+            this.parseWKT(srsCode);
+            this.datum = new Proj4js.datum(this);
+            this.loadProjCode(this.projName);
+            return;
+      }
+      
+      // DGR 2008-08-03 : support urn and url
+      if (srsCode.indexOf('urn:') == 0) {
+          //urn:ORIGINATOR:def:crs:CODESPACE:VERSION:ID
+          var urn = srsCode.split(':');
+          if ((urn[1] == 'ogc' || urn[1] =='x-ogc') &&
+              (urn[2] =='def') &&
+              (urn[3] =='crs')) {
+              srsCode = urn[4]+':'+urn[urn.length-1];
+          }
+      } else if (srsCode.indexOf('http://') == 0) {
+          //url#ID
+          var url = srsCode.split('#');
+          if (url[0].match(/epsg.org/)) {
+            // http://www.epsg.org/#
+            srsCode = 'EPSG:'+url[1];
+          } else if (url[0].match(/RIG.xml/)) {
+            //http://librairies.ign.fr/geoportail/resources/RIG.xml#
+            //http://interop.ign.fr/registers/ign/RIG.xml#
+            srsCode = 'IGNF:'+url[1];
+          }
+      }
+      this.srsCode = srsCode.toUpperCase();
+      if (this.srsCode.indexOf("EPSG") == 0) {
+          this.srsCode = this.srsCode;
+          this.srsAuth = 'epsg';
+          this.srsProjNumber = this.srsCode.substring(5);
+      // DGR 2007-11-20 : authority IGNF
+      } else if (this.srsCode.indexOf("IGNF") == 0) {
+          this.srsCode = this.srsCode;
+          this.srsAuth = 'IGNF';
+          this.srsProjNumber = this.srsCode.substring(5);
+      // DGR 2008-06-19 : pseudo-authority CRS for WMS
+      } else if (this.srsCode.indexOf("CRS") == 0) {
+          this.srsCode = this.srsCode;
+          this.srsAuth = 'CRS';
+          this.srsProjNumber = this.srsCode.substring(4);
+      } else {
+          this.srsAuth = '';
+          this.srsProjNumber = this.srsCode;
+      }
+      this.loadProjDefinition();
+  },
+  
+/**
+ * Function: loadProjDefinition
+ *    Loads the coordinate system initialization string if required.
+ *    Note that dynamic loading happens asynchronously so an application must 
+ *    wait for the readyToUse property is set to true.
+ *    To prevent dynamic loading, include the defs through a script tag in
+ *    your application.
+ *
+ */
+    loadProjDefinition: function() {
+      //check in memory
+      if (Proj4js.defs[this.srsCode]) {
+        this.defsLoaded();
+        return;
+      }
+
+      //else check for def on the server
+      var url = Proj4js.getScriptLocation() + 'defs/' + this.srsAuth.toUpperCase() + this.srsProjNumber + '.js';
+      Proj4js.loadScript(url, 
+                Proj4js.bind(this.defsLoaded, this),
+                Proj4js.bind(this.loadFromService, this),
+                Proj4js.bind(this.checkDefsLoaded, this) );
+    },
+
+/**
+ * Function: loadFromService
+ *    Creates the REST URL for loading the definition from a web service and 
+ *    loads it.
+ *
+ */
+    loadFromService: function() {
+      //else load from web service
+      var url = Proj4js.defsLookupService +'/' + this.srsAuth +'/'+ this.srsProjNumber + '/proj4js/';
+      Proj4js.loadScript(url, 
+            Proj4js.bind(this.defsLoaded, this),
+            Proj4js.bind(this.defsFailed, this),
+            Proj4js.bind(this.checkDefsLoaded, this) );
+    },
+
+/**
+ * Function: defsLoaded
+ * Continues the Proj object initilization once the def file is loaded
+ *
+ */
+    defsLoaded: function() {
+      this.parseDefs();
+      this.loadProjCode(this.projName);
+    },
+    
+/**
+ * Function: checkDefsLoaded
+ *    This is the loadCheck method to see if the def object exists
+ *
+ */
+    checkDefsLoaded: function() {
+      if (Proj4js.defs[this.srsCode]) {
+        return true;
+      } else {
+        return false;
+      }
+    },
+
+ /**
+ * Function: defsFailed
+ *    Report an error in loading the defs file, but continue on using WGS84
+ *
+ */
+   defsFailed: function() {
+      Proj4js.reportError('failed to load projection definition for: '+this.srsCode);
+      Proj4js.defs[this.srsCode] = Proj4js.defs['WGS84'];  //set it to something so it can at least continue
+      this.defsLoaded();
+    },
+
+/**
+ * Function: loadProjCode
+ *    Loads projection class code dynamically if required.
+ *     Projection code may be included either through a script tag or in
+ *     a built version of proj4js
+ *
+ */
+    loadProjCode: function(projName) {
+      if (Proj4js.Proj[projName]) {
+        this.initTransforms();
+        return;
+      }
+
+      //the URL for the projection code
+      var url = Proj4js.getScriptLocation() + 'projCode/' + projName + '.js';
+      Proj4js.loadScript(url, 
+              Proj4js.bind(this.loadProjCodeSuccess, this, projName),
+              Proj4js.bind(this.loadProjCodeFailure, this, projName), 
+              Proj4js.bind(this.checkCodeLoaded, this, projName) );
+    },
+
+ /**
+ * Function: loadProjCodeSuccess
+ *    Loads any proj dependencies or continue on to final initialization.
+ *
+ */
+    loadProjCodeSuccess: function(projName) {
+      if (Proj4js.Proj[projName].dependsOn){
+        this.loadProjCode(Proj4js.Proj[projName].dependsOn);
+      } else {
+        this.initTransforms();
+      }
+    },
+
+ /**
+ * Function: defsFailed
+ *    Report an error in loading the proj file.  Initialization of the Proj
+ *    object has failed and the readyToUse flag will never be set.
+ *
+ */
+    loadProjCodeFailure: function(projName) {
+      Proj4js.reportError("failed to find projection file for: " + projName);
+      //TBD initialize with identity transforms so proj will still work?
+    },
+    
+/**
+ * Function: checkCodeLoaded
+ *    This is the loadCheck method to see if the projection code is loaded
+ *
+ */
+    checkCodeLoaded: function(projName) {
+      if (Proj4js.Proj[projName]) {
+        return true;
+      } else {
+        return false;
+      }
+    },
+
+/**
+ * Function: initTransforms
+ *    Finalize the initialization of the Proj object
+ *
+ */
+    initTransforms: function() {
+      Proj4js.extend(this, Proj4js.Proj[this.projName]);
+      this.init();
+      this.readyToUse = true;
+  },
+
+/**
+ * Function: parseWKT
+ * Parses a WKT string to get initialization parameters
+ *
+ */
+ wktRE: /^(\w+)\[(.*)\]$/,
+ parseWKT: function(wkt) {
+    var wktMatch = wkt.match(this.wktRE);
+    if (!wktMatch) return;
+    var wktObject = wktMatch[1];
+    var wktContent = wktMatch[2];
+    var wktTemp = wktContent.split(",");
+    var wktName = wktTemp.shift();
+    wktName = wktName.replace(/^\"/,"");
+    wktName = wktName.replace(/\"$/,"");
+    
+    /*
+    wktContent = wktTemp.join(",");
+    var wktArray = wktContent.split("],");
+    for (var i=0; i<wktArray.length-1; ++i) {
+      wktArray[i] += "]";
+    }
+    */
+    
+    var wktArray = new Array();
+    var bkCount = 0;
+    var obj = "";
+    for (var i=0; i<wktTemp.length; ++i) {
+      var token = wktTemp[i];
+      for (var j=0; j<token.length; ++j) {
+        if (token.charAt(j) == "[") ++bkCount;
+        if (token.charAt(j) == "]") --bkCount;
+      }
+      obj += token;
+      if (bkCount === 0) {
+        wktArray.push(obj);
+        obj = "";
+      } else {
+        obj += ",";
+      }
+    }
+    
+    //do something based on the type of the wktObject being parsed
+    //add in variations in the spelling as required
+    switch (wktObject) {
+      case 'LOCAL_CS':
+        this.projName = 'identity'
+        this.localCS = true;
+        this.srsCode = wktName;
+        break;
+      case 'GEOGCS':
+        this.projName = 'longlat'
+        this.geocsCode = wktName;
+        if (!this.srsCode) this.srsCode = wktName;
+        break;
+      case 'PROJCS':
+        this.srsCode = wktName;
+        break;
+      case 'GEOCCS':
+        break;
+      case 'PROJECTION':
+        this.projName = Proj4js.wktProjections[wktName]
+        break;
+      case 'DATUM':
+        this.datumName = wktName;
+        break;
+      case 'LOCAL_DATUM':
+        this.datumCode = 'none';
+        break;
+      case 'SPHEROID':
+        this.ellps = wktName;
+        this.a = parseFloat(wktArray.shift());
+        this.rf = parseFloat(wktArray.shift());
+        break;
+      case 'PRIMEM':
+        this.from_greenwich = parseFloat(wktArray.shift()); //to radians?
+        break;
+      case 'UNIT':
+        this.units = wktName;
+        this.unitsPerMeter = parseFloat(wktArray.shift());
+        break;
+      case 'PARAMETER':
+        var name = wktName;
+        var value = parseFloat(parseFloat(wktArray.shift()));
+        //there amy be many variations on the wktName values, add in case
+        //statements as required
+        switch (name) {
+          case 'false_easting':
+            this.x0 = value;
+            break;
+          case 'false_northing':
+            this.y0 = value;
+            break;
+          case 'scale_factor':
+            this.k0 = value;
+            break;
+          case 'central_meridian':
+            this.long0 = value;
+            break;
+          case 'latitude_of_origin':
+            this.lat0 = value;
+            break;
+          case 'more_here':
+            break;
+          default:
+            break;
+        }
+        break;
+      case 'TOWGS84':
+        this.datum_params = wktArray;
+        break;
+      case 'MORE_HERE':
+        break;
+      default:
+        break;
+    }
+    for (var i=0; i<wktArray.length; ++i) {
+      this.parseWKT(wktArray[i]);
+    }
+ },
+
+/**
+ * Function: parseDefs
+ * Parses the PROJ.4 initialization string and sets the associated properties.
+ *
+ */
+  parseDefs: function() {
+      this.defData = Proj4js.defs[this.srsCode];
+      var paramName, paramVal;
+      if (!this.defData) {
+        return;
+      }
+      var paramArray=this.defData.split("+");
+
+      for (var prop=0; prop<paramArray.length; prop++) {
+          var property = paramArray[prop].split("=");
+          paramName = property[0].toLowerCase();
+          paramVal = property[1];
+
+          switch (paramName.replace(/\s/gi,"")) {  // trim out spaces
+              case "": break;   // throw away nameless parameter
+              case "title":  this.title = paramVal; break;
+              case "proj":   this.projName =  paramVal.replace(/\s/gi,""); break;
+              case "units":  this.units = paramVal.replace(/\s/gi,""); break;
+              case "datum":  this.datumCode = paramVal.replace(/\s/gi,""); break;
+              case "nadgrids": this.nagrids = paramVal.replace(/\s/gi,""); break;
+              case "ellps":  this.ellps = paramVal.replace(/\s/gi,""); break;
+              case "a":      this.a =  parseFloat(paramVal); break;  // semi-major radius
+              case "b":      this.b =  parseFloat(paramVal); break;  // semi-minor radius
+              // DGR 2007-11-20
+              case "rf":     this.rf = parseFloat(paramVal); break; // inverse flattening rf= a/(a-b)
+              case "lat_0":  this.lat0 = paramVal*Proj4js.common.D2R; break;        // phi0, central latitude
+              case "lat_1":  this.lat1 = paramVal*Proj4js.common.D2R; break;        //standard parallel 1
+              case "lat_2":  this.lat2 = paramVal*Proj4js.common.D2R; break;        //standard parallel 2
+              case "lat_ts": this.lat_ts = paramVal*Proj4js.common.D2R; break;      // used in merc and eqc
+              case "lon_0":  this.long0 = paramVal*Proj4js.common.D2R; break;       // lam0, central longitude
+              case "alpha":  this.alpha =  parseFloat(paramVal)*Proj4js.common.D2R; break;  //for somerc projection
+              case "lonc":   this.longc = paramVal*Proj4js.common.D2R; break;       //for somerc projection
+              case "x_0":    this.x0 = parseFloat(paramVal); break;  // false easting
+              case "y_0":    this.y0 = parseFloat(paramVal); break;  // false northing
+              case "k_0":    this.k0 = parseFloat(paramVal); break;  // projection scale factor
+              case "k":      this.k0 = parseFloat(paramVal); break;  // both forms returned
+              case "r_a":    this.R_A = true; break;                 // sphere--area of ellipsoid
+              case "zone":   this.zone = parseInt(paramVal); break;  // UTM Zone
+              case "south":   this.utmSouth = true; break;  // UTM north/south
+              case "towgs84":this.datum_params = paramVal.split(","); break;
+              case "to_meter": this.to_meter = parseFloat(paramVal); break; // cartesian scaling
+              case "from_greenwich": this.from_greenwich = paramVal*Proj4js.common.D2R; break;
+              // DGR 2008-07-09 : if pm is not a well-known prime meridian take
+              // the value instead of 0.0, then convert to radians
+              case "pm":     paramVal = paramVal.replace(/\s/gi,"");
+                             this.from_greenwich = Proj4js.PrimeMeridian[paramVal] ?
+                                Proj4js.PrimeMeridian[paramVal] : parseFloat(paramVal);
+                             this.from_greenwich *= Proj4js.common.D2R; 
+                             break;
+              case "no_defs": break; 
+              default: //alert("Unrecognized parameter: " + paramName);
+          } // switch()
+      } // for paramArray
+      this.deriveConstants();
+  },
+
+/**
+ * Function: deriveConstants
+ * Sets several derived constant values and initialization of datum and ellipse
+ *     parameters.
+ *
+ */
+  deriveConstants: function() {
+      if (this.nagrids == '@null') this.datumCode = 'none';
+      if (this.datumCode && this.datumCode != 'none') {
+        var datumDef = Proj4js.Datum[this.datumCode];
+        if (datumDef) {
+          this.datum_params = datumDef.towgs84 ? datumDef.towgs84.split(',') : null;
+          this.ellps = datumDef.ellipse;
+          this.datumName = datumDef.datumName ? datumDef.datumName : this.datumCode;
+        }
+      }
+      if (!this.a) {    // do we have an ellipsoid?
+          var ellipse = Proj4js.Ellipsoid[this.ellps] ? Proj4js.Ellipsoid[this.ellps] : Proj4js.Ellipsoid['WGS84'];
+          Proj4js.extend(this, ellipse);
+      }
+      if (this.rf && !this.b) this.b = (1.0 - 1.0/this.rf) * this.a;
+      if (Math.abs(this.a - this.b)<Proj4js.common.EPSLN) {
+        this.sphere = true;
+        this.b= this.a;
+      }
+      this.a2 = this.a * this.a;          // used in geocentric
+      this.b2 = this.b * this.b;          // used in geocentric
+      this.es = (this.a2-this.b2)/this.a2;  // e ^ 2
+      this.e = Math.sqrt(this.es);        // eccentricity
+      if (this.R_A) {
+        this.a *= 1. - this.es * (Proj4js.common.SIXTH + this.es * (Proj4js.common.RA4 + this.es * Proj4js.common.RA6));
+        this.a2 = this.a * this.a;
+        this.b2 = this.b * this.b;
+        this.es = 0.;
+      }
+      this.ep2=(this.a2-this.b2)/this.b2; // used in geocentric
+      if (!this.k0) this.k0 = 1.0;    //default value
+
+      this.datum = new Proj4js.datum(this);
+  }
+});
+
+Proj4js.Proj.longlat = {
+  init: function() {
+    //no-op for longlat
+  },
+  forward: function(pt) {
+    //identity transform
+    return pt;
+  },
+  inverse: function(pt) {
+    //identity transform
+    return pt;
+  }
+};
+Proj4js.Proj.identity = Proj4js.Proj.longlat;
+
+/**
+  Proj4js.defs is a collection of coordinate system definition objects in the 
+  PROJ.4 command line format.
+  Generally a def is added by means of a separate .js file for example:
+
+    <SCRIPT type="text/javascript" src="defs/EPSG26912.js"></SCRIPT>
+
+  def is a CS definition in PROJ.4 WKT format, for example:
+    +proj="tmerc"   //longlat, etc.
+    +a=majorRadius
+    +b=minorRadius
+    +lat0=somenumber
+    +long=somenumber
+*/
+Proj4js.defs = {
+  // These are so widely used, we'll go ahead and throw them in
+  // without requiring a separate .js file
+  'WGS84': "+title=long/lat:WGS84 +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees",
+  'EPSG:4326': "+title=long/lat:WGS84 +proj=longlat +a=6378137.0 +b=6356752.31424518 +ellps=WGS84 +datum=WGS84 +units=degrees",
+  'EPSG:4269': "+title=long/lat:NAD83 +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees",
+  'EPSG:3785': "+title= Google Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"
+};
+Proj4js.defs['GOOGLE'] = Proj4js.defs['EPSG:3785'];
+Proj4js.defs['EPSG:900913'] = Proj4js.defs['EPSG:3785'];
+Proj4js.defs['EPSG:102113'] = Proj4js.defs['EPSG:3785'];
+
+Proj4js.common = {
+  PI : 3.141592653589793238, //Math.PI,
+  HALF_PI : 1.570796326794896619, //Math.PI*0.5,
+  TWO_PI : 6.283185307179586477, //Math.PI*2,
+  FORTPI : 0.78539816339744833,
+  R2D : 57.29577951308232088,
+  D2R : 0.01745329251994329577,
+  SEC_TO_RAD : 4.84813681109535993589914102357e-6, /* SEC_TO_RAD = Pi/180/3600 */
+  EPSLN : 1.0e-10,
+  MAX_ITER : 20,
+  // following constants from geocent.c
+  COS_67P5 : 0.38268343236508977,  /* cosine of 67.5 degrees */
+  AD_C : 1.0026000,                /* Toms region 1 constant */
+
+  /* datum_type values */
+  PJD_UNKNOWN  : 0,
+  PJD_3PARAM   : 1,
+  PJD_7PARAM   : 2,
+  PJD_GRIDSHIFT: 3,
+  PJD_WGS84    : 4,   // WGS84 or equivalent
+  PJD_NODATUM  : 5,   // WGS84 or equivalent
+  SRS_WGS84_SEMIMAJOR : 6378137.0,  // only used in grid shift transforms
+
+  // ellipoid pj_set_ell.c
+  SIXTH : .1666666666666666667, /* 1/6 */
+  RA4   : .04722222222222222222, /* 17/360 */
+  RA6   : .02215608465608465608, /* 67/3024 */
+  RV4   : .06944444444444444444, /* 5/72 */
+  RV6   : .04243827160493827160, /* 55/1296 */
+
+// Function to compute the constant small m which is the radius of
+//   a parallel of latitude, phi, divided by the semimajor axis.
+// -----------------------------------------------------------------
+  msfnz : function(eccent, sinphi, cosphi) {
+      var con = eccent * sinphi;
+      return cosphi/(Math.sqrt(1.0 - con * con));
+  },
+
+// Function to compute the constant small t for use in the forward
+//   computations in the Lambert Conformal Conic and the Polar
+//   Stereographic projections.
+// -----------------------------------------------------------------
+  tsfnz : function(eccent, phi, sinphi) {
+    var con = eccent * sinphi;
+    var com = .5 * eccent;
+    con = Math.pow(((1.0 - con) / (1.0 + con)), com);
+    return (Math.tan(.5 * (this.HALF_PI - phi))/con);
+  },
+
+// Function to compute the latitude angle, phi2, for the inverse of the
+//   Lambert Conformal Conic and Polar Stereographic projections.
+// ----------------------------------------------------------------
+  phi2z : function(eccent, ts) {
+    var eccnth = .5 * eccent;
+    var con, dphi;
+    var phi = this.HALF_PI - 2 * Math.atan(ts);
+    for (var i = 0; i <= 15; i++) {
+      con = eccent * Math.sin(phi);
+      dphi = this.HALF_PI - 2 * Math.atan(ts *(Math.pow(((1.0 - con)/(1.0 + con)),eccnth))) - phi;
+      phi += dphi;
+      if (Math.abs(dphi) <= .0000000001) return phi;
+    }
+    alert("phi2z has NoConvergence");
+    return (-9999);
+  },
+
+/* Function to compute constant small q which is the radius of a 
+   parallel of latitude, phi, divided by the semimajor axis. 
+------------------------------------------------------------*/
+  qsfnz : function(eccent,sinphi) {
+    var con;
+    if (eccent > 1.0e-7) {
+      con = eccent * sinphi;
+      return (( 1.0- eccent * eccent) * (sinphi /(1.0 - con * con) - (.5/eccent)*Math.log((1.0 - con)/(1.0 + con))));
+    } else {
+      return(2.0 * sinphi);
+    }
+  },
+
+/* Function to eliminate roundoff errors in asin
+----------------------------------------------*/
+  asinz : function(x) {
+    if (Math.abs(x)>1.0) {
+      x=(x>1.0)?1.0:-1.0;
+    }
+    return Math.asin(x);
+  },
+
+// following functions from gctpc cproj.c for transverse mercator projections
+  e0fn : function(x) {return(1.0-0.25*x*(1.0+x/16.0*(3.0+1.25*x)));},
+  e1fn : function(x) {return(0.375*x*(1.0+0.25*x*(1.0+0.46875*x)));},
+  e2fn : function(x) {return(0.05859375*x*x*(1.0+0.75*x));},
+  e3fn : function(x) {return(x*x*x*(35.0/3072.0));},
+  mlfn : function(e0,e1,e2,e3,phi) {return(e0*phi-e1*Math.sin(2.0*phi)+e2*Math.sin(4.0*phi)-e3*Math.sin(6.0*phi));},
+
+  srat : function(esinp, exp) {
+    return(Math.pow((1.0-esinp)/(1.0+esinp), exp));
+  },
+
+// Function to return the sign of an argument
+  sign : function(x) { if (x < 0.0) return(-1); else return(1);},
+
+// Function to adjust longitude to -180 to 180; input in radians
+  adjust_lon : function(x) {
+    x = (Math.abs(x) < this.PI) ? x: (x - (this.sign(x)*this.TWO_PI) );
+    return x;
+  },
+
+// IGNF - DGR : algorithms used by IGN France
+
+// Function to adjust latitude to -90 to 90; input in radians
+  adjust_lat : function(x) {
+    x= (Math.abs(x) < this.HALF_PI) ? x: (x - (this.sign(x)*this.PI) );
+    return x;
+  },
+
+// Latitude Isometrique - close to tsfnz ...
+  latiso : function(eccent, phi, sinphi) {
+    if (Math.abs(phi) > this.HALF_PI) return +Number.NaN;
+    if (phi==this.HALF_PI) return Number.POSITIVE_INFINITY;
+    if (phi==-1.0*this.HALF_PI) return -1.0*Number.POSITIVE_INFINITY;
+
+    var con= eccent*sinphi;
+    return Math.log(Math.tan((this.HALF_PI+phi)/2.0))+eccent*Math.log((1.0-con)/(1.0+con))/2.0;
+  },
+
+  fL : function(x,L) {
+    return 2.0*Math.atan(x*Math.exp(L)) - this.HALF_PI;
+  },
+
+// Inverse Latitude Isometrique - close to ph2z
+  invlatiso : function(eccent, ts) {
+    var phi= this.fL(1.0,ts);
+    var Iphi= 0.0;
+    var con= 0.0;
+    do {
+      Iphi= phi;
+      con= eccent*Math.sin(Iphi);
+      phi= this.fL(Math.exp(eccent*Math.log((1.0+con)/(1.0-con))/2.0),ts)
+    } while (Math.abs(phi-Iphi)>1.0e-12);
+    return phi;
+  },
+
+// Needed for Gauss Schreiber
+// Original:  Denis Makarov (info at binarythings.com)
+// Web Site:  http://www.binarythings.com
+  sinh : function(x)
+  {
+    var r= Math.exp(x);
+    r= (r-1.0/r)/2.0;
+    return r;
+  },
+
+  cosh : function(x)
+  {
+    var r= Math.exp(x);
+    r= (r+1.0/r)/2.0;
+    return r;
+  },
+
+  tanh : function(x)
+  {
+    var r= Math.exp(x);
+    r= (r-1.0/r)/(r+1.0/r);
+    return r;
+  },
+
+  asinh : function(x)
+  {
+    var s= (x>= 0? 1.0:-1.0);
+    return s*(Math.log( Math.abs(x) + Math.sqrt(x*x+1.0) ));
+  },
+
+  acosh : function(x)
+  {
+    return 2.0*Math.log(Math.sqrt((x+1.0)/2.0) + Math.sqrt((x-1.0)/2.0));
+  },
+
+  atanh : function(x)
+  {
+    return Math.log((x-1.0)/(x+1.0))/2.0;
+  },
+
+// Grande Normale
+  gN : function(a,e,sinphi)
+  {
+    var temp= e*sinphi;
+    return a/Math.sqrt(1.0 - temp*temp);
+  }
+
+};
+
+/** datum object
+*/
+Proj4js.datum = Proj4js.Class({
+
+  initialize : function(proj) {
+    this.datum_type = Proj4js.common.PJD_WGS84;   //default setting
+    if (proj.datumCode && proj.datumCode == 'none') {
+      this.datum_type = Proj4js.common.PJD_NODATUM;
+    }
+    if (proj && proj.datum_params) {
+      for (var i=0; i<proj.datum_params.length; i++) {
+        proj.datum_params[i]=parseFloat(proj.datum_params[i]);
+      }
+      if (proj.datum_params[0] != 0 || proj.datum_params[1] != 0 || proj.datum_params[2] != 0 ) {
+        this.datum_type = Proj4js.common.PJD_3PARAM;
+      }
+      if (proj.datum_params.length > 3) {
+        if (proj.datum_params[3] != 0 || proj.datum_params[4] != 0 ||
+            proj.datum_params[5] != 0 || proj.datum_params[6] != 0 ) {
+          this.datum_type = Proj4js.common.PJD_7PARAM;
+          proj.datum_params[3] *= Proj4js.common.SEC_TO_RAD;
+          proj.datum_params[4] *= Proj4js.common.SEC_TO_RAD;
+          proj.datum_params[5] *= Proj4js.common.SEC_TO_RAD;
+          proj.datum_params[6] = (proj.datum_params[6]/1000000.0) + 1.0;
+        }
+      }
+    }
+    if (proj) {
+      this.a = proj.a;    //datum object also uses these values
+      this.b = proj.b;
+      this.es = proj.es;
+      this.ep2 = proj.ep2;
+      this.datum_params = proj.datum_params;
+    }
+  },
+
+  /****************************************************************/
+  // cs_compare_datums()
+  //   Returns 1 (TRUE) if the two datums match, otherwise 0 (FALSE).
+  compare_datums : function( dest ) {
+    if( this.datum_type != dest.datum_type ) {
+      return false; // false, datums are not equal
+    } else if( this.a != dest.a || Math.abs(this.es-dest.es) > 0.000000000050 ) {
+      // the tolerence for es is to ensure that GRS80 and WGS84
+      // are considered identical
+      return false;
+    } else if( this.datum_type == Proj4js.common.PJD_3PARAM ) {
+      return (this.datum_params[0] == dest.datum_params[0]
+              && this.datum_params[1] == dest.datum_params[1]
+              && this.datum_params[2] == dest.datum_params[2]);
+    } else if( this.datum_type == Proj4js.common.PJD_7PARAM ) {
+      return (this.datum_params[0] == dest.datum_params[0]
+              && this.datum_params[1] == dest.datum_params[1]
+              && this.datum_params[2] == dest.datum_params[2]
+              && this.datum_params[3] == dest.datum_params[3]
+              && this.datum_params[4] == dest.datum_params[4]
+              && this.datum_params[5] == dest.datum_params[5]
+              && this.datum_params[6] == dest.datum_params[6]);
+    } else if( this.datum_type == Proj4js.common.PJD_GRIDSHIFT ) {
+      return strcmp( pj_param(this.params,"snadgrids").s,
+                     pj_param(dest.params,"snadgrids").s ) == 0;
+    } else {
+      return true; // datums are equal
+    }
+  }, // cs_compare_datums()
+
+  /*
+   * The function Convert_Geodetic_To_Geocentric converts geodetic coordinates
+   * (latitude, longitude, and height) to geocentric coordinates (X, Y, Z),
+   * according to the current ellipsoid parameters.
+   *
+   *    Latitude  : Geodetic latitude in radians                     (input)
+   *    Longitude : Geodetic longitude in radians                    (input)
+   *    Height    : Geodetic height, in meters                       (input)
+   *    X         : Calculated Geocentric X coordinate, in meters    (output)
+   *    Y         : Calculated Geocentric Y coordinate, in meters    (output)
+   *    Z         : Calculated Geocentric Z coordinate, in meters    (output)
+   *
+   */
+  geodetic_to_geocentric : function(p) {
+    var Longitude = p.x;
+    var Latitude = p.y;
+    var Height = p.z ? p.z : 0;   //Z value not always supplied
+    var X;  // output
+    var Y;
+    var Z;
+
+    var Error_Code=0;  //  GEOCENT_NO_ERROR;
+    var Rn;            /*  Earth radius at location  */
+    var Sin_Lat;       /*  Math.sin(Latitude)  */
+    var Sin2_Lat;      /*  Square of Math.sin(Latitude)  */
+    var Cos_Lat;       /*  Math.cos(Latitude)  */
+
+    /*
+    ** Don't blow up if Latitude is just a little out of the value
+    ** range as it may just be a rounding issue.  Also removed longitude
+    ** test, it should be wrapped by Math.cos() and Math.sin().  NFW for PROJ.4, Sep/2001.
+    */
+    if( Latitude < -Proj4js.common.HALF_PI && Latitude > -1.001 * Proj4js.common.HALF_PI ) {
+        Latitude = -Proj4js.common.HALF_PI;
+    } else if( Latitude > Proj4js.common.HALF_PI && Latitude < 1.001 * Proj4js.common.HALF_PI ) {
+        Latitude = Proj4js.common.HALF_PI;
+    } else if ((Latitude < -Proj4js.common.HALF_PI) || (Latitude > Proj4js.common.HALF_PI)) {
+      /* Latitude out of range */
+      Proj4js.reportError('geocent:lat out of range:'+Latitude);
+      return null;
+    }
+
+    if (Longitude > Proj4js.common.PI) Longitude -= (2*Proj4js.common.PI);
+    Sin_Lat = Math.sin(Latitude);
+    Cos_Lat = Math.cos(Latitude);
+    Sin2_Lat = Sin_Lat * Sin_Lat;
+    Rn = this.a / (Math.sqrt(1.0e0 - this.es * Sin2_Lat));
+    X = (Rn + Height) * Cos_Lat * Math.cos(Longitude);
+    Y = (Rn + Height) * Cos_Lat * Math.sin(Longitude);
+    Z = ((Rn * (1 - this.es)) + Height) * Sin_Lat;
+
+    p.x = X;
+    p.y = Y;
+    p.z = Z;
+    return Error_Code;
+  }, // cs_geodetic_to_geocentric()
+
+
+  geocentric_to_geodetic : function (p) {
+/* local defintions and variables */
+/* end-criterium of loop, accuracy of sin(Latitude) */
+var genau = 1.E-12;
+var genau2 = (genau*genau);
+var maxiter = 30;
+
+    var P;        /* distance between semi-minor axis and location */
+    var RR;       /* distance between center and location */
+    var CT;       /* sin of geocentric latitude */
+    var ST;       /* cos of geocentric latitude */
+    var RX;
+    var RK;
+    var RN;       /* Earth radius at location */
+    var CPHI0;    /* cos of start or old geodetic latitude in iterations */
+    var SPHI0;    /* sin of start or old geodetic latitude in iterations */
+    var CPHI;     /* cos of searched geodetic latitude */
+    var SPHI;     /* sin of searched geodetic latitude */
+    var SDPHI;    /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */
+    var At_Pole;     /* indicates location is in polar region */
+    var iter;        /* # of continous iteration, max. 30 is always enough (s.a.) */
+
+    var X = p.x;
+    var Y = p.y;
+    var Z = p.z ? p.z : 0.0;   //Z value not always supplied
+    var Longitude;
+    var Latitude;
+    var Height;
+
+    At_Pole = false;
+    P = Math.sqrt(X*X+Y*Y);
+    RR = Math.sqrt(X*X+Y*Y+Z*Z);
+
+/*      special cases for latitude and longitude */
+    if (P/this.a < genau) {
+
+/*  special case, if P=0. (X=0., Y=0.) */
+        At_Pole = true;
+        Longitude = 0.0;
+
+/*  if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis
+ *  of ellipsoid (=center of mass), Latitude becomes PI/2 */
+        if (RR/this.a < genau) {
+            Latitude = Proj4js.common.HALF_PI;
+            Height   = -this.b;
+            return;
+        }
+    } else {
+/*  ellipsoidal (geodetic) longitude
+ *  interval: -PI < Longitude <= +PI */
+        Longitude=Math.atan2(Y,X);
+    }
+
+/* --------------------------------------------------------------
+ * Following iterative algorithm was developped by
+ * "Institut für Erdmessung", University of Hannover, July 1988.
+ * Internet: www.ife.uni-hannover.de
+ * Iterative computation of CPHI,SPHI and Height.
+ * Iteration of CPHI and SPHI to 10**-12 radian resp.
+ * 2*10**-7 arcsec.
+ * --------------------------------------------------------------
+ */
+    CT = Z/RR;
+    ST = P/RR;
+    RX = 1.0/Math.sqrt(1.0-this.es*(2.0-this.es)*ST*ST);
+    CPHI0 = ST*(1.0-this.es)*RX;
+    SPHI0 = CT*RX;
+    iter = 0;
+
+/* loop to find sin(Latitude) resp. Latitude
+ * until |sin(Latitude(iter)-Latitude(iter-1))| < genau */
+    do
+    {
+        iter++;
+        RN = this.a/Math.sqrt(1.0-this.es*SPHI0*SPHI0);
+
+/*  ellipsoidal (geodetic) height */
+        Height = P*CPHI0+Z*SPHI0-RN*(1.0-this.es*SPHI0*SPHI0);
+
+        RK = this.es*RN/(RN+Height);
+        RX = 1.0/Math.sqrt(1.0-RK*(2.0-RK)*ST*ST);
+        CPHI = ST*(1.0-RK)*RX;
+        SPHI = CT*RX;
+        SDPHI = SPHI*CPHI0-CPHI*SPHI0;
+        CPHI0 = CPHI;
+        SPHI0 = SPHI;
+    }
+    while (SDPHI*SDPHI > genau2 && iter < maxiter);
+
+/*      ellipsoidal (geodetic) latitude */
+    Latitude=Math.atan(SPHI/Math.abs(CPHI));
+
+    p.x = Longitude;
+    p.y = Latitude;
+    p.z = Height;
+    return p;
+  }, // cs_geocentric_to_geodetic()
+
+  /** Convert_Geocentric_To_Geodetic
+   * The method used here is derived from 'An Improved Algorithm for
+   * Geocentric to Geodetic Coordinate Conversion', by Ralph Toms, Feb 1996
+   */
+  geocentric_to_geodetic_noniter : function (p) {
+    var X = p.x;
+    var Y = p.y;
+    var Z = p.z ? p.z : 0;   //Z value not always supplied
+    var Longitude;
+    var Latitude;
+    var Height;
+
+    var W;        /* distance from Z axis */
+    var W2;       /* square of distance from Z axis */
+    var T0;       /* initial estimate of vertical component */
+    var T1;       /* corrected estimate of vertical component */
+    var S0;       /* initial estimate of horizontal component */
+    var S1;       /* corrected estimate of horizontal component */
+    var Sin_B0;   /* Math.sin(B0), B0 is estimate of Bowring aux variable */
+    var Sin3_B0;  /* cube of Math.sin(B0) */
+    var Cos_B0;   /* Math.cos(B0) */
+    var Sin_p1;   /* Math.sin(phi1), phi1 is estimated latitude */
+    var Cos_p1;   /* Math.cos(phi1) */
+    var Rn;       /* Earth radius at location */
+    var Sum;      /* numerator of Math.cos(phi1) */
+    var At_Pole;  /* indicates location is in polar region */
+
+    X = parseFloat(X);  // cast from string to float
+    Y = parseFloat(Y);
+    Z = parseFloat(Z);
+
+    At_Pole = false;
+    if (X != 0.0)
+    {
+        Longitude = Math.atan2(Y,X);
+    }
+    else
+    {
+        if (Y > 0)
+        {
+            Longitude = Proj4js.common.HALF_PI;
+        }
+        else if (Y < 0)
+        {
+            Longitude = -Proj4js.common.HALF_PI;
+        }
+        else
+        {
+            At_Pole = true;
+            Longitude = 0.0;
+            if (Z > 0.0)
+            {  /* north pole */
+                Latitude = Proj4js.common.HALF_PI;
+            }
+            else if (Z < 0.0)
+            {  /* south pole */
+                Latitude = -Proj4js.common.HALF_PI;
+            }
+            else
+            {  /* center of earth */
+                Latitude = Proj4js.common.HALF_PI;
+                Height = -this.b;
+                return;
+            }
+        }
+    }
+    W2 = X*X + Y*Y;
+    W = Math.sqrt(W2);
+    T0 = Z * Proj4js.common.AD_C;
+    S0 = Math.sqrt(T0 * T0 + W2);
+    Sin_B0 = T0 / S0;
+    Cos_B0 = W / S0;
+    Sin3_B0 = Sin_B0 * Sin_B0 * Sin_B0;
+    T1 = Z + this.b * this.ep2 * Sin3_B0;
+    Sum = W - this.a * this.es * Cos_B0 * Cos_B0 * Cos_B0;
+    S1 = Math.sqrt(T1*T1 + Sum * Sum);
+    Sin_p1 = T1 / S1;
+    Cos_p1 = Sum / S1;
+    Rn = this.a / Math.sqrt(1.0 - this.es * Sin_p1 * Sin_p1);
+    if (Cos_p1 >= Proj4js.common.COS_67P5)
+    {
+        Height = W / Cos_p1 - Rn;
+    }
+    else if (Cos_p1 <= -Proj4js.common.COS_67P5)
+    {
+        Height = W / -Cos_p1 - Rn;
+    }
+    else
+    {
+        Height = Z / Sin_p1 + Rn * (this.es - 1.0);
+    }
+    if (At_Pole == false)
+    {
+        Latitude = Math.atan(Sin_p1 / Cos_p1);
+    }
+
+    p.x = Longitude;
+    p.y = Latitude;
+    p.z = Height;
+    return p;
+  }, // geocentric_to_geodetic_noniter()
+
+  /****************************************************************/
+  // pj_geocentic_to_wgs84( p )
+  //  p = point to transform in geocentric coordinates (x,y,z)
+  geocentric_to_wgs84 : function ( p ) {
+
+    if( this.datum_type == Proj4js.common.PJD_3PARAM )
+    {
+      // if( x[io] == HUGE_VAL )
+      //    continue;
+      p.x += this.datum_params[0];
+      p.y += this.datum_params[1];
+      p.z += this.datum_params[2];
+
+    }
+    else if (this.datum_type == Proj4js.common.PJD_7PARAM)
+    {
+      var Dx_BF =this.datum_params[0];
+      var Dy_BF =this.datum_params[1];
+      var Dz_BF =this.datum_params[2];
+      var Rx_BF =this.datum_params[3];
+      var Ry_BF =this.datum_params[4];
+      var Rz_BF =this.datum_params[5];
+      var M_BF  =this.datum_params[6];
+      // if( x[io] == HUGE_VAL )
+      //    continue;
+      var x_out = M_BF*(       p.x - Rz_BF*p.y + Ry_BF*p.z) + Dx_BF;
+      var y_out = M_BF*( Rz_BF*p.x +       p.y - Rx_BF*p.z) + Dy_BF;
+      var z_out = M_BF*(-Ry_BF*p.x + Rx_BF*p.y +       p.z) + Dz_BF;
+      p.x = x_out;
+      p.y = y_out;
+      p.z = z_out;
+    }
+  }, // cs_geocentric_to_wgs84
+
+  /****************************************************************/
+  // pj_geocentic_from_wgs84()
+  //  coordinate system definition,
+  //  point to transform in geocentric coordinates (x,y,z)
+  geocentric_from_wgs84 : function( p ) {
+
+    if( this.datum_type == Proj4js.common.PJD_3PARAM )
+    {
+      //if( x[io] == HUGE_VAL )
+      //    continue;
+      p.x -= this.datum_params[0];
+      p.y -= this.datum_params[1];
+      p.z -= this.datum_params[2];
+
+    }
+    else if (this.datum_type == Proj4js.common.PJD_7PARAM)
+    {
+      var Dx_BF =this.datum_params[0];
+      var Dy_BF =this.datum_params[1];
+      var Dz_BF =this.datum_params[2];
+      var Rx_BF =this.datum_params[3];
+      var Ry_BF =this.datum_params[4];
+      var Rz_BF =this.datum_params[5];
+      var M_BF  =this.datum_params[6];
+      var x_tmp = (p.x - Dx_BF) / M_BF;
+      var y_tmp = (p.y - Dy_BF) / M_BF;
+      var z_tmp = (p.z - Dz_BF) / M_BF;
+      //if( x[io] == HUGE_VAL )
+      //    continue;
+
+      p.x =        x_tmp + Rz_BF*y_tmp - Ry_BF*z_tmp;
+      p.y = -Rz_BF*x_tmp +       y_tmp + Rx_BF*z_tmp;
+      p.z =  Ry_BF*x_tmp - Rx_BF*y_tmp +       z_tmp;
+    } //cs_geocentric_from_wgs84()
+  }
+});
+
+/** point object, nothing fancy, just allows values to be
+    passed back and forth by reference rather than by value.
+    Other point classes may be used as long as they have
+    x and y properties, which will get modified in the transform method.
+*/
+Proj4js.Point = Proj4js.Class({
+
+    /**
+     * Constructor: Proj4js.Point
+     *
+     * Parameters:
+     * - x {float} or {Array} either the first coordinates component or
+     *     the full coordinates
+     * - y {float} the second component
+     * - z {float} the third component, optional.
+     */
+    initialize : function(x,y,z) {
+      if (typeof x == 'object') {
+        this.x = x[0];
+        this.y = x[1];
+        this.z = x[2] || 0.0;
+      } else if (typeof x == 'string') {
+        var coords = x.split(',');
+        this.x = parseFloat(coords[0]);
+        this.y = parseFloat(coords[1]);
+        this.z = parseFloat(coords[2]) || 0.0;
+      } else {
+        this.x = x;
+        this.y = y;
+        this.z = z || 0.0;
+      }
+    },
+
+    /**
+     * APIMethod: clone
+     * Build a copy of a Proj4js.Point object.
+     *
+     * Return:
+     * {Proj4js}.Point the cloned point.
+     */
+    clone : function() {
+      return new Proj4js.Point(this.x, this.y, this.z);
+    },
+
+    /**
+     * APIMethod: toString
+     * Return a readable string version of the point
+     *
+     * Return:
+     * {String} String representation of Proj4js.Point object. 
+     *           (ex. <i>"x=5,y=42"</i>)
+     */
+    toString : function() {
+        return ("x=" + this.x + ",y=" + this.y);
+    },
+
+    /** 
+     * APIMethod: toShortString
+     * Return a short string version of the point.
+     *
+     * Return:
+     * {String} Shortened String representation of Proj4js.Point object. 
+     *         (ex. <i>"5, 42"</i>)
+     */
+    toShortString : function() {
+        return (this.x + ", " + this.y);
+    }
+});
+
+Proj4js.PrimeMeridian = {
+    "greenwich": 0.0,               //"0dE",
+    "lisbon":     -9.131906111111,   //"9d07'54.862\"W",
+    "paris":       2.337229166667,   //"2d20'14.025\"E",
+    "bogota":    -74.080916666667,  //"74d04'51.3\"W",
+    "madrid":     -3.687938888889,  //"3d41'16.58\"W",
+    "rome":       12.452333333333,  //"12d27'8.4\"E",
+    "bern":        7.439583333333,  //"7d26'22.5\"E",
+    "jakarta":   106.807719444444,  //"106d48'27.79\"E",
+    "ferro":     -17.666666666667,  //"17d40'W",
+    "brussels":    4.367975,        //"4d22'4.71\"E",
+    "stockholm":  18.058277777778,  //"18d3'29.8\"E",
+    "athens":     23.7163375,       //"23d42'58.815\"E",
+    "oslo":       10.722916666667   //"10d43'22.5\"E"
+};
+
+Proj4js.Ellipsoid = {
+  "MERIT": {a:6378137.0, rf:298.257, ellipseName:"MERIT 1983"},
+  "SGS85": {a:6378136.0, rf:298.257, ellipseName:"Soviet Geodetic System 85"},
+  "GRS80": {a:6378137.0, rf:298.257222101, ellipseName:"GRS 1980(IUGG, 1980)"},
+  "IAU76": {a:6378140.0, rf:298.257, ellipseName:"IAU 1976"},
+  "airy": {a:6377563.396, b:6356256.910, ellipseName:"Airy 1830"},
+  "APL4.": {a:6378137, rf:298.25, ellipseName:"Appl. Physics. 1965"},
+  "NWL9D": {a:6378145.0, rf:298.25, ellipseName:"Naval Weapons Lab., 1965"},
+  "mod_airy": {a:6377340.189, b:6356034.446, ellipseName:"Modified Airy"},
+  "andrae": {a:6377104.43, rf:300.0, ellipseName:"Andrae 1876 (Den., Iclnd.)"},
+  "aust_SA": {a:6378160.0, rf:298.25, ellipseName:"Australian Natl & S. Amer. 1969"},
+  "GRS67": {a:6378160.0, rf:298.2471674270, ellipseName:"GRS 67(IUGG 1967)"},
+  "bessel": {a:6377397.155, rf:299.1528128, ellipseName:"Bessel 1841"},
+  "bess_nam": {a:6377483.865, rf:299.1528128, ellipseName:"Bessel 1841 (Namibia)"},
+  "clrk66": {a:6378206.4, b:6356583.8, ellipseName:"Clarke 1866"},
+  "clrk80": {a:6378249.145, rf:293.4663, ellipseName:"Clarke 1880 mod."},
+  "CPM": {a:6375738.7, rf:334.29, ellipseName:"Comm. des Poids et Mesures 1799"},
+  "delmbr": {a:6376428.0, rf:311.5, ellipseName:"Delambre 1810 (Belgium)"},
+  "engelis": {a:6378136.05, rf:298.2566, ellipseName:"Engelis 1985"},
+  "evrst30": {a:6377276.345, rf:300.8017, ellipseName:"Everest 1830"},
+  "evrst48": {a:6377304.063, rf:300.8017, ellipseName:"Everest 1948"},
+  "evrst56": {a:6377301.243, rf:300.8017, ellipseName:"Everest 1956"},
+  "evrst69": {a:6377295.664, rf:300.8017, ellipseName:"Everest 1969"},
+  "evrstSS": {a:6377298.556, rf:300.8017, ellipseName:"Everest (Sabah & Sarawak)"},
+  "fschr60": {a:6378166.0, rf:298.3, ellipseName:"Fischer (Mercury Datum) 1960"},
+  "fschr60m": {a:6378155.0, rf:298.3, ellipseName:"Fischer 1960"},
+  "fschr68": {a:6378150.0, rf:298.3, ellipseName:"Fischer 1968"},
+  "helmert": {a:6378200.0, rf:298.3, ellipseName:"Helmert 1906"},
+  "hough": {a:6378270.0, rf:297.0, ellipseName:"Hough"},
+  "intl": {a:6378388.0, rf:297.0, ellipseName:"International 1909 (Hayford)"},
+  "kaula": {a:6378163.0, rf:298.24, ellipseName:"Kaula 1961"},
+  "lerch": {a:6378139.0, rf:298.257, ellipseName:"Lerch 1979"},
+  "mprts": {a:6397300.0, rf:191.0, ellipseName:"Maupertius 1738"},
+  "new_intl": {a:6378157.5, b:6356772.2, ellipseName:"New International 1967"},
+  "plessis": {a:6376523.0, rf:6355863.0, ellipseName:"Plessis 1817 (France)"},
+  "krass": {a:6378245.0, rf:298.3, ellipseName:"Krassovsky, 1942"},
+  "SEasia": {a:6378155.0, b:6356773.3205, ellipseName:"Southeast Asia"},
+  "walbeck": {a:6376896.0, b:6355834.8467, ellipseName:"Walbeck"},
+  "WGS60": {a:6378165.0, rf:298.3, ellipseName:"WGS 60"},
+  "WGS66": {a:6378145.0, rf:298.25, ellipseName:"WGS 66"},
+  "WGS72": {a:6378135.0, rf:298.26, ellipseName:"WGS 72"},
+  "WGS84": {a:6378137.0, rf:298.257223563, ellipseName:"WGS 84"},
+  "sphere": {a:6370997.0, b:6370997.0, ellipseName:"Normal Sphere (r=6370997)"}
+};
+
+Proj4js.Datum = {
+  "WGS84": {towgs84: "0,0,0", ellipse: "WGS84", datumName: "WGS84"},
+  "GGRS87": {towgs84: "-199.87,74.79,246.62", ellipse: "GRS80", datumName: "Greek_Geodetic_Reference_System_1987"},
+  "NAD83": {towgs84: "0,0,0", ellipse: "GRS80", datumName: "North_American_Datum_1983"},
+  "NAD27": {nadgrids: "@conus, at alaska, at ntv2_0.gsb, at ntv1_can.dat", ellipse: "clrk66", datumName: "North_American_Datum_1927"},
+  "potsdam": {towgs84: "606.0,23.0,413.0", ellipse: "bessel", datumName: "Potsdam Rauenberg 1950 DHDN"},
+  "carthage": {towgs84: "-263.0,6.0,431.0", ellipse: "clark80", datumName: "Carthage 1934 Tunisia"},
+  "hermannskogel": {towgs84: "653.0,-212.0,449.0", ellipse: "bessel", datumName: "Hermannskogel"},
+  "ire65": {towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15", ellipse: "mod_airy", datumName: "Ireland 1965"},
+  "nzgd49": {towgs84: "59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993", ellipse: "intl", datumName: "New Zealand Geodetic Datum 1949"},
+  "OSGB36": {towgs84: "446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894", ellipse: "airy", datumName: "Airy 1830"}
+};
+
+Proj4js.WGS84 = new Proj4js.Proj('WGS84');
+Proj4js.Datum['OSB36'] = Proj4js.Datum['OSGB36']; //as returned from spatialreference.org
+
+//lookup table to go from the projection name in WKT to the Proj4js projection name
+//build this out as required
+Proj4js.wktProjections = {
+  "Lambert Tangential Conformal Conic Projection": "lcc",
+  "Mercator": "merc",
+  "Transverse_Mercator": "tmerc",
+  "Transverse Mercator": "tmerc",
+  "Lambert Azimuthal Equal Area": "laea",
+  "Universal Transverse Mercator System": "utm"
+};
+
+
+/* ======================================================================
+    projCode/aea.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                     ALBERS CONICAL EQUAL AREA 
+
+PURPOSE:	Transforms input longitude and latitude to Easting and Northing
+		for the Albers Conical Equal Area projection.  The longitude
+		and latitude must be in radians.  The Easting and Northing
+		values will be returned in meters.
+
+PROGRAMMER              DATE
+----------              ----
+T. Mittan,       	Feb, 1992
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+    Printing Office, Washington D.C., 1989.
+*******************************************************************************/
+
+
+Proj4js.Proj.aea = {
+  init : function() {
+
+    if (Math.abs(this.lat1 + this.lat2) < Proj4js.common.EPSLN) {
+       Proj4js.reportError("aeaInitEqualLatitudes");
+       return;
+    }
+    this.temp = this.b / this.a;
+    this.es = 1.0 - Math.pow(this.temp,2);
+    this.e3 = Math.sqrt(this.es);
+
+    this.sin_po=Math.sin(this.lat1);
+    this.cos_po=Math.cos(this.lat1);
+    this.t1=this.sin_po;
+    this.con = this.sin_po;
+    this.ms1 = Proj4js.common.msfnz(this.e3,this.sin_po,this.cos_po);
+    this.qs1 = Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);
+
+    this.sin_po=Math.sin(this.lat2);
+    this.cos_po=Math.cos(this.lat2);
+    this.t2=this.sin_po;
+    this.ms2 = Proj4js.common.msfnz(this.e3,this.sin_po,this.cos_po);
+    this.qs2 = Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);
+
+    this.sin_po=Math.sin(this.lat0);
+    this.cos_po=Math.cos(this.lat0);
+    this.t3=this.sin_po;
+    this.qs0 = Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);
+
+    if (Math.abs(this.lat1 - this.lat2) > Proj4js.common.EPSLN) {
+      this.ns0 = (this.ms1 * this.ms1 - this.ms2 *this.ms2)/ (this.qs2 - this.qs1);
+    } else {
+      this.ns0 = this.con;
+    }
+    this.c = this.ms1 * this.ms1 + this.ns0 * this.qs1;
+    this.rh = this.a * Math.sqrt(this.c - this.ns0 * this.qs0)/this.ns0;
+  },
+
+/* Albers Conical Equal Area forward equations--mapping lat,long to x,y
+  -------------------------------------------------------------------*/
+  forward: function(p){
+
+    var lon=p.x;
+    var lat=p.y;
+
+    this.sin_phi=Math.sin(lat);
+    this.cos_phi=Math.cos(lat);
+
+    var qs = Proj4js.common.qsfnz(this.e3,this.sin_phi,this.cos_phi);
+    var rh1 =this.a * Math.sqrt(this.c - this.ns0 * qs)/this.ns0;
+    var theta = this.ns0 * Proj4js.common.adjust_lon(lon - this.long0); 
+    var x = rh1 * Math.sin(theta) + this.x0;
+    var y = this.rh - rh1 * Math.cos(theta) + this.y0;
+
+    p.x = x; 
+    p.y = y;
+    return p;
+  },
+
+
+  inverse: function(p) {
+    var rh1,qs,con,theta,lon,lat;
+
+    p.x -= this.x0;
+    p.y = this.rh - p.y + this.y0;
+    if (this.ns0 >= 0) {
+      rh1 = Math.sqrt(p.x *p.x + p.y * p.y);
+      con = 1.0;
+    } else {
+      rh1 = -Math.sqrt(p.x * p.x + p.y *p.y);
+      con = -1.0;
+    }
+    theta = 0.0;
+    if (rh1 != 0.0) {
+      theta = Math.atan2(con * p.x, con * p.y);
+    }
+    con = rh1 * this.ns0 / this.a;
+    qs = (this.c - con * con) / this.ns0;
+    if (this.e3 >= 1e-10) {
+      con = 1 - .5 * (1.0 -this.es) * Math.log((1.0 - this.e3) / (1.0 + this.e3))/this.e3;
+      if (Math.abs(Math.abs(con) - Math.abs(qs)) > .0000000001 ) {
+          lat = this.phi1z(this.e3,qs);
+      } else {
+          if (qs >= 0) {
+             lat = .5 * PI;
+          } else {
+             lat = -.5 * PI;
+          }
+      }
+    } else {
+      lat = this.phi1z(e3,qs);
+    }
+
+    lon = Proj4js.common.adjust_lon(theta/this.ns0 + this.long0);
+    p.x = lon;
+    p.y = lat;
+    return p;
+  },
+  
+/* Function to compute phi1, the latitude for the inverse of the
+   Albers Conical Equal-Area projection.
+-------------------------------------------*/
+  phi1z: function (eccent,qs) {
+    var con, com, dphi;
+    var phi = Proj4js.common.asinz(.5 * qs);
+    if (eccent < Proj4js.common.EPSLN) return phi;
+    
+    var eccnts = eccent * eccent; 
+    for (var i = 1; i <= 25; i++) {
+        sinphi = Math.sin(phi);
+        cosphi = Math.cos(phi);
+        con = eccent * sinphi; 
+        com = 1.0 - con * con;
+        dphi = .5 * com * com / cosphi * (qs / (1.0 - eccnts) - sinphi / com + .5 / eccent * Math.log((1.0 - con) / (1.0 + con)));
+        phi = phi + dphi;
+        if (Math.abs(dphi) <= 1e-7) return phi;
+    }
+    Proj4js.reportError("aea:phi1z:Convergence error");
+    return null;
+  }
+  
+};
+
+
+
+/* ======================================================================
+    projCode/sterea.js
+   ====================================================================== */
+
+
+Proj4js.Proj.sterea = {
+  dependsOn : 'gauss',
+
+  init : function() {
+    Proj4js.Proj['gauss'].init.apply(this);
+    if (!this.rc) {
+      Proj4js.reportError("sterea:init:E_ERROR_0");
+      return;
+    }
+    this.sinc0 = Math.sin(this.phic0);
+    this.cosc0 = Math.cos(this.phic0);
+    this.R2 = 2.0 * this.rc;
+    if (!this.title) this.title = "Oblique Stereographic Alternative";
+  },
+
+  forward : function(p) {
+    p.x = Proj4js.common.adjust_lon(p.x-this.long0); /* adjust del longitude */
+    Proj4js.Proj['gauss'].forward.apply(this, [p]);
+    sinc = Math.sin(p.y);
+    cosc = Math.cos(p.y);
+    cosl = Math.cos(p.x);
+    k = this.k0 * this.R2 / (1.0 + this.sinc0 * sinc + this.cosc0 * cosc * cosl);
+    p.x = k * cosc * Math.sin(p.x);
+    p.y = k * (this.cosc0 * sinc - this.sinc0 * cosc * cosl);
+    p.x = this.a * p.x + this.x0;
+    p.y = this.a * p.y + this.y0;
+    return p;
+  },
+
+  inverse : function(p) {
+    var lon,lat;
+    p.x = (p.x - this.x0) / this.a; /* descale and de-offset */
+    p.y = (p.y - this.y0) / this.a;
+
+    p.x /= this.k0;
+    p.y /= this.k0;
+    if ( (rho = Math.sqrt(p.x*p.x + p.y*p.y)) ) {
+      c = 2.0 * Math.atan2(rho, this.R2);
+      sinc = Math.sin(c);
+      cosc = Math.cos(c);
+      lat = Math.asin(cosc * this.sinc0 + p.y * sinc * this.cosc0 / rho);
+      lon = Math.atan2(p.x * sinc, rho * this.cosc0 * cosc - p.y * this.sinc0 * sinc);
+    } else {
+      lat = this.phic0;
+      lon = 0.;
+    }
+
+    p.x = lon;
+    p.y = lat;
+    Proj4js.Proj['gauss'].inverse.apply(this,[p]);
+    p.x = Proj4js.common.adjust_lon(p.x + this.long0); /* adjust longitude to CM */
+    return p;
+  }
+};
+
+/* ======================================================================
+    projCode/poly.js
+   ====================================================================== */
+
+/* Function to compute, phi4, the latitude for the inverse of the
+   Polyconic projection.
+------------------------------------------------------------*/
+function phi4z (eccent,e0,e1,e2,e3,a,b,c,phi) {
+	var sinphi, sin2ph, tanph, ml, mlp, con1, con2, con3, dphi, i;
+
+	phi = a;
+	for (i = 1; i <= 15; i++) {
+		sinphi = Math.sin(phi);
+		tanphi = Math.tan(phi);
+		c = tanphi * Math.sqrt (1.0 - eccent * sinphi * sinphi);
+		sin2ph = Math.sin (2.0 * phi);
+		/*
+		ml = e0 * *phi - e1 * sin2ph + e2 * sin (4.0 *  *phi);
+		mlp = e0 - 2.0 * e1 * cos (2.0 *  *phi) + 4.0 * e2 *  cos (4.0 *  *phi);
+		*/
+		ml = e0 * phi - e1 * sin2ph + e2 * Math.sin (4.0 *  phi) - e3 * Math.sin (6.0 * phi);
+		mlp = e0 - 2.0 * e1 * Math.cos (2.0 *  phi) + 4.0 * e2 * Math.cos (4.0 *  phi) - 6.0 * e3 * Math.cos (6.0 *  phi);
+		con1 = 2.0 * ml + c * (ml * ml + b) - 2.0 * a *  (c * ml + 1.0);
+		con2 = eccent * sin2ph * (ml * ml + b - 2.0 * a * ml) / (2.0 *c);
+		con3 = 2.0 * (a - ml) * (c * mlp - 2.0 / sin2ph) - 2.0 * mlp;
+		dphi = con1 / (con2 + con3);
+		phi += dphi;
+		if (Math.abs(dphi) <= .0000000001 ) return(phi);   
+	}
+	Proj4js.reportError("phi4z: No convergence");
+	return null;
+}
+
+
+/* Function to compute the constant e4 from the input of the eccentricity
+   of the spheroid, x.  This constant is used in the Polar Stereographic
+   projection.
+--------------------------------------------------------------------*/
+function e4fn(x) {
+	var con, com;
+	con = 1.0 + x;
+	com = 1.0 - x;
+	return (Math.sqrt((Math.pow(con,con))*(Math.pow(com,com))));
+}
+
+
+
+
+
+/*******************************************************************************
+NAME                             POLYCONIC 
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Polyconic projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+PROGRAMMER              DATE
+----------              ----
+T. Mittan		Mar, 1993
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+    Printing Office, Washington D.C., 1989.
+*******************************************************************************/
+
+Proj4js.Proj.poly = {
+
+	/* Initialize the POLYCONIC projection
+	  ----------------------------------*/
+	init: function() {
+		var temp;			/* temporary variable		*/
+		if (this.lat0=0) this.lat0=90;//this.lat0 ca
+
+		/* Place parameters in static storage for common use
+		  -------------------------------------------------*/
+		this.temp = this.b / this.a;
+		this.es = 1.0 - Math.pow(this.temp,2);// devait etre dans tmerc.js mais n y est pas donc je commente sinon retour de valeurs nulles 
+		this.e = Math.sqrt(this.es);
+		this.e0 = Proj4js.common.e0fn(this.es);
+		this.e1 = Proj4js.common.e1fn(this.es);
+		this.e2 = Proj4js.common.e2fn(this.es);
+		this.e3 = Proj4js.common.e3fn(this.es);
+		this.ml0 = Proj4js.common.mlfn(this.e0, this.e1,this.e2, this.e3, this.lat0);//si que des zeros le calcul ne se fait pas
+		//if (!this.ml0) {this.ml0=0;}
+	},
+
+
+	/* Polyconic forward equations--mapping lat,long to x,y
+	  ---------------------------------------------------*/
+	forward: function(p) {
+		var sinphi, cosphi;	/* sin and cos value				*/
+		var al;				/* temporary values				*/
+		var c;				/* temporary values				*/
+		var con, ml;		/* cone constant, small m			*/
+		var ms;				/* small m					*/
+		var x,y;
+
+		var lon=p.x;
+		var lat=p.y;	
+
+		con = Proj4js.common.adjust_lon(lon - this.long0);
+		if (Math.abs(lat) <= .0000001) {
+			x = this.x0 + this.a * con;
+			y = this.y0 - this.a * this.ml0;
+		} else {
+			sinphi = Math.sin(lat);
+			cosphi = Math.cos(lat);	   
+
+			ml = Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, lat);
+			ms = Proj4js.common.msfnz(this.e,sinphi,cosphi);
+			con = sinphi;
+			x = this.x0 + this.a * ms * Math.sin(con)/sinphi;
+			y = this.y0 + this.a * (ml - this.ml0 + ms * (1.0 - Math.cos(con))/sinphi);
+		}
+
+		p.x=x;
+		p.y=y;   
+		return p;
+	},
+
+
+	/* Inverse equations
+	-----------------*/
+	inverse: function(p) {
+		var sin_phi, cos_phi;	/* sin and cos value				*/
+		var al;					/* temporary values				*/
+		var b;					/* temporary values				*/
+		var c;					/* temporary values				*/
+		var con, ml;			/* cone constant, small m			*/
+		var iflg;				/* error flag					*/
+		var lon,lat;
+		p.x -= this.x0;
+		p.y -= this.y0;
+		al = this.ml0 + p.y/this.a;
+		iflg = 0;
+
+		if (Math.abs(al) <= .0000001) {
+			lon = p.x/this.a + this.long0;
+			lat = 0.0;
+		} else {
+			b = al * al + (p.x/this.a) * (p.x/this.a);
+			iflg = phi4z(this.es,this.e0,this.e1,this.e2,this.e3,this.al,b,c,lat);
+			if (iflg != 1) return(iflg);
+			lon = Proj4js.common.adjust_lon((Proj4js.common.asinz(p.x * c / this.a) / Math.sin(lat)) + this.long0);
+		}
+
+		p.x=lon;
+		p.y=lat;
+		return p;
+	}
+};
+
+
+
+/* ======================================================================
+    projCode/equi.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                             EQUIRECTANGULAR 
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Equirectangular projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+PROGRAMMER              DATE
+----------              ----
+T. Mittan		Mar, 1993
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+    Printing Office, Washington D.C., 1989.
+*******************************************************************************/
+Proj4js.Proj.equi = {
+
+  init: function() {
+    if(!this.x0) this.x0=0;
+    if(!this.y0) this.y0=0;
+    if(!this.lat0) this.lat0=0;
+    if(!this.long0) this.long0=0;
+    ///this.t2;
+  },
+
+
+
+/* Equirectangular forward equations--mapping lat,long to x,y
+  ---------------------------------------------------------*/
+  forward: function(p) {
+
+    var lon=p.x;				
+    var lat=p.y;			
+
+    var dlon = Proj4js.common.adjust_lon(lon - this.long0);
+    var x = this.x0 +this. a * dlon *Math.cos(this.lat0);
+    var y = this.y0 + this.a * lat;
+
+    this.t1=x;
+    this.t2=Math.cos(this.lat0);
+    p.x=x;
+    p.y=y;
+    return p;
+  },  //equiFwd()
+
+
+
+/* Equirectangular inverse equations--mapping x,y to lat/long
+  ---------------------------------------------------------*/
+  inverse: function(p) {
+
+    p.x -= this.x0;
+    p.y -= this.y0;
+    var lat = p.y /this. a;
+
+    if ( Math.abs(lat) > Proj4js.common.HALF_PI) {
+        Proj4js.reportError("equi:Inv:DataError");
+    }
+    var lon = Proj4js.common.adjust_lon(this.long0 + p.x / (this.a * Math.cos(this.lat0)));
+    p.x=lon;
+    p.y=lat;
+  }//equiInv()
+};
+
+
+/* ======================================================================
+    projCode/merc.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                            MERCATOR
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Mercator projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+PROGRAMMER              DATE
+----------              ----
+D. Steinwand, EROS      Nov, 1991
+T. Mittan		Mar, 1993
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+    Printing Office, Washington D.C., 1989.
+*******************************************************************************/
+
+//static double r_major = a;		   /* major axis 				*/
+//static double r_minor = b;		   /* minor axis 				*/
+//static double lon_center = long0;	   /* Center longitude (projection center) */
+//static double lat_origin =  lat0;	   /* center latitude			*/
+//static double e,es;		           /* eccentricity constants		*/
+//static double m1;		               /* small value m			*/
+//static double false_northing = y0;   /* y offset in meters			*/
+//static double false_easting = x0;	   /* x offset in meters			*/
+//scale_fact = k0 
+
+Proj4js.Proj.merc = {
+  init : function() {
+	//?this.temp = this.r_minor / this.r_major;
+	//this.temp = this.b / this.a;
+	//this.es = 1.0 - Math.sqrt(this.temp);
+	//this.e = Math.sqrt( this.es );
+	//?this.m1 = Math.cos(this.lat_origin) / (Math.sqrt( 1.0 - this.es * Math.sin(this.lat_origin) * Math.sin(this.lat_origin)));
+	//this.m1 = Math.cos(0.0) / (Math.sqrt( 1.0 - this.es * Math.sin(0.0) * Math.sin(0.0)));
+    if (this.lat_ts) {
+      if (this.sphere) {
+        this.k0 = Math.cos(this.lat_ts);
+      } else {
+        this.k0 = Proj4js.common.msfnz(this.es, Math.sin(this.lat_ts), Math.cos(this.lat_ts));
+      }
+    }
+  },
+
+/* Mercator forward equations--mapping lat,long to x,y
+  --------------------------------------------------*/
+
+  forward : function(p) {	
+    //alert("ll2m coords : "+coords);
+    var lon = p.x;
+    var lat = p.y;
+    // convert to radians
+    if ( lat*Proj4js.common.R2D > 90.0 && 
+          lat*Proj4js.common.R2D < -90.0 && 
+          lon*Proj4js.common.R2D > 180.0 && 
+          lon*Proj4js.common.R2D < -180.0) {
+      Proj4js.reportError("merc:forward: llInputOutOfRange: "+ lon +" : " + lat);
+      return null;
+    }
+
+    var x,y;
+    if(Math.abs( Math.abs(lat) - Proj4js.common.HALF_PI)  <= Proj4js.common.EPSLN) {
+      Proj4js.reportError("merc:forward: ll2mAtPoles");
+      return null;
+    } else {
+      if (this.sphere) {
+        x = this.x0 + this.a * this.k0 * Proj4js.common.adjust_lon(lon - this.long0);
+        y = this.y0 + this.a * this.k0 * Math.log(Math.tan(Proj4js.common.FORTPI + 0.5*lat));
+      } else {
+        var sinphi = Math.sin(lat);
+        var ts = Proj4js.common.tsfnz(this.e,lat,sinphi);
+        x = this.x0 + this.a * this.k0 * Proj4js.common.adjust_lon(lon - this.long0);
+        y = this.y0 - this.a * this.k0 * Math.log(ts);
+      }
+      p.x = x; 
+      p.y = y;
+      return p;
+    }
+  },
+
+
+  /* Mercator inverse equations--mapping x,y to lat/long
+  --------------------------------------------------*/
+  inverse : function(p) {	
+
+    var x = p.x - this.x0;
+    var y = p.y - this.y0;
+    var lon,lat;
+
+    if (this.sphere) {
+      lat = Proj4js.common.HALF_PI - 2.0 * Math.atan(Math.exp(-y / this.a * this.k0));
+    } else {
+      var ts = Math.exp(-y / (this.a * this.k0));
+      lat = Proj4js.common.phi2z(this.e,ts);
+      if(lat == -9999) {
+        Proj4js.reportError("merc:inverse: lat = -9999");
+        return null;
+      }
+    }
+    lon = Proj4js.common.adjust_lon(this.long0+ x / (this.a * this.k0));
+
+    p.x = lon;
+    p.y = lat;
+    return p;
+  }
+};
+
+
+/* ======================================================================
+    projCode/utm.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                            TRANSVERSE MERCATOR
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Transverse Mercator projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+    Printing Office, Washington D.C., 1989.
+*******************************************************************************/
+
+
+/**
+  Initialize Transverse Mercator projection
+*/
+
+Proj4js.Proj.utm = {
+  dependsOn : 'tmerc',
+
+  init : function() {
+    if (!this.zone) {
+      Proj4js.reportError("utm:init: zone must be specified for UTM");
+      return;
+    }
+    this.lat0 = 0.0;
+    this.long0 = ((6 * Math.abs(this.zone)) - 183) * Proj4js.common.D2R;
+    this.x0 = 500000.0;
+    this.y0 = this.utmSouth ? 10000000.0 : 0.0;
+    this.k0 = 0.9996;
+
+    Proj4js.Proj['tmerc'].init.apply(this);
+    this.forward = Proj4js.Proj['tmerc'].forward;
+    this.inverse = Proj4js.Proj['tmerc'].inverse;
+  }
+};
+/* ======================================================================
+    projCode/eqdc.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                            EQUIDISTANT CONIC 
+
+PURPOSE:	Transforms input longitude and latitude to Easting and Northing
+		for the Equidistant Conic projection.  The longitude and
+		latitude must be in radians.  The Easting and Northing values
+		will be returned in meters.
+
+PROGRAMMER              DATE
+----------              ----
+T. Mittan		Mar, 1993
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+    Printing Office, Washington D.C., 1989.
+*******************************************************************************/
+
+/* Variables common to all subroutines in this code file
+  -----------------------------------------------------*/
+
+Proj4js.Proj.eqdc = {
+
+/* Initialize the Equidistant Conic projection
+  ------------------------------------------*/
+  init: function() {
+
+    /* Place parameters in static storage for common use
+      -------------------------------------------------*/
+
+    if(!this.mode) this.mode=0;//chosen default mode
+    this.temp = this.b / this.a;
+    this.es = 1.0 - Math.pow(this.temp,2);
+    this.e = Math.sqrt(this.es);
+    this.e0 = Proj4js.common.e0fn(this.es);
+    this.e1 = Proj4js.common.e1fn(this.es);
+    this.e2 = Proj4js.common.e2fn(this.es);
+    this.e3 = Proj4js.common.e3fn(this.es);
+
+    this.sinphi=Math.sin(this.lat1);
+    this.cosphi=Math.cos(this.lat1);
+
+    this.ms1 = Proj4js.common.msfnz(this.e,this.sinphi,this.cosphi);
+    this.ml1 = Proj4js.common.mlfn(this.e0, this.e1, this.e2,this.e3, this.lat1);
+
+    /* format B
+    ---------*/
+    if (this.mode != 0) {
+      if (Math.abs(this.lat1 + this.lat2) < Proj4js.common.EPSLN) {
+            Proj4js.reportError("eqdc:Init:EqualLatitudes");
+            //return(81);
+       }
+       this.sinphi=Math.sin(this.lat2);
+       this.cosphi=Math.cos(this.lat2);   
+
+       this.ms2 = Proj4js.common.msfnz(this.e,this.sinphi,this.cosphi);
+       this.ml2 = Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, this.lat2);
+       if (Math.abs(this.lat1 - this.lat2) >= Proj4js.common.EPSLN) {
+         this.ns = (this.ms1 - this.ms2) / (this.ml2 - this.ml1);
+       } else {
+          this.ns = this.sinphi;
+       }
+    } else {
+      this.ns = this.sinphi;
+    }
+    this.g = this.ml1 + this.ms1/this.ns;
+    this.ml0 = Proj4js.common.mlfn(this.e0, this.e1,this. e2, this.e3, this.lat0);
+    this.rh = this.a * (this.g - this.ml0);
+  },
+
+
+/* Equidistant Conic forward equations--mapping lat,long to x,y
+  -----------------------------------------------------------*/
+  forward: function(p) {
+    var lon=p.x;
+    var lat=p.y;
+
+    /* Forward equations
+      -----------------*/
+    var ml = Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, lat);
+    var rh1 = this.a * (this.g - ml);
+    var theta = this.ns * Proj4js.common.adjust_lon(lon - this.long0);
+
+    var x = this.x0  + rh1 * Math.sin(theta);
+    var y = this.y0 + this.rh - rh1 * Math.cos(theta);
+    p.x=x;
+    p.y=y;
+    return p;
+  },
+
+/* Inverse equations
+  -----------------*/
+  inverse: function(p) {
+    p.x -= this.x0;
+    p.y  = this.rh - p.y + this.y0;
+    var con, rh1;
+    if (this.ns >= 0) {
+       var rh1 = Math.sqrt(p.x *p.x + p.y * p.y); 
+       var con = 1.0;
+    } else {
+       rh1 = -Math.sqrt(p.x *p. x +p. y * p.y); 
+       con = -1.0;
+    }
+    var theta = 0.0;
+    if (rh1 != 0.0) theta = Math.atan2(con *p.x, con *p.y);
+    var ml = this.g - rh1 /this.a;
+    var lat = this.phi3z(ml,this.e0,this.e1,this.e2,this.e3);
+    var lon = Proj4js.common.adjust_lon(this.long0 + theta / this.ns);
+
+     p.x=lon;
+     p.y=lat;  
+     return p;
+    },
+    
+/* Function to compute latitude, phi3, for the inverse of the Equidistant
+   Conic projection.
+-----------------------------------------------------------------*/
+  phi3z: function(ml,e0,e1,e2,e3) {
+    var phi;
+    var dphi;
+
+    phi = ml;
+    for (var i = 0; i < 15; i++) {
+      dphi = (ml + e1 * Math.sin(2.0 * phi) - e2 * Math.sin(4.0 * phi) + e3 * Math.sin(6.0 * phi))/ e0 - phi;
+      phi += dphi;
+      if (Math.abs(dphi) <= .0000000001) {
+        return phi;
+      }
+    }
+    Proj4js.reportError("PHI3Z-CONV:Latitude failed to converge after 15 iterations");
+    return null;
+  }
+
+    
+};
+/* ======================================================================
+    projCode/tmerc.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                            TRANSVERSE MERCATOR
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Transverse Mercator projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+    Printing Office, Washington D.C., 1989.
+*******************************************************************************/
+
+
+/**
+  Initialize Transverse Mercator projection
+*/
+
+Proj4js.Proj.tmerc = {
+  init : function() {
+    this.e0 = Proj4js.common.e0fn(this.es);
+    this.e1 = Proj4js.common.e1fn(this.es);
+    this.e2 = Proj4js.common.e2fn(this.es);
+    this.e3 = Proj4js.common.e3fn(this.es);
+    this.ml0 = this.a * Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
+  },
+
+  /**
+    Transverse Mercator Forward  - long/lat to x/y
+    long/lat in radians
+  */
+  forward : function(p) {
+    var lon = p.x;
+    var lat = p.y;
+
+    var delta_lon = Proj4js.common.adjust_lon(lon - this.long0); // Delta longitude
+    var con;    // cone constant
+    var x, y;
+    var sin_phi=Math.sin(lat);
+    var cos_phi=Math.cos(lat);
+
+    if (this.sphere) {  /* spherical form */
+      var b = cos_phi * Math.sin(delta_lon);
+      if ((Math.abs(Math.abs(b) - 1.0)) < .0000000001)  {
+        Proj4js.reportError("tmerc:forward: Point projects into infinity");
+        return(93);
+      } else {
+        x = .5 * this.a * this.k0 * Math.log((1.0 + b)/(1.0 - b));
+        con = Math.acos(cos_phi * Math.cos(delta_lon)/Math.sqrt(1.0 - b*b));
+        if (lat < 0) con = - con;
+        y = this.a * this.k0 * (con - this.lat0);
+      }
+    } else {
+      var al  = cos_phi * delta_lon;
+      var als = Math.pow(al,2);
+      var c   = this.ep2 * Math.pow(cos_phi,2);
+      var tq  = Math.tan(lat);
+      var t   = Math.pow(tq,2);
+      con = 1.0 - this.es * Math.pow(sin_phi,2);
+      var n   = this.a / Math.sqrt(con);
+      var ml  = this.a * Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, lat);
+
+      x = this.k0 * n * al * (1.0 + als / 6.0 * (1.0 - t + c + als / 20.0 * (5.0 - 18.0 * t + Math.pow(t,2) + 72.0 * c - 58.0 * this.ep2))) + this.x0;
+      y = this.k0 * (ml - this.ml0 + n * tq * (als * (0.5 + als / 24.0 * (5.0 - t + 9.0 * c + 4.0 * Math.pow(c,2) + als / 30.0 * (61.0 - 58.0 * t + Math.pow(t,2) + 600.0 * c - 330.0 * this.ep2))))) + this.y0;
+
+    }
+    p.x = x; p.y = y;
+    return p;
+  }, // tmercFwd()
+
+  /**
+    Transverse Mercator Inverse  -  x/y to long/lat
+  */
+  inverse : function(p) {
+    var con, phi;  /* temporary angles       */
+    var delta_phi; /* difference between longitudes    */
+    var i;
+    var max_iter = 6;      /* maximun number of iterations */
+    var lat, lon;
+
+    if (this.sphere) {   /* spherical form */
+      var f = Math.exp(p.x/(this.a * this.k0));
+      var g = .5 * (f - 1/f);
+      var temp = this.lat0 + p.y/(this.a * this.k0);
+      var h = Math.cos(temp);
+      con = Math.sqrt((1.0 - h * h)/(1.0 + g * g));
+      lat = Proj4js.common.asinz(con);
+      if (temp < 0)
+        lat = -lat;
+      if ((g == 0) && (h == 0)) {
+        lon = this.long0;
+      } else {
+        lon = Proj4js.common.adjust_lon(Math.atan2(g,h) + this.long0);
+      }
+    } else {    // ellipsoidal form
+      var x = p.x - this.x0;
+      var y = p.y - this.y0;
+
+      con = (this.ml0 + y / this.k0) / this.a;
+      phi = con;
+      for (i=0;true;i++) {
+        delta_phi=((con + this.e1 * Math.sin(2.0*phi) - this.e2 * Math.sin(4.0*phi) + this.e3 * Math.sin(6.0*phi)) / this.e0) - phi;
+        phi += delta_phi;
+        if (Math.abs(delta_phi) <= Proj4js.common.EPSLN) break;
+        if (i >= max_iter) {
+          Proj4js.reportError("tmerc:inverse: Latitude failed to converge");
+          return(95);
+        }
+      } // for()
+      if (Math.abs(phi) < Proj4js.common.HALF_PI) {
+        // sincos(phi, &sin_phi, &cos_phi);
+        var sin_phi=Math.sin(phi);
+        var cos_phi=Math.cos(phi);
+        var tan_phi = Math.tan(phi);
+        var c = this.ep2 * Math.pow(cos_phi,2);
+        var cs = Math.pow(c,2);
+        var t = Math.pow(tan_phi,2);
+        var ts = Math.pow(t,2);
+        con = 1.0 - this.es * Math.pow(sin_phi,2);
+        var n = this.a / Math.sqrt(con);
+        var r = n * (1.0 - this.es) / con;
+        var d = x / (n * this.k0);
+        var ds = Math.pow(d,2);
+        lat = phi - (n * tan_phi * ds / r) * (0.5 - ds / 24.0 * (5.0 + 3.0 * t + 10.0 * c - 4.0 * cs - 9.0 * this.ep2 - ds / 30.0 * (61.0 + 90.0 * t + 298.0 * c + 45.0 * ts - 252.0 * this.ep2 - 3.0 * cs)));
+        lon = Proj4js.common.adjust_lon(this.long0 + (d * (1.0 - ds / 6.0 * (1.0 + 2.0 * t + c - ds / 20.0 * (5.0 - 2.0 * c + 28.0 * t - 3.0 * cs + 8.0 * this.ep2 + 24.0 * ts))) / cos_phi));
+      } else {
+        lat = Proj4js.common.HALF_PI * Proj4js.common.sign(y);
+        lon = this.long0;
+      }
+    }
+    p.x = lon;
+    p.y = lat;
+    return p;
+  } // tmercInv()
+};
+/* ======================================================================
+    defs/GOOGLE.js
+   ====================================================================== */
+
+Proj4js.defs["GOOGLE"]="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs";
+Proj4js.defs["EPSG:900913"]=Proj4js.defs["GOOGLE"];
+/* ======================================================================
+    projCode/gstmerc.js
+   ====================================================================== */
+
+Proj4js.Proj.gstmerc = {
+  init : function() {
+
+    // array of:  a, b, lon0, lat0, k0, x0, y0
+      var temp= this.b / this.a;
+      this.e= Math.sqrt(1.0 - temp*temp);
+      this.lc= this.long0;
+      this.rs= Math.sqrt(1.0+this.e*this.e*Math.pow(Math.cos(this.lat0),4.0)/(1.0-this.e*this.e));
+      var sinz= Math.sin(this.lat0);
+      var pc= Math.asin(sinz/this.rs);
+      var sinzpc= Math.sin(pc);
+      this.cp= Proj4js.common.latiso(0.0,pc,sinzpc)-this.rs*Proj4js.common.latiso(this.e,this.lat0,sinz);
+      this.n2= this.k0*this.a*Math.sqrt(1.0-this.e*this.e)/(1.0-this.e*this.e*sinz*sinz);
+      this.xs= this.x0;
+      this.ys= this.y0-this.n2*pc;
+
+      if (!this.title) this.title = "Gauss Schreiber transverse mercator";
+    },
+
+
+    // forward equations--mapping lat,long to x,y
+    // -----------------------------------------------------------------
+    forward : function(p) {
+
+      var lon= p.x;
+      var lat= p.y;
+
+      var L= this.rs*(lon-this.lc);
+      var Ls= this.cp+(this.rs*Proj4js.common.latiso(this.e,lat,Math.sin(lat)));
+      var lat1= Math.asin(Math.sin(L)/Proj4js.common.cosh(Ls));
+      var Ls1= Proj4js.common.latiso(0.0,lat1,Math.sin(lat1));
+      p.x= this.xs+(this.n2*Ls1);
+      p.y= this.ys+(this.n2*Math.atan(Proj4js.common.sinh(Ls)/Math.cos(L)));
+      return p;
+    },
+
+  // inverse equations--mapping x,y to lat/long
+  // -----------------------------------------------------------------
+  inverse : function(p) {
+
+    var x= p.x;
+    var y= p.y;
+
+    var L= Math.atan(Proj4js.common.sinh((x-this.xs)/this.n2)/Math.cos((y-this.ys)/this.n2));
+    var lat1= Math.asin(Math.sin((y-this.ys)/this.n2)/Proj4js.common.cosh((x-this.xs)/this.n2));
+    var LC= Proj4js.common.latiso(0.0,lat1,Math.sin(lat1));
+    p.x= this.lc+L/this.rs;
+    p.y= Proj4js.common.invlatiso(this.e,(LC-this.cp)/this.rs);
+    return p;
+  }
+
+};
+/* ======================================================================
+    projCode/ortho.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                             ORTHOGRAPHIC 
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Orthographic projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+PROGRAMMER              DATE
+----------              ----
+T. Mittan		Mar, 1993
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+    Printing Office, Washington D.C., 1989.
+*******************************************************************************/
+
+Proj4js.Proj.ortho = {
+
+  /* Initialize the Orthographic projection
+    -------------------------------------*/
+  init: function(def) {
+    //double temp;			/* temporary variable		*/
+
+    /* Place parameters in static storage for common use
+      -------------------------------------------------*/;
+    this.sin_p14=Math.sin(this.lat0);
+    this.cos_p14=Math.cos(this.lat0);	
+  },
+
+
+  /* Orthographic forward equations--mapping lat,long to x,y
+    ---------------------------------------------------*/
+  forward: function(p) {
+    var sinphi, cosphi;	/* sin and cos value				*/
+    var dlon;		/* delta longitude value			*/
+    var coslon;		/* cos of longitude				*/
+    var ksp;		/* scale factor					*/
+    var g;		
+    var lon=p.x;
+    var lat=p.y;	
+    /* Forward equations
+      -----------------*/
+    dlon = Proj4js.common.adjust_lon(lon - this.long0);
+
+    sinphi=Math.sin(lat);
+    cosphi=Math.cos(lat);	
+
+    coslon = Math.cos(dlon);
+    g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
+    ksp = 1.0;
+    if ((g > 0) || (Math.abs(g) <= Proj4js.common.EPSLN)) {
+      var x = this.a * ksp * cosphi * Math.sin(dlon);
+      var y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);
+    } else {
+      Proj4js.reportError("orthoFwdPointError");
+    }
+    p.x=x;
+    p.y=y;
+    return p;
+  },
+
+
+  inverse: function(p) {
+    var rh;		/* height above ellipsoid			*/
+    var z;		/* angle					*/
+    var sinz,cosz;	/* sin of z and cos of z			*/
+    var temp;
+    var con;
+    var lon , lat;
+    /* Inverse equations
+      -----------------*/
+    p.x -= this.x0;
+    p.y -= this.y0;
+    rh = Math.sqrt(p.x * p.x + p.y * p.y);
+    if (rh > this.a + .0000001) {
+      Proj4js.reportError("orthoInvDataError");
+    }
+    z = Proj4js.common.asinz(rh / this.a);
+
+    sinz=Math.sin(z);
+    cosz=Math.cos(z);
+
+    lon = this.long0;
+    if (Math.abs(rh) <= Proj4js.common.EPSLN) {
+      lat = this.lat0; 
+    }
+    lat = Proj4js.common.asinz(cosz * this.sin_p14 + (p.y * sinz * this.cos_p14)/rh);
+    con = Math.abs(this.lat0) - Proj4js.common.HALF_PI;
+    if (Math.abs(con) <= Proj4js.common.EPSLN) {
+       if (this.lat0 >= 0) {
+          lon = Proj4js.common.adjust_lon(this.long0 + Math.atan2(p.x, -p.y));
+       } else {
+          lon = Proj4js.common.adjust_lon(this.long0 -Math.atan2(-p.x, p.y));
+       }
+    }
+    con = cosz - this.sin_p14 * Math.sin(lat);
+    p.x=lon;
+    p.y=lat;
+    return p;
+  }
+};
+
+
+/* ======================================================================
+    projCode/somerc.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                       SWISS OBLIQUE MERCATOR
+
+PURPOSE:	Swiss projection.
+WARNING:  X and Y are inverted (weird) in the swiss coordinate system. Not
+   here, since we want X to be horizontal and Y vertical.
+
+ALGORITHM REFERENCES
+1. "Formules et constantes pour le Calcul pour la
+ projection cylindrique conforme à axe oblique et pour la transformation entre
+ des systèmes de référence".
+ http://www.swisstopo.admin.ch/internet/swisstopo/fr/home/topics/survey/sys/refsys/switzerland.parsysrelated1.31216.downloadList.77004.DownloadFile.tmp/swissprojectionfr.pdf
+
+*******************************************************************************/
+
+Proj4js.Proj.somerc = {
+
+  init: function() {
+    var phy0 = this.lat0;
+    this.lambda0 = this.long0;
+    var sinPhy0 = Math.sin(phy0);
+    var semiMajorAxis = this.a;
+    var invF = this.rf;
+    var flattening = 1 / invF;
+    var e2 = 2 * flattening - Math.pow(flattening, 2);
+    var e = this.e = Math.sqrt(e2);
+    this.R = this.k0 * semiMajorAxis * Math.sqrt(1 - e2) / (1 - e2 * Math.pow(sinPhy0, 2.0));
+    this.alpha = Math.sqrt(1 + e2 / (1 - e2) * Math.pow(Math.cos(phy0), 4.0));
+    this.b0 = Math.asin(sinPhy0 / this.alpha);
+    this.K = Math.log(Math.tan(Math.PI / 4.0 + this.b0 / 2.0))
+            - this.alpha
+            * Math.log(Math.tan(Math.PI / 4.0 + phy0 / 2.0))
+            + this.alpha
+            * e / 2
+            * Math.log((1 + e * sinPhy0)
+            / (1 - e * sinPhy0));
+  },
+
+
+  forward: function(p) {
+    var Sa1 = Math.log(Math.tan(Math.PI / 4.0 - p.y / 2.0));
+    var Sa2 = this.e / 2.0
+            * Math.log((1 + this.e * Math.sin(p.y))
+            / (1 - this.e * Math.sin(p.y)));
+    var S = -this.alpha * (Sa1 + Sa2) + this.K;
+
+        // spheric latitude
+    var b = 2.0 * (Math.atan(Math.exp(S)) - Math.PI / 4.0);
+
+        // spheric longitude
+    var I = this.alpha * (p.x - this.lambda0);
+
+        // psoeudo equatorial rotation
+    var rotI = Math.atan(Math.sin(I)
+            / (Math.sin(this.b0) * Math.tan(b) +
+               Math.cos(this.b0) * Math.cos(I)));
+
+    var rotB = Math.asin(Math.cos(this.b0) * Math.sin(b) -
+                         Math.sin(this.b0) * Math.cos(b) * Math.cos(I));
+
+    p.y = this.R / 2.0
+            * Math.log((1 + Math.sin(rotB)) / (1 - Math.sin(rotB)))
+            + this.y0;
+    p.x = this.R * rotI + this.x0;
+    return p;
+  },
+
+  inverse: function(p) {
+    var Y = p.x - this.x0;
+    var X = p.y - this.y0;
+
+    var rotI = Y / this.R;
+    var rotB = 2 * (Math.atan(Math.exp(X / this.R)) - Math.PI / 4.0);
+
+    var b = Math.asin(Math.cos(this.b0) * Math.sin(rotB)
+            + Math.sin(this.b0) * Math.cos(rotB) * Math.cos(rotI));
+    var I = Math.atan(Math.sin(rotI)
+            / (Math.cos(this.b0) * Math.cos(rotI) - Math.sin(this.b0)
+            * Math.tan(rotB)));
+
+    var lambda = this.lambda0 + I / this.alpha;
+
+    var S = 0.0;
+    var phy = b;
+    var prevPhy = -1000.0;
+    var iteration = 0;
+    while (Math.abs(phy - prevPhy) > 0.0000001)
+    {
+      if (++iteration > 20)
+      {
+        Proj4js.reportError("omercFwdInfinity");
+        return;
+      }
+      //S = Math.log(Math.tan(Math.PI / 4.0 + phy / 2.0));
+      S = 1.0
+              / this.alpha
+              * (Math.log(Math.tan(Math.PI / 4.0 + b / 2.0)) - this.K)
+              + this.e
+              * Math.log(Math.tan(Math.PI / 4.0
+              + Math.asin(this.e * Math.sin(phy))
+              / 2.0));
+      prevPhy = phy;
+      phy = 2.0 * Math.atan(Math.exp(S)) - Math.PI / 2.0;
+    }
+
+    p.x = lambda;
+    p.y = phy;
+    return p;
+  }
+};
+/* ======================================================================
+    projCode/stere.js
+   ====================================================================== */
+
+
+// Initialize the Stereographic projection
+
+Proj4js.Proj.stere = {
+  ssfn_: function(phit, sinphi, eccen) {
+  	sinphi *= eccen;
+  	return (Math.tan (.5 * (Proj4js.common.HALF_PI + phit)) * Math.pow((1. - sinphi) / (1. + sinphi), .5 * eccen));
+  },
+  TOL:	1.e-8,
+  NITER:	8,
+  CONV:	1.e-10,
+  S_POLE:	0,
+  N_POLE:	1,
+  OBLIQ:	2,
+  EQUIT:	3,
+
+  init : function() {
+  	this.phits = this.lat_ts ? this.lat_ts : Proj4js.common.HALF_PI;
+    var t = Math.abs(this.lat0);
+  	if ((Math.abs(t) - Proj4js.common.HALF_PI) < Proj4js.common.EPSLN) {
+  		this.mode = this.lat0 < 0. ? this.S_POLE : this.N_POLE;
+  	} else {
+  		this.mode = t > Proj4js.common.EPSLN ? this.OBLIQ : this.EQUIT;
+    }
+  	this.phits = Math.abs(this.phits);
+  	if (this.es) {
+  		var X;
+
+  		switch (this.mode) {
+  		case this.N_POLE:
+  		case this.S_POLE:
+  			if (Math.abs(this.phits - Proj4js.common.HALF_PI) < Proj4js.common.EPSLN) {
+  				this.akm1 = 2. * this.k0 / Math.sqrt(Math.pow(1+this.e,1+this.e)*Math.pow(1-this.e,1-this.e));
+  			} else {
+          t = Math.sin(this.phits);
+  				this.akm1 = Math.cos(this.phits) / Proj4js.common.tsfnz(this.e, this.phits, t);
+  				t *= this.e;
+  				this.akm1 /= Math.sqrt(1. - t * t);
+  			}
+  			break;
+  		case this.EQUIT:
+  			this.akm1 = 2. * this.k0;
+  			break;
+  		case this.OBLIQ:
+  			t = Math.sin(this.lat0);
+  			X = 2. * Math.atan(this.ssfn_(this.lat0, t, this.e)) - Proj4js.common.HALF_PI;
+  			t *= this.e;
+  			this.akm1 = 2. * this.k0 * Math.cos(this.lat0) / Math.sqrt(1. - t * t);
+  			this.sinX1 = Math.sin(X);
+  			this.cosX1 = Math.cos(X);
+  			break;
+  		}
+  	} else {
+  		switch (this.mode) {
+  		case this.OBLIQ:
+  			this.sinph0 = Math.sin(this.lat0);
+  			this.cosph0 = Math.cos(this.lat0);
+  		case this.EQUIT:
+  			this.akm1 = 2. * this.k0;
+  			break;
+  		case this.S_POLE:
+  		case this.N_POLE:
+  			this.akm1 = Math.abs(this.phits - Proj4js.common.HALF_PI) >= Proj4js.common.EPSLN ?
+  			   Math.cos(this.phits) / Math.tan(Proj4js.common.FORTPI - .5 * this.phits) :
+  			   2. * this.k0 ;
+  			break;
+  		}
+  	}
+  }, 
+
+// Stereographic forward equations--mapping lat,long to x,y
+  forward: function(p) {
+    var lon = p.x;
+    lon = Proj4js.common.adjust_lon(lon - this.long0);
+    var lat = p.y;
+    var x, y;
+    
+    if (this.sphere) {
+    	var  sinphi, cosphi, coslam, sinlam;
+
+    	sinphi = Math.sin(lat);
+    	cosphi = Math.cos(lat);
+    	coslam = Math.cos(lon);
+    	sinlam = Math.sin(lon);
+    	switch (this.mode) {
+    	case this.EQUIT:
+    		y = 1. + cosphi * coslam;
+    		if (y <= Proj4js.common.EPSLN) {
+          F_ERROR;
+        }
+        y = this.akm1 / y;
+    		x = y * cosphi * sinlam;
+        y *= sinphi;
+    		break;
+    	case this.OBLIQ:
+    		y = 1. + this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
+    		if (y <= Proj4js.common.EPSLN) {
+          F_ERROR;
+        }
+        y = this.akm1 / y;
+    		x = y * cosphi * sinlam;
+    		y *= this.cosph0 * sinphi - this.sinph0 * cosphi * coslam;
+    		break;
+    	case this.N_POLE:
+    		coslam = -coslam;
+    		lat = -lat;
+        //Note  no break here so it conitnues through S_POLE
+    	case this.S_POLE:
+    		if (Math.abs(lat - Proj4js.common.HALF_PI) < this.TOL) {
+          F_ERROR;
+        }
+        y = this.akm1 * Math.tan(Proj4js.common.FORTPI + .5 * lat);
+    		x = sinlam * y;
+    		y *= coslam;
+    		break;
+    	}
+    } else {
+    	coslam = Math.cos(lon);
+    	sinlam = Math.sin(lon);
+    	sinphi = Math.sin(lat);
+    	if (this.mode == this.OBLIQ || this.mode == this.EQUIT) {
+        X = 2. * Math.atan(this.ssfn_(lat, sinphi, this.e));
+    		sinX = Math.sin(X - Proj4js.common.HALF_PI);
+    		cosX = Math.cos(X);
+    	}
+    	switch (this.mode) {
+    	case this.OBLIQ:
+    		A = this.akm1 / (this.cosX1 * (1. + this.sinX1 * sinX + this.cosX1 * cosX * coslam));
+    		y = A * (this.cosX1 * sinX - this.sinX1 * cosX * coslam);
+    		x = A * cosX;
+    		break;
+    	case this.EQUIT:
+    		A = 2. * this.akm1 / (1. + cosX * coslam);
+    		y = A * sinX;
+    		x = A * cosX;
+    		break;
+    	case this.S_POLE:
+    		lat = -lat;
+    		coslam = - coslam;
+    		sinphi = -sinphi;
+    	case this.N_POLE:
+    		x = this.akm1 * Proj4js.common.tsfnz(this.e, lat, sinphi);
+    		y = - x * coslam;
+    		break;
+    	}
+    	x = x * sinlam;
+    }
+    p.x = x*this.a + this.x0;
+    p.y = y*this.a + this.y0;
+    return p;
+  },
+
+
+//* Stereographic inverse equations--mapping x,y to lat/long
+  inverse: function(p) {
+    var x = (p.x - this.x0)/this.a;   /* descale and de-offset */
+    var y = (p.y - this.y0)/this.a;
+    var lon, lat;
+
+    var cosphi, sinphi, tp=0.0, phi_l=0.0, rho, halfe=0.0, pi2=0.0;
+    var i;
+
+    if (this.sphere) {
+    	var  c, rh, sinc, cosc;
+
+      rh = Math.sqrt(x*x + y*y);
+      c = 2. * Math.atan(rh / this.akm1);
+    	sinc = Math.sin(c);
+    	cosc = Math.cos(c);
+    	lon = 0.;
+    	switch (this.mode) {
+    	case this.EQUIT:
+    		if (Math.abs(rh) <= Proj4js.common.EPSLN) {
+    			lat = 0.;
+    		} else {
+    			lat = Math.asin(y * sinc / rh);
+        }
+    		if (cosc != 0. || x != 0.) lon = Math.atan2(x * sinc, cosc * rh);
+    		break;
+    	case this.OBLIQ:
+    		if (Math.abs(rh) <= Proj4js.common.EPSLN) {
+    			lat = this.phi0;
+    		} else {
+    			lat = Math.asin(cosc * sinph0 + y * sinc * cosph0 / rh);
+        }
+        c = cosc - sinph0 * Math.sin(lat);
+    		if (c != 0. || x != 0.) {
+    			lon = Math.atan2(x * sinc * cosph0, c * rh);
+        }
+    		break;
+    	case this.N_POLE:
+    		y = -y;
+    	case this.S_POLE:
+    		if (Math.abs(rh) <= Proj4js.common.EPSLN) {
+    			lat = this.phi0;
+    		} else {
+    			lat = Math.asin(this.mode == this.S_POLE ? -cosc : cosc);
+        }
+    		lon = (x == 0. && y == 0.) ? 0. : Math.atan2(x, y);
+    		break;
+    	}
+    } else {
+    	rho = Math.sqrt(x*x + y*y);
+    	switch (this.mode) {
+    	case this.OBLIQ:
+    	case this.EQUIT:
+        tp = 2. * Math.atan2(rho * this.cosX1 , this.akm1);
+    		cosphi = Math.cos(tp);
+    		sinphi = Math.sin(tp);
+        if( rho == 0.0 ) {
+    		  phi_l = Math.asin(cosphi * this.sinX1);
+        } else {
+    		  phi_l = Math.asin(cosphi * this.sinX1 + (y * sinphi * this.cosX1 / rho));
+        }
+
+    		tp = Math.tan(.5 * (Proj4js.common.HALF_PI + phi_l));
+    		x *= sinphi;
+    		y = rho * this.cosX1 * cosphi - y * this.sinX1* sinphi;
+    		pi2 = Proj4js.common.HALF_PI;
+    		halfe = .5 * this.e;
+    		break;
+    	case this.N_POLE:
+    		y = -y;
+    	case this.S_POLE:
+        tp = - rho / this.akm1;
+    		phi_l = Proj4js.common.HALF_PI - 2. * Math.atan(tp);
+    		pi2 = -Proj4js.common.HALF_PI;
+    		halfe = -.5 * this.e;
+    		break;
+    	}
+    	for (i = this.NITER; i--; phi_l = lat) { //check this
+    		sinphi = this.e * Math.sin(phi_l);
+    		lat = 2. * Math.atan(tp * Math.pow((1.+sinphi)/(1.-sinphi), halfe)) - pi2;
+    		if (Math.abs(phi_l - lat) < this.CONV) {
+    			if (this.mode == this.S_POLE) lat = -lat;
+    			lon = (x == 0. && y == 0.) ? 0. : Math.atan2(x, y);
+          p.x = Proj4js.common.adjust_lon(lon + this.long0);
+          p.y = lat;
+    			return p;
+    		}
+    	}
+    }
+  }
+}; 
+/* ======================================================================
+    projCode/nzmg.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                            NEW ZEALAND MAP GRID
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the New Zealand Map Grid projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+
+ALGORITHM REFERENCES
+
+1.  Department of Land and Survey Technical Circular 1973/32
+      http://www.linz.govt.nz/docs/miscellaneous/nz-map-definition.pdf
+
+2.  OSG Technical Report 4.1
+      http://www.linz.govt.nz/docs/miscellaneous/nzmg.pdf
+
+
+IMPLEMENTATION NOTES
+
+The two references use different symbols for the calculated values. This
+implementation uses the variable names similar to the symbols in reference [1].
+
+The alogrithm uses different units for delta latitude and delta longitude.
+The delta latitude is assumed to be in units of seconds of arc x 10^-5.
+The delta longitude is the usual radians. Look out for these conversions.
+
+The algorithm is described using complex arithmetic. There were three
+options:
+   * find and use a Javascript library for complex arithmetic
+   * write my own complex library
+   * expand the complex arithmetic by hand to simple arithmetic
+
+This implementation has expanded the complex multiplication operations
+into parallel simple arithmetic operations for the real and imaginary parts.
+The imaginary part is way over to the right of the display; this probably
+violates every coding standard in the world, but, to me, it makes it much
+more obvious what is going on.
+
+The following complex operations are used:
+   - addition
+   - multiplication
+   - division
+   - complex number raised to integer power
+   - summation
+
+A summary of complex arithmetic operations:
+   (from http://en.wikipedia.org/wiki/Complex_arithmetic)
+   addition:       (a + bi) + (c + di) = (a + c) + (b + d)i
+   subtraction:    (a + bi) - (c + di) = (a - c) + (b - d)i
+   multiplication: (a + bi) x (c + di) = (ac - bd) + (bc + ad)i
+   division:       (a + bi) / (c + di) = [(ac + bd)/(cc + dd)] + [(bc - ad)/(cc + dd)]i
+
+The algorithm needs to calculate summations of simple and complex numbers. This is
+implemented using a for-loop, pre-loading the summed value to zero.
+
+The algorithm needs to calculate theta^2, theta^3, etc while doing a summation.
+There are three possible implementations:
+   - use Math.pow in the summation loop - except for complex numbers
+   - precalculate the values before running the loop
+   - calculate theta^n = theta^(n-1) * theta during the loop
+This implementation uses the third option for both real and complex arithmetic.
+
+For example
+   psi_n = 1;
+   sum = 0;
+   for (n = 1; n <=6; n++) {
+      psi_n1 = psi_n * psi;       // calculate psi^(n+1)
+      psi_n = psi_n1;
+      sum = sum + A[n] * psi_n;
+   }
+
+
+TEST VECTORS
+
+NZMG E, N:         2487100.638      6751049.719     metres
+NZGD49 long, lat:      172.739194       -34.444066  degrees
+
+NZMG E, N:         2486533.395      6077263.661     metres
+NZGD49 long, lat:      172.723106       -40.512409  degrees
+
+NZMG E, N:         2216746.425      5388508.765     metres
+NZGD49 long, lat:      169.172062       -46.651295  degrees
+
+Note that these test vectors convert from NZMG metres to lat/long referenced
+to NZGD49, not the more usual WGS84. The difference is about 70m N/S and about
+10m E/W.
+
+These test vectors are provided in reference [1]. Many more test
+vectors are available in
+   http://www.linz.govt.nz/docs/topography/topographicdata/placenamesdatabase/nznamesmar08.zip
+which is a catalog of names on the 260-series maps.
+
+
+EPSG CODES
+
+NZMG     EPSG:27200
+NZGD49   EPSG:4272
+
+http://spatialreference.org/ defines these as
+  Proj4js.defs["EPSG:4272"] = "+proj=longlat +ellps=intl +datum=nzgd49 +no_defs ";
+  Proj4js.defs["EPSG:27200"] = "+proj=nzmg +lat_0=-41 +lon_0=173 +x_0=2510000 +y_0=6023150 +ellps=intl +datum=nzgd49 +units=m +no_defs ";
+
+
+LICENSE
+  Copyright: Stephen Irons 2008
+  Released under terms of the LGPL as per: http://www.gnu.org/copyleft/lesser.html
+
+*******************************************************************************/
+
+
+/**
+  Initialize New Zealand Map Grip projection
+*/
+
+Proj4js.Proj.nzmg = {
+
+  /**
+   * iterations: Number of iterations to refine inverse transform.
+   *     0 -> km accuracy
+   *     1 -> m accuracy -- suitable for most mapping applications
+   *     2 -> mm accuracy
+   */
+  iterations: 1,
+
+  init : function() {
+    this.A = new Array();
+    this.A[1]  = +0.6399175073;
+    this.A[2]  = -0.1358797613;
+    this.A[3]  = +0.063294409;
+    this.A[4]  = -0.02526853;
+    this.A[5]  = +0.0117879;
+    this.A[6]  = -0.0055161;
+    this.A[7]  = +0.0026906;
+    this.A[8]  = -0.001333;
+    this.A[9]  = +0.00067;
+    this.A[10] = -0.00034;
+
+    this.B_re = new Array();        this.B_im = new Array();
+    this.B_re[1] = +0.7557853228;   this.B_im[1] =  0.0;
+    this.B_re[2] = +0.249204646;    this.B_im[2] = +0.003371507;
+    this.B_re[3] = -0.001541739;    this.B_im[3] = +0.041058560;
+    this.B_re[4] = -0.10162907;     this.B_im[4] = +0.01727609;
+    this.B_re[5] = -0.26623489;     this.B_im[5] = -0.36249218;
+    this.B_re[6] = -0.6870983;      this.B_im[6] = -1.1651967;
+
+    this.C_re = new Array();        this.C_im = new Array();
+    this.C_re[1] = +1.3231270439;   this.C_im[1] =  0.0;
+    this.C_re[2] = -0.577245789;    this.C_im[2] = -0.007809598;
+    this.C_re[3] = +0.508307513;    this.C_im[3] = -0.112208952;
+    this.C_re[4] = -0.15094762;     this.C_im[4] = +0.18200602;
+    this.C_re[5] = +1.01418179;     this.C_im[5] = +1.64497696;
+    this.C_re[6] = +1.9660549;      this.C_im[6] = +2.5127645;
+
+    this.D = new Array();
+    this.D[1] = +1.5627014243;
+    this.D[2] = +0.5185406398;
+    this.D[3] = -0.03333098;
+    this.D[4] = -0.1052906;
+    this.D[5] = -0.0368594;
+    this.D[6] = +0.007317;
+    this.D[7] = +0.01220;
+    this.D[8] = +0.00394;
+    this.D[9] = -0.0013;
+  },
+
+  /**
+    New Zealand Map Grid Forward  - long/lat to x/y
+    long/lat in radians
+  */
+  forward : function(p) {
+    var lon = p.x;
+    var lat = p.y;
+
+    var delta_lat = lat - this.lat0;
+    var delta_lon = lon - this.long0;
+
+    // 1. Calculate d_phi and d_psi    ...                          // and d_lambda
+    // For this algorithm, delta_latitude is in seconds of arc x 10-5, so we need to scale to those units. Longitude is radians.
+    var d_phi = delta_lat / Proj4js.common.SEC_TO_RAD * 1E-5;       var d_lambda = delta_lon;
+    var d_phi_n = 1;  // d_phi^0
+
+    var d_psi = 0;
+    for (n = 1; n <= 10; n++) {
+      d_phi_n = d_phi_n * d_phi;
+      d_psi = d_psi + this.A[n] * d_phi_n;
+    }
+
+    // 2. Calculate theta
+    var th_re = d_psi;                                              var th_im = d_lambda;
+
+    // 3. Calculate z
+    var th_n_re = 1;                                                var th_n_im = 0;  // theta^0
+    var th_n_re1;                                                   var th_n_im1;
+
+    var z_re = 0;                                                   var z_im = 0;
+    for (n = 1; n <= 6; n++) {
+      th_n_re1 = th_n_re*th_re - th_n_im*th_im;                     th_n_im1 = th_n_im*th_re + th_n_re*th_im;
+      th_n_re = th_n_re1;                                           th_n_im = th_n_im1;
+      z_re = z_re + this.B_re[n]*th_n_re - this.B_im[n]*th_n_im;    z_im = z_im + this.B_im[n]*th_n_re + this.B_re[n]*th_n_im;
+    }
+
+    // 4. Calculate easting and northing
+    x = (z_im * this.a) + this.x0;
+    y = (z_re * this.a) + this.y0;
+
+    p.x = x; p.y = y;
+
+    return p;
+  },
+
+
+  /**
+    New Zealand Map Grid Inverse  -  x/y to long/lat
+  */
+  inverse : function(p) {
+
+    var x = p.x;
+    var y = p.y;
+
+    var delta_x = x - this.x0;
+    var delta_y = y - this.y0;
+
+    // 1. Calculate z
+    var z_re = delta_y / this.a;                                              var z_im = delta_x / this.a;
+
+    // 2a. Calculate theta - first approximation gives km accuracy
+    var z_n_re = 1;                                                           var z_n_im = 0;  // z^0
+    var z_n_re1;                                                              var z_n_im1;
+
+    var th_re = 0;                                                            var th_im = 0;
+    for (n = 1; n <= 6; n++) {
+      z_n_re1 = z_n_re*z_re - z_n_im*z_im;                                    z_n_im1 = z_n_im*z_re + z_n_re*z_im;
+      z_n_re = z_n_re1;                                                       z_n_im = z_n_im1;
+      th_re = th_re + this.C_re[n]*z_n_re - this.C_im[n]*z_n_im;              th_im = th_im + this.C_im[n]*z_n_re + this.C_re[n]*z_n_im;
+    }
+
+    // 2b. Iterate to refine the accuracy of the calculation
+    //        0 iterations gives km accuracy
+    //        1 iteration gives m accuracy -- good enough for most mapping applications
+    //        2 iterations bives mm accuracy
+    for (i = 0; i < this.iterations; i++) {
+       var th_n_re = th_re;                                                      var th_n_im = th_im;
+       var th_n_re1;                                                             var th_n_im1;
+
+       var num_re = z_re;                                                        var num_im = z_im;
+       for (n = 2; n <= 6; n++) {
+         th_n_re1 = th_n_re*th_re - th_n_im*th_im;                               th_n_im1 = th_n_im*th_re + th_n_re*th_im;
+         th_n_re = th_n_re1;                                                     th_n_im = th_n_im1;
+         num_re = num_re + (n-1)*(this.B_re[n]*th_n_re - this.B_im[n]*th_n_im);  num_im = num_im + (n-1)*(this.B_im[n]*th_n_re + this.B_re[n]*th_n_im);
+       }
+
+       th_n_re = 1;                                                              th_n_im = 0;
+       var den_re = this.B_re[1];                                                var den_im = this.B_im[1];
+       for (n = 2; n <= 6; n++) {
+         th_n_re1 = th_n_re*th_re - th_n_im*th_im;                               th_n_im1 = th_n_im*th_re + th_n_re*th_im;
+         th_n_re = th_n_re1;                                                     th_n_im = th_n_im1;
+         den_re = den_re + n * (this.B_re[n]*th_n_re - this.B_im[n]*th_n_im);    den_im = den_im + n * (this.B_im[n]*th_n_re + this.B_re[n]*th_n_im);
+       }
+
+       // Complex division
+       var den2 = den_re*den_re + den_im*den_im;
+       th_re = (num_re*den_re + num_im*den_im) / den2;                           th_im = (num_im*den_re - num_re*den_im) / den2;
+    }
+
+    // 3. Calculate d_phi              ...                                    // and d_lambda
+    var d_psi = th_re;                                                        var d_lambda = th_im;
+    var d_psi_n = 1;  // d_psi^0
+
+    var d_phi = 0;
+    for (n = 1; n <= 9; n++) {
+       d_psi_n = d_psi_n * d_psi;
+       d_phi = d_phi + this.D[n] * d_psi_n;
+    }
+
+    // 4. Calculate latitude and longitude
+    // d_phi is calcuated in second of arc * 10^-5, so we need to scale back to radians. d_lambda is in radians.
+    var lat = this.lat0 + (d_phi * Proj4js.common.SEC_TO_RAD * 1E5);
+    var lon = this.long0 +  d_lambda;
+
+    p.x = lon;
+    p.y = lat;
+
+    return p;
+  }
+};
+/* ======================================================================
+    projCode/mill.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                    MILLER CYLINDRICAL 
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Miller Cylindrical projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+PROGRAMMER              DATE            
+----------              ----           
+T. Mittan		March, 1993
+
+This function was adapted from the Lambert Azimuthal Equal Area projection
+code (FORTRAN) in the General Cartographic Transformation Package software
+which is available from the U.S. Geological Survey National Mapping Division.
+ 
+ALGORITHM REFERENCES
+
+1.  "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
+    The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
+
+2.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+3.  "Software Documentation for GCTP General Cartographic Transformation
+    Package", U.S. Geological Survey National Mapping Division, May 1982.
+*******************************************************************************/
+
+Proj4js.Proj.mill = {
+
+/* Initialize the Miller Cylindrical projection
+  -------------------------------------------*/
+  init: function() {
+    //no-op
+  },
+
+
+  /* Miller Cylindrical forward equations--mapping lat,long to x,y
+    ------------------------------------------------------------*/
+  forward: function(p) {
+    var lon=p.x;
+    var lat=p.y;
+    /* Forward equations
+      -----------------*/
+    var dlon = Proj4js.common.adjust_lon(lon -this.long0);
+    var x = this.x0 + this.a * dlon;
+    var y = this.y0 + this.a * Math.log(Math.tan((Proj4js.common.PI / 4.0) + (lat / 2.5))) * 1.25;
+
+    p.x=x;
+    p.y=y;
+    return p;
+  },//millFwd()
+
+  /* Miller Cylindrical inverse equations--mapping x,y to lat/long
+    ------------------------------------------------------------*/
+  inverse: function(p) {
+    p.x -= this.x0;
+    p.y -= this.y0;
+
+    var lon = Proj4js.common.adjust_lon(this.long0 + p.x /this.a);
+    var lat = 2.5 * (Math.atan(Math.exp(0.8*p.y/this.a)) - Proj4js.common.PI / 4.0);
+
+    p.x=lon;
+    p.y=lat;
+    return p;
+  }//millInv()
+};
+/* ======================================================================
+    projCode/gnom.js
+   ====================================================================== */
+
+/*****************************************************************************
+NAME                             GNOMONIC
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Gnomonic Projection.
+                Implementation based on the existing sterea and ortho
+                implementations.
+
+PROGRAMMER              DATE
+----------              ----
+Richard Marsden         November 2009
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Flattening the Earth - Two Thousand Years of Map 
+    Projections", University of Chicago Press 1993
+
+2.  Wolfram Mathworld "Gnomonic Projection"
+    http://mathworld.wolfram.com/GnomonicProjection.html
+    Accessed: 12th November 2009
+******************************************************************************/
+
+Proj4js.Proj.gnom = {
+
+  /* Initialize the Gnomonic projection
+    -------------------------------------*/
+  init: function(def) {
+
+    /* Place parameters in static storage for common use
+      -------------------------------------------------*/
+    this.sin_p14=Math.sin(this.lat0);
+    this.cos_p14=Math.cos(this.lat0);
+    // Approximation for projecting points to the horizon (infinity)
+    this.infinity_dist = 1000 * this.a;
+    this.rc = 1;
+  },
+
+
+  /* Gnomonic forward equations--mapping lat,long to x,y
+    ---------------------------------------------------*/
+  forward: function(p) {
+    var sinphi, cosphi;	/* sin and cos value				*/
+    var dlon;		/* delta longitude value			*/
+    var coslon;		/* cos of longitude				*/
+    var ksp;		/* scale factor					*/
+    var g;		
+    var lon=p.x;
+    var lat=p.y;	
+    /* Forward equations
+      -----------------*/
+    dlon = Proj4js.common.adjust_lon(lon - this.long0);
+
+    sinphi=Math.sin(lat);
+    cosphi=Math.cos(lat);	
+
+    coslon = Math.cos(dlon);
+    g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
+    ksp = 1.0;
+    if ((g > 0) || (Math.abs(g) <= Proj4js.common.EPSLN)) {
+      x = this.x0 + this.a * ksp * cosphi * Math.sin(dlon) / g;
+      y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon) / g;
+    } else {
+      Proj4js.reportError("orthoFwdPointError");
+
+      // Point is in the opposing hemisphere and is unprojectable
+      // We still need to return a reasonable point, so we project 
+      // to infinity, on a bearing 
+      // equivalent to the northern hemisphere equivalent
+      // This is a reasonable approximation for short shapes and lines that 
+      // straddle the horizon.
+
+      x = this.x0 + this.infinity_dist * cosphi * Math.sin(dlon);
+      y = this.y0 + this.infinity_dist * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);
+
+    }
+    p.x=x;
+    p.y=y;
+    return p;
+  },
+
+
+  inverse: function(p) {
+    var rh;		/* Rho */
+    var z;		/* angle */
+    var sinc, cosc;
+    var c;
+    var lon , lat;
+
+    /* Inverse equations
+      -----------------*/
+    p.x = (p.x - this.x0) / this.a;
+    p.y = (p.y - this.y0) / this.a;
+
+    p.x /= this.k0;
+    p.y /= this.k0;
+
+    if ( (rh = Math.sqrt(p.x * p.x + p.y * p.y)) ) {
+      c = Math.atan2(rh, this.rc);
+      sinc = Math.sin(c);
+      cosc = Math.cos(c);
+
+      lat = Proj4js.common.asinz(cosc*this.sin_p14 + (p.y*sinc*this.cos_p14) / rh);
+      lon = Math.atan2(p.x*sinc, rh*this.cos_p14*cosc - p.y*this.sin_p14*sinc);
+      lon = Proj4js.common.adjust_lon(this.long0+lon);
+    } else {
+      lat = this.phic0;
+      lon = 0.0;
+    }
+ 
+    p.x=lon;
+    p.y=lat;
+    return p;
+  }
+};
+
+
+/* ======================================================================
+    projCode/sinu.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                  		SINUSOIDAL
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Sinusoidal projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+PROGRAMMER              DATE            
+----------              ----           
+D. Steinwand, EROS      May, 1991     
+
+This function was adapted from the Sinusoidal projection code (FORTRAN) in the 
+General Cartographic Transformation Package software which is available from 
+the U.S. Geological Survey National Mapping Division.
+ 
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  "Software Documentation for GCTP General Cartographic Transformation
+    Package", U.S. Geological Survey National Mapping Division, May 1982.
+*******************************************************************************/
+
+Proj4js.Proj.sinu = {
+
+	/* Initialize the Sinusoidal projection
+	  ------------------------------------*/
+	init: function() {
+		/* Place parameters in static storage for common use
+		  -------------------------------------------------*/
+		this.R = 6370997.0; //Radius of earth
+	},
+
+	/* Sinusoidal forward equations--mapping lat,long to x,y
+	-----------------------------------------------------*/
+	forward: function(p) {
+		var x,y,delta_lon;	
+		var lon=p.x;
+		var lat=p.y;	
+		/* Forward equations
+		-----------------*/
+		delta_lon = Proj4js.common.adjust_lon(lon - this.long0);
+		x = this.R * delta_lon * Math.cos(lat) + this.x0;
+		y = this.R * lat + this.y0;
+
+		p.x=x;
+		p.y=y;	
+		return p;
+	},
+
+	inverse: function(p) {
+		var lat,temp,lon;	
+
+		/* Inverse equations
+		  -----------------*/
+		p.x -= this.x0;
+		p.y -= this.y0;
+		lat = p.y / this.R;
+		if (Math.abs(lat) > Proj4js.common.HALF_PI) {
+		    Proj4js.reportError("sinu:Inv:DataError");
+		}
+		temp = Math.abs(lat) - Proj4js.common.HALF_PI;
+		if (Math.abs(temp) > Proj4js.common.EPSLN) {
+			temp = this.long0+ p.x / (this.R *Math.cos(lat));
+			lon = Proj4js.common.adjust_lon(temp);
+		} else {
+			lon = this.long0;
+		}
+		  
+		p.x=lon;
+		p.y=lat;
+		return p;
+	}
+};
+
+
+/* ======================================================================
+    projCode/vandg.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                    VAN DER GRINTEN 
+
+PURPOSE:	Transforms input Easting and Northing to longitude and
+		latitude for the Van der Grinten projection.  The
+		Easting and Northing must be in meters.  The longitude
+		and latitude values will be returned in radians.
+
+PROGRAMMER              DATE            
+----------              ----           
+T. Mittan		March, 1993
+
+This function was adapted from the Van Der Grinten projection code
+(FORTRAN) in the General Cartographic Transformation Package software
+which is available from the U.S. Geological Survey National Mapping Division.
+ 
+ALGORITHM REFERENCES
+
+1.  "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
+    The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
+
+2.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+3.  "Software Documentation for GCTP General Cartographic Transformation
+    Package", U.S. Geological Survey National Mapping Division, May 1982.
+*******************************************************************************/
+
+Proj4js.Proj.vandg = {
+
+/* Initialize the Van Der Grinten projection
+  ----------------------------------------*/
+	init: function() {
+		this.R = 6370997.0; //Radius of earth
+	},
+
+	forward: function(p) {
+
+		var lon=p.x;
+		var lat=p.y;	
+
+		/* Forward equations
+		-----------------*/
+		var dlon = Proj4js.common.adjust_lon(lon - this.long0);
+		var x,y;
+
+		if (Math.abs(lat) <= Proj4js.common.EPSLN) {
+			x = this.x0  + this.R * dlon;
+			y = this.y0;
+		}
+		var theta = Proj4js.common.asinz(2.0 * Math.abs(lat / Proj4js.common.PI));
+		if ((Math.abs(dlon) <= Proj4js.common.EPSLN) || (Math.abs(Math.abs(lat) - Proj4js.common.HALF_PI) <= Proj4js.common.EPSLN)) {
+			x = this.x0;
+			if (lat >= 0) {
+				y = this.y0 + Proj4js.common.PI * this.R * Math.tan(.5 * theta);
+			} else {
+				y = this.y0 + Proj4js.common.PI * this.R * - Math.tan(.5 * theta);
+			}
+			//  return(OK);
+		}
+		var al = .5 * Math.abs((Proj4js.common.PI / dlon) - (dlon / Proj4js.common.PI));
+		var asq = al * al;
+		var sinth = Math.sin(theta);
+		var costh = Math.cos(theta);
+
+		var g = costh / (sinth + costh - 1.0);
+		var gsq = g * g;
+		var m = g * (2.0 / sinth - 1.0);
+		var msq = m * m;
+		var con = Proj4js.common.PI * this.R * (al * (g - msq) + Math.sqrt(asq * (g - msq) * (g - msq) - (msq + asq) * (gsq - msq))) / (msq + asq);
+		if (dlon < 0) {
+		 con = -con;
+		}
+		x = this.x0 + con;
+		con = Math.abs(con / (Proj4js.common.PI * this.R));
+		if (lat >= 0) {
+		 y = this.y0 + Proj4js.common.PI * this.R * Math.sqrt(1.0 - con * con - 2.0 * al * con);
+		} else {
+		 y = this.y0 - Proj4js.common.PI * this.R * Math.sqrt(1.0 - con * con - 2.0 * al * con);
+		}
+		p.x = x;
+		p.y = y;
+		return p;
+	},
+
+/* Van Der Grinten inverse equations--mapping x,y to lat/long
+  ---------------------------------------------------------*/
+	inverse: function(p) {
+		var dlon;
+		var xx,yy,xys,c1,c2,c3;
+		var al,asq;
+		var a1;
+		var m1;
+		var con;
+		var th1;
+		var d;
+
+		/* inverse equations
+		-----------------*/
+		p.x -= this.x0;
+		p.y -= this.y0;
+		con = Proj4js.common.PI * this.R;
+		xx = p.x / con;
+		yy =p.y / con;
+		xys = xx * xx + yy * yy;
+		c1 = -Math.abs(yy) * (1.0 + xys);
+		c2 = c1 - 2.0 * yy * yy + xx * xx;
+		c3 = -2.0 * c1 + 1.0 + 2.0 * yy * yy + xys * xys;
+		d = yy * yy / c3 + (2.0 * c2 * c2 * c2 / c3 / c3 / c3 - 9.0 * c1 * c2 / c3 /c3) / 27.0;
+		a1 = (c1 - c2 * c2 / 3.0 / c3) / c3;
+		m1 = 2.0 * Math.sqrt( -a1 / 3.0);
+		con = ((3.0 * d) / a1) / m1;
+		if (Math.abs(con) > 1.0) {
+			if (con >= 0.0) {
+				con = 1.0;
+			} else {
+				con = -1.0;
+			}
+		}
+		th1 = Math.acos(con) / 3.0;
+		if (p.y >= 0) {
+			lat = (-m1 *Math.cos(th1 + Proj4js.common.PI / 3.0) - c2 / 3.0 / c3) * Proj4js.common.PI;
+		} else {
+			lat = -(-m1 * Math.cos(th1 + Proj4js.common.PI / 3.0) - c2 / 3.0 / c3) * Proj4js.common.PI;
+		}
+
+		if (Math.abs(xx) < Proj4js.common.EPSLN) {
+			lon = this.long0;
+		}
+		lon = Proj4js.common.adjust_lon(this.long0 + Proj4js.common.PI * (xys - 1.0 + Math.sqrt(1.0 + 2.0 * (xx * xx - yy * yy) + xys * xys)) / 2.0 / xx);
+
+		p.x=lon;
+		p.y=lat;
+		return p;
+	}
+};
+/* ======================================================================
+    projCode/cea.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                    LAMBERT CYLINDRICAL EQUAL AREA
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Lambert Cylindrical Equal Area projection.
+                This class of projection includes the Behrmann and 
+                Gall-Peters Projections.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+PROGRAMMER              DATE            
+----------              ----
+R. Marsden              August 2009
+Winwaed Software Tech LLC, http://www.winwaed.com
+
+This function was adapted from the Miller Cylindrical Projection in the Proj4JS
+library.
+
+Note: This implementation assumes a Spherical Earth. The (commented) code 
+has been included for the ellipsoidal forward transform, but derivation of 
+the ellispoidal inverse transform is beyond me. Note that most of the 
+Proj4JS implementations do NOT currently support ellipsoidal figures. 
+Therefore this is not seen as a problem - especially this lack of support 
+is explicitly stated here.
+ 
+ALGORITHM REFERENCES
+
+1.  "Cartographic Projection Procedures for the UNIX Environment - 
+     A User's Manual" by Gerald I. Evenden, USGS Open File Report 90-284
+    and Release 4 Interim Reports (2003)
+
+2.  Snyder, John P., "Flattening the Earth - Two Thousand Years of Map 
+    Projections", Univ. Chicago Press, 1993
+*******************************************************************************/
+
+Proj4js.Proj.cea = {
+
+/* Initialize the Cylindrical Equal Area projection
+  -------------------------------------------*/
+  init: function() {
+    //no-op
+  },
+
+
+  /* Cylindrical Equal Area forward equations--mapping lat,long to x,y
+    ------------------------------------------------------------*/
+  forward: function(p) {
+    var lon=p.x;
+    var lat=p.y;
+    /* Forward equations
+      -----------------*/
+    dlon = Proj4js.common.adjust_lon(lon -this.long0);
+    var x = this.x0 + this.a * dlon * Math.cos(this.lat_ts);
+    var y = this.y0 + this.a * Math.sin(lat) / Math.cos(this.lat_ts);
+   /* Elliptical Forward Transform
+      Not implemented due to a lack of a matchign inverse function
+    {
+      var Sin_Lat = Math.sin(lat);
+      var Rn = this.a * (Math.sqrt(1.0e0 - this.es * Sin_Lat * Sin_Lat ));
+      x = this.x0 + this.a * dlon * Math.cos(this.lat_ts);
+      y = this.y0 + Rn * Math.sin(lat) / Math.cos(this.lat_ts);
+    }
+   */
+
+
+    p.x=x;
+    p.y=y;
+    return p;
+  },//ceaFwd()
+
+  /* Cylindrical Equal Area inverse equations--mapping x,y to lat/long
+    ------------------------------------------------------------*/
+  inverse: function(p) {
+    p.x -= this.x0;
+    p.y -= this.y0;
+
+    var lon = Proj4js.common.adjust_lon( this.long0 + (p.x / this.a) / Math.cos(this.lat_ts) );
+
+    var lat = Math.asin( (p.y/this.a) * Math.cos(this.lat_ts) );
+
+    p.x=lon;
+    p.y=lat;
+    return p;
+  }//ceaInv()
+};
+/* ======================================================================
+    projCode/eqc.js
+   ====================================================================== */
+
+/* similar to equi.js FIXME proj4 uses eqc */
+Proj4js.Proj.eqc = {
+  init : function() {
+
+      if(!this.x0) this.x0=0;
+      if(!this.y0) this.y0=0;
+      if(!this.lat0) this.lat0=0;
+      if(!this.long0) this.long0=0;
+      if(!this.lat_ts) this.lat_ts=0;
+      if (!this.title) this.title = "Equidistant Cylindrical (Plate Carre)";
+
+      this.rc= Math.cos(this.lat_ts);
+    },
+
+
+    // forward equations--mapping lat,long to x,y
+    // -----------------------------------------------------------------
+    forward : function(p) {
+
+      var lon= p.x;
+      var lat= p.y;
+
+      var dlon = Proj4js.common.adjust_lon(lon - this.long0);
+      var dlat = Proj4js.common.adjust_lat(lat - this.lat0 );
+      p.x= this.x0 + (this.a*dlon*this.rc);
+      p.y= this.y0 + (this.a*dlat        );
+      return p;
+    },
+
+  // inverse equations--mapping x,y to lat/long
+  // -----------------------------------------------------------------
+  inverse : function(p) {
+
+    var x= p.x;
+    var y= p.y;
+
+    p.x= Proj4js.common.adjust_lon(this.long0 + ((x - this.x0)/(this.a*this.rc)));
+    p.y= Proj4js.common.adjust_lat(this.lat0  + ((y - this.y0)/(this.a        )));
+    return p;
+  }
+
+};
+/* ======================================================================
+    projCode/cass.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                            CASSINI
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Cassini projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+    Ported from PROJ.4.
+
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+*******************************************************************************/
+
+
+//Proj4js.defs["EPSG:28191"] = "+proj=cass +lat_0=31.73409694444445 +lon_0=35.21208055555556 +x_0=170251.555 +y_0=126867.909 +a=6378300.789 +b=6356566.435 +towgs84=-275.722,94.7824,340.894,-8.001,-4.42,-11.821,1 +units=m +no_defs";
+
+// Initialize the Cassini projection
+// -----------------------------------------------------------------
+
+Proj4js.Proj.cass = {
+  init : function() {
+    if (!this.sphere) {
+      this.en = this.pj_enfn(this.es)
+      this.m0 = this.pj_mlfn(this.lat0, Math.sin(this.lat0), Math.cos(this.lat0), this.en);
+    }
+  },
+
+  C1:	.16666666666666666666,
+  C2:	.00833333333333333333,
+  C3:	.04166666666666666666,
+  C4:	.33333333333333333333,
+  C5:	.06666666666666666666,
+
+
+/* Cassini forward equations--mapping lat,long to x,y
+  -----------------------------------------------------------------------*/
+  forward: function(p) {
+
+    /* Forward equations
+      -----------------*/
+    var x,y;
+    var lam=p.x;
+    var phi=p.y;
+    lam = Proj4js.common.adjust_lon(lam - this.long0);
+    
+    if (this.sphere) {
+      x = Math.asin(Math.cos(phi) * Math.sin(lam));
+      y = Math.atan2(Math.tan(phi) , Math.cos(lam)) - this.phi0;
+    } else {
+        //ellipsoid
+      this.n = Math.sin(phi);
+      this.c = Math.cos(phi);
+      y = this.pj_mlfn(phi, this.n, this.c, this.en);
+      this.n = 1./Math.sqrt(1. - this.es * this.n * this.n);
+      this.tn = Math.tan(phi); 
+      this.t = this.tn * this.tn;
+      this.a1 = lam * this.c;
+      this.c *= this.es * this.c / (1 - this.es);
+      this.a2 = this.a1 * this.a1;
+      x = this.n * this.a1 * (1. - this.a2 * this.t * (this.C1 - (8. - this.t + 8. * this.c) * this.a2 * this.C2));
+      y -= this.m0 - this.n * this.tn * this.a2 * (.5 + (5. - this.t + 6. * this.c) * this.a2 * this.C3);
+    }
+    
+    p.x = this.a*x + this.x0;
+    p.y = this.a*y + this.y0;
+    return p;
+  },//cassFwd()
+
+/* Inverse equations
+  -----------------*/
+  inverse: function(p) {
+    p.x -= this.x0;
+    p.y -= this.y0;
+    var x = p.x/this.a;
+    var y = p.y/this.a;
+    
+    if (this.sphere) {
+      this.dd = y + this.lat0;
+      phi = Math.asin(Math.sin(this.dd) * Math.cos(x));
+      lam = Math.atan2(Math.tan(x), Math.cos(this.dd));
+    } else {
+      /* ellipsoid */
+      ph1 = this.pj_inv_mlfn(this.m0 + y, this.es, this.en);
+      this.tn = Math.tan(ph1); 
+      this.t = this.tn * this.tn;
+      this.n = Math.sin(ph1);
+      this.r = 1. / (1. - this.es * this.n * this.n);
+      this.n = Math.sqrt(this.r);
+      this.r *= (1. - this.es) * this.n;
+      this.dd = x / this.n;
+      this.d2 = this.dd * this.dd;
+      phi = ph1 - (this.n * this.tn / this.r) * this.d2 * (.5 - (1. + 3. * this.t) * this.d2 * this.C3);
+      lam = this.dd * (1. + this.t * this.d2 * (-this.C4 + (1. + 3. * this.t) * this.d2 * this.C5)) / Math.cos(ph1);
+    }
+    p.x = Proj4js.common.adjust_lon(this.long0+lam);
+    p.y = phi;
+    return p;
+  },//lamazInv()
+
+
+  //code from the PROJ.4 pj_mlfn.c file;  this may be useful for other projections
+  pj_enfn: function(es) {
+    en = new Array();
+    en[0] = this.C00 - es * (this.C02 + es * (this.C04 + es * (this.C06 + es * this.C08)));
+    en[1] = es * (this.C22 - es * (this.C04 + es * (this.C06 + es * this.C08)));
+    var t = es * es;
+    en[2] = t * (this.C44 - es * (this.C46 + es * this.C48));
+    t *= es;
+    en[3] = t * (this.C66 - es * this.C68);
+    en[4] = t * es * this.C88;
+    return en;
+  },
+  
+  pj_mlfn: function(phi, sphi, cphi, en) {
+    cphi *= sphi;
+    sphi *= sphi;
+    return(en[0] * phi - cphi * (en[1] + sphi*(en[2]+ sphi*(en[3] + sphi*en[4]))));
+  },
+  
+  pj_inv_mlfn: function(arg, es, en) {
+    k = 1./(1.-es);
+    phi = arg;
+    for (i = Proj4js.common.MAX_ITER; i ; --i) { /* rarely goes over 2 iterations */
+      s = Math.sin(phi);
+      t = 1. - es * s * s;
+      //t = this.pj_mlfn(phi, s, Math.cos(phi), en) - arg;
+      //phi -= t * (t * Math.sqrt(t)) * k;
+      t = (this.pj_mlfn(phi, s, Math.cos(phi), en) - arg) * (t * Math.sqrt(t)) * k;
+      phi -= t;
+      if (Math.abs(t) < Proj4js.common.EPSLN)
+        return phi;
+    }
+    Proj4js.reportError("cass:pj_inv_mlfn: Convergence error");
+    return phi;
+  },
+
+/* meridinal distance for ellipsoid and inverse
+**	8th degree - accurate to < 1e-5 meters when used in conjuction
+**		with typical major axis values.
+**	Inverse determines phi to EPS (1e-11) radians, about 1e-6 seconds.
+*/
+  C00: 1.0,
+  C02: .25,
+  C04: .046875,
+  C06: .01953125,
+  C08: .01068115234375,
+  C22: .75,
+  C44: .46875,
+  C46: .01302083333333333333,
+  C48: .00712076822916666666,
+  C66: .36458333333333333333,
+  C68: .00569661458333333333,
+  C88: .3076171875
+
+}
+/* ======================================================================
+    projCode/gauss.js
+   ====================================================================== */
+
+
+Proj4js.Proj.gauss = {
+
+  init : function() {
+    sphi = Math.sin(this.lat0);
+    cphi = Math.cos(this.lat0);  
+    cphi *= cphi;
+    this.rc = Math.sqrt(1.0 - this.es) / (1.0 - this.es * sphi * sphi);
+    this.C = Math.sqrt(1.0 + this.es * cphi * cphi / (1.0 - this.es));
+    this.phic0 = Math.asin(sphi / this.C);
+    this.ratexp = 0.5 * this.C * this.e;
+    this.K = Math.tan(0.5 * this.phic0 + Proj4js.common.FORTPI) / (Math.pow(Math.tan(0.5*this.lat0 + Proj4js.common.FORTPI), this.C) * Proj4js.common.srat(this.e*sphi, this.ratexp));
+  },
+
+  forward : function(p) {
+    var lon = p.x;
+    var lat = p.y;
+
+    p.y = 2.0 * Math.atan( this.K * Math.pow(Math.tan(0.5 * lat + Proj4js.common.FORTPI), this.C) * Proj4js.common.srat(this.e * Math.sin(lat), this.ratexp) ) - Proj4js.common.HALF_PI;
+    p.x = this.C * lon;
+    return p;
+  },
+
+  inverse : function(p) {
+    var DEL_TOL = 1e-14;
+    var lon = p.x / this.C;
+    var lat = p.y;
+    num = Math.pow(Math.tan(0.5 * lat + Proj4js.common.FORTPI)/this.K, 1./this.C);
+    for (var i = Proj4js.common.MAX_ITER; i>0; --i) {
+      lat = 2.0 * Math.atan(num * Proj4js.common.srat(this.e * Math.sin(p.y), -0.5 * this.e)) - Proj4js.common.HALF_PI;
+      if (Math.abs(lat - p.y) < DEL_TOL) break;
+      p.y = lat;
+    }	
+    /* convergence failed */
+    if (!i) {
+      Proj4js.reportError("gauss:inverse:convergence failed");
+      return null;
+    }
+    p.x = lon;
+    p.y = lat;
+    return p;
+  }
+};
+
+/* ======================================================================
+    projCode/omerc.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                       OBLIQUE MERCATOR (HOTINE) 
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Oblique Mercator projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+PROGRAMMER              DATE
+----------              ----
+T. Mittan		Mar, 1993
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+    Printing Office, Washington D.C., 1989.
+*******************************************************************************/
+
+Proj4js.Proj.omerc = {
+
+  /* Initialize the Oblique Mercator  projection
+    ------------------------------------------*/
+  init: function() {
+    if (!this.mode) this.mode=0;
+    if (!this.lon1)   {this.lon1=0;this.mode=1;}
+    if (!this.lon2)   this.lon2=0;
+    if (!this.lat2)    this.lat2=0;
+
+    /* Place parameters in static storage for common use
+      -------------------------------------------------*/
+    var temp = this.b/ this.a;
+    var es = 1.0 - Math.pow(temp,2);
+    var e = Math.sqrt(es);
+
+    this.sin_p20=Math.sin(this.lat0);
+    this.cos_p20=Math.cos(this.lat0);
+
+    this.con = 1.0 - this.es * this.sin_p20 * this.sin_p20;
+    this.com = Math.sqrt(1.0 - es);
+    this.bl = Math.sqrt(1.0 + this.es * Math.pow(this.cos_p20,4.0)/(1.0 - es));
+    this.al = this.a * this.bl * this.k0 * this.com / this.con;
+    if (Math.abs(this.lat0) < Proj4js.common.EPSLN) {
+       this.ts = 1.0;
+       this.d = 1.0;
+       this.el = 1.0;
+    } else {
+       this.ts = Proj4js.common.tsfnz(this.e,this.lat0,this.sin_p20);
+       this.con = Math.sqrt(this.con);
+       this.d = this.bl * this.com / (this.cos_p20 * this.con);
+       if ((this.d * this.d - 1.0) > 0.0) {
+          if (this.lat0 >= 0.0) {
+             this.f = this.d + Math.sqrt(this.d * this.d - 1.0);
+          } else {
+             this.f = this.d - Math.sqrt(this.d * this.d - 1.0);
+          }
+       } else {
+         this.f = this.d;
+       }
+       this.el = this.f * Math.pow(this.ts,this.bl);
+    }
+
+    //this.longc=52.60353916666667;
+
+    if (this.mode != 0) {
+       this.g = .5 * (this.f - 1.0/this.f);
+       this.gama = Proj4js.common.asinz(Math.sin(this.alpha) / this.d);
+       this.longc= this.longc - Proj4js.common.asinz(this.g * Math.tan(this.gama))/this.bl;
+
+       /* Report parameters common to format B
+       -------------------------------------*/
+       //genrpt(azimuth * R2D,"Azimuth of Central Line:    ");
+       //cenlon(lon_origin);
+      // cenlat(lat_origin);
+
+       this.con = Math.abs(this.lat0);
+       if ((this.con > Proj4js.common.EPSLN) && (Math.abs(this.con - Proj4js.common.HALF_PI) > Proj4js.common.EPSLN)) {
+            this.singam=Math.sin(this.gama);
+            this.cosgam=Math.cos(this.gama);
+
+            this.sinaz=Math.sin(this.alpha);
+            this.cosaz=Math.cos(this.alpha);
+
+            if (this.lat0>= 0) {
+               this.u =  (this.al / this.bl) * Math.atan(Math.sqrt(this.d*this.d - 1.0)/this.cosaz);
+            } else {
+               this.u =  -(this.al / this.bl) *Math.atan(Math.sqrt(this.d*this.d - 1.0)/this.cosaz);
+            }
+          } else {
+            Proj4js.reportError("omerc:Init:DataError");
+          }
+       } else {
+       this.sinphi =Math. sin(this.at1);
+       this.ts1 = Proj4js.common.tsfnz(this.e,this.lat1,this.sinphi);
+       this.sinphi = Math.sin(this.lat2);
+       this.ts2 = Proj4js.common.tsfnz(this.e,this.lat2,this.sinphi);
+       this.h = Math.pow(this.ts1,this.bl);
+       this.l = Math.pow(this.ts2,this.bl);
+       this.f = this.el/this.h;
+       this.g = .5 * (this.f - 1.0/this.f);
+       this.j = (this.el * this.el - this.l * this.h)/(this.el * this.el + this.l * this.h);
+       this.p = (this.l - this.h) / (this.l + this.h);
+       this.dlon = this.lon1 - this.lon2;
+       if (this.dlon < -Proj4js.common.PI) this.lon2 = this.lon2 - 2.0 * Proj4js.common.PI;
+       if (this.dlon > Proj4js.common.PI) this.lon2 = this.lon2 + 2.0 * Proj4js.common.PI;
+       this.dlon = this.lon1 - this.lon2;
+       this.longc = .5 * (this.lon1 + this.lon2) -Math.atan(this.j * Math.tan(.5 * this.bl * this.dlon)/this.p)/this.bl;
+       this.dlon  = Proj4js.common.adjust_lon(this.lon1 - this.longc);
+       this.gama = Math.atan(Math.sin(this.bl * this.dlon)/this.g);
+       this.alpha = Proj4js.common.asinz(this.d * Math.sin(this.gama));
+
+       /* Report parameters common to format A
+       -------------------------------------*/
+
+       if (Math.abs(this.lat1 - this.lat2) <= Proj4js.common.EPSLN) {
+          Proj4js.reportError("omercInitDataError");
+          //return(202);
+       } else {
+          this.con = Math.abs(this.lat1);
+       }
+       if ((this.con <= Proj4js.common.EPSLN) || (Math.abs(this.con - HALF_PI) <= Proj4js.common.EPSLN)) {
+           Proj4js.reportError("omercInitDataError");
+                //return(202);
+       } else {
+         if (Math.abs(Math.abs(this.lat0) - Proj4js.common.HALF_PI) <= Proj4js.common.EPSLN) {
+            Proj4js.reportError("omercInitDataError");
+            //return(202);
+         }
+       }
+
+       this.singam=Math.sin(this.gam);
+       this.cosgam=Math.cos(this.gam);
+
+       this.sinaz=Math.sin(this.alpha);
+       this.cosaz=Math.cos(this.alpha);  
+
+
+       if (this.lat0 >= 0) {
+          this.u =  (this.al/this.bl) * Math.atan(Math.sqrt(this.d * this.d - 1.0)/this.cosaz);
+       } else {
+          this.u = -(this.al/this.bl) * Math.atan(Math.sqrt(this.d * this.d - 1.0)/this.cosaz);
+       }
+     }
+  },
+
+
+  /* Oblique Mercator forward equations--mapping lat,long to x,y
+    ----------------------------------------------------------*/
+  forward: function(p) {
+    var theta;		/* angle					*/
+    var sin_phi, cos_phi;/* sin and cos value				*/
+    var b;		/* temporary values				*/
+    var c, t, tq;	/* temporary values				*/
+    var con, n, ml;	/* cone constant, small m			*/
+    var q,us,vl;
+    var ul,vs;
+    var s;
+    var dlon;
+    var ts1;
+
+    var lon=p.x;
+    var lat=p.y;
+    /* Forward equations
+      -----------------*/
+    sin_phi = Math.sin(lat);
+    dlon = Proj4js.common.adjust_lon(lon - this.longc);
+    vl = Math.sin(this.bl * dlon);
+    if (Math.abs(Math.abs(lat) - Proj4js.common.HALF_PI) > Proj4js.common.EPSLN) {
+       ts1 = Proj4js.common.tsfnz(this.e,lat,sin_phi);
+       q = this.el / (Math.pow(ts1,this.bl));
+       s = .5 * (q - 1.0 / q);
+       t = .5 * (q + 1.0/ q);
+       ul = (s * this.singam - vl * this.cosgam) / t;
+       con = Math.cos(this.bl * dlon);
+       if (Math.abs(con) < .0000001) {
+          us = this.al * this.bl * dlon;
+       } else {
+          us = this.al * Math.atan((s * this.cosgam + vl * this.singam) / con)/this.bl;
+          if (con < 0) us = us + Proj4js.common.PI * this.al / this.bl;
+       }
+    } else {
+       if (lat >= 0) {
+          ul = this.singam;
+       } else {
+          ul = -this.singam;
+       }
+       us = this.al * lat / this.bl;
+    }
+    if (Math.abs(Math.abs(ul) - 1.0) <= Proj4js.common.EPSLN) {
+       //alert("Point projects into infinity","omer-for");
+       Proj4js.reportError("omercFwdInfinity");
+       //return(205);
+    }
+    vs = .5 * this.al * Math.log((1.0 - ul)/(1.0 + ul)) / this.bl;
+    us = us - this.u;
+    var x = this.x0 + vs * this.cosaz + us * this.sinaz;
+    var y = this.y0 + us * this.cosaz - vs * this.sinaz;
+
+    p.x=x;
+    p.y=y;
+    return p;
+  },
+
+  inverse: function(p) {
+    var delta_lon;	/* Delta longitude (Given longitude - center 	*/
+    var theta;		/* angle					*/
+    var delta_theta;	/* adjusted longitude				*/
+    var sin_phi, cos_phi;/* sin and cos value				*/
+    var b;		/* temporary values				*/
+    var c, t, tq;	/* temporary values				*/
+    var con, n, ml;	/* cone constant, small m			*/
+    var vs,us,q,s,ts1;
+    var vl,ul,bs;
+    var dlon;
+    var  flag;
+
+    /* Inverse equations
+      -----------------*/
+    p.x -= this.x0;
+    p.y -= this.y0;
+    flag = 0;
+    vs = p.x * this.cosaz - p.y * this.sinaz;
+    us = p.y * this.cosaz + p.x * this.sinaz;
+    us = us + this.u;
+    q = Math.exp(-this.bl * vs / this.al);
+    s = .5 * (q - 1.0/q);
+    t = .5 * (q + 1.0/q);
+    vl = Math.sin(this.bl * us / this.al);
+    ul = (vl * this.cosgam + s * this.singam)/t;
+    if (Math.abs(Math.abs(ul) - 1.0) <= Proj4js.common.EPSLN)
+       {
+       lon = this.longc;
+       if (ul >= 0.0) {
+          lat = Proj4js.common.HALF_PI;
+       } else {
+         lat = -Proj4js.common.HALF_PI;
+       }
+    } else {
+       con = 1.0 / this.bl;
+       ts1 =Math.pow((this.el / Math.sqrt((1.0 + ul) / (1.0 - ul))),con);
+       lat = Proj4js.common.phi2z(this.e,ts1);
+       //if (flag != 0)
+          //return(flag);
+       //~ con = Math.cos(this.bl * us /al);
+       theta = this.longc - Math.atan2((s * this.cosgam - vl * this.singam) , con)/this.bl;
+       lon = Proj4js.common.adjust_lon(theta);
+    }
+    p.x=lon;
+    p.y=lat;
+    return p;
+  }
+};
+/* ======================================================================
+    projCode/lcc.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                            LAMBERT CONFORMAL CONIC
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Lambert Conformal Conic projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+*******************************************************************************/
+
+
+//<2104> +proj=lcc +lat_1=10.16666666666667 +lat_0=10.16666666666667 +lon_0=-71.60561777777777 +k_0=1 +x0=-17044 +x0=-23139.97 +ellps=intl +units=m +no_defs  no_defs
+
+// Initialize the Lambert Conformal conic projection
+// -----------------------------------------------------------------
+
+//Proj4js.Proj.lcc = Class.create();
+Proj4js.Proj.lcc = {
+  init : function() {
+
+    // array of:  r_maj,r_min,lat1,lat2,c_lon,c_lat,false_east,false_north
+    //double c_lat;                   /* center latitude                      */
+    //double c_lon;                   /* center longitude                     */
+    //double lat1;                    /* first standard parallel              */
+    //double lat2;                    /* second standard parallel             */
+    //double r_maj;                   /* major axis                           */
+    //double r_min;                   /* minor axis                           */
+    //double false_east;              /* x offset in meters                   */
+    //double false_north;             /* y offset in meters                   */
+
+      if (!this.lat2){this.lat2=this.lat0;}//if lat2 is not defined
+      if (!this.k0) this.k0 = 1.0;
+
+    // Standard Parallels cannot be equal and on opposite sides of the equator
+      if (Math.abs(this.lat1+this.lat2) < Proj4js.common.EPSLN) {
+        Proj4js.reportError("lcc:init: Equal Latitudes");
+        return;
+      }
+
+      var temp = this.b / this.a;
+      this.e = Math.sqrt(1.0 - temp*temp);
+
+      var sin1 = Math.sin(this.lat1);
+      var cos1 = Math.cos(this.lat1);
+      var ms1 = Proj4js.common.msfnz(this.e, sin1, cos1);
+      var ts1 = Proj4js.common.tsfnz(this.e, this.lat1, sin1);
+
+      var sin2 = Math.sin(this.lat2);
+      var cos2 = Math.cos(this.lat2);
+      var ms2 = Proj4js.common.msfnz(this.e, sin2, cos2);
+      var ts2 = Proj4js.common.tsfnz(this.e, this.lat2, sin2);
+
+      var ts0 = Proj4js.common.tsfnz(this.e, this.lat0, Math.sin(this.lat0));
+
+      if (Math.abs(this.lat1 - this.lat2) > Proj4js.common.EPSLN) {
+        this.ns = Math.log(ms1/ms2)/Math.log(ts1/ts2);
+      } else {
+        this.ns = sin1;
+      }
+      this.f0 = ms1 / (this.ns * Math.pow(ts1, this.ns));
+      this.rh = this.a * this.f0 * Math.pow(ts0, this.ns);
+      if (!this.title) this.title = "Lambert Conformal Conic";
+    },
+
+
+    // Lambert Conformal conic forward equations--mapping lat,long to x,y
+    // -----------------------------------------------------------------
+    forward : function(p) {
+
+      var lon = p.x;
+      var lat = p.y;
+
+    // convert to radians
+      if ( lat <= 90.0 && lat >= -90.0 && lon <= 180.0 && lon >= -180.0) {
+        //lon = lon * Proj4js.common.D2R;
+        //lat = lat * Proj4js.common.D2R;
+      } else {
+        Proj4js.reportError("lcc:forward: llInputOutOfRange: "+ lon +" : " + lat);
+        return null;
+      }
+
+      var con  = Math.abs( Math.abs(lat) - Proj4js.common.HALF_PI);
+      var ts, rh1;
+      if (con > Proj4js.common.EPSLN) {
+        ts = Proj4js.common.tsfnz(this.e, lat, Math.sin(lat) );
+        rh1 = this.a * this.f0 * Math.pow(ts, this.ns);
+      } else {
+        con = lat * this.ns;
+        if (con <= 0) {
+          Proj4js.reportError("lcc:forward: No Projection");
+          return null;
+        }
+        rh1 = 0;
+      }
+      var theta = this.ns * Proj4js.common.adjust_lon(lon - this.long0);
+      p.x = this.k0 * (rh1 * Math.sin(theta)) + this.x0;
+      p.y = this.k0 * (this.rh - rh1 * Math.cos(theta)) + this.y0;
+
+      return p;
+    },
+
+  // Lambert Conformal Conic inverse equations--mapping x,y to lat/long
+  // -----------------------------------------------------------------
+  inverse : function(p) {
+
+    var rh1, con, ts;
+    var lat, lon;
+    var x = (p.x - this.x0)/this.k0;
+    var y = (this.rh - (p.y - this.y0)/this.k0);
+    if (this.ns > 0) {
+      rh1 = Math.sqrt (x * x + y * y);
+      con = 1.0;
+    } else {
+      rh1 = -Math.sqrt (x * x + y * y);
+      con = -1.0;
+    }
+    var theta = 0.0;
+    if (rh1 != 0) {
+      theta = Math.atan2((con * x),(con * y));
+    }
+    if ((rh1 != 0) || (this.ns > 0.0)) {
+      con = 1.0/this.ns;
+      ts = Math.pow((rh1/(this.a * this.f0)), con);
+      lat = Proj4js.common.phi2z(this.e, ts);
+      if (lat == -9999) return null;
+    } else {
+      lat = -Proj4js.common.HALF_PI;
+    }
+    lon = Proj4js.common.adjust_lon(theta/this.ns + this.long0);
+
+    p.x = lon;
+    p.y = lat;
+    return p;
+  }
+};
+
+
+
+
+/* ======================================================================
+    projCode/laea.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                  LAMBERT AZIMUTHAL EQUAL-AREA
+ 
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the Lambert Azimuthal Equal-Area projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+PROGRAMMER              DATE            
+----------              ----           
+D. Steinwand, EROS      March, 1991   
+
+This function was adapted from the Lambert Azimuthal Equal Area projection
+code (FORTRAN) in the General Cartographic Transformation Package software
+which is available from the U.S. Geological Survey National Mapping Division.
+ 
+ALGORITHM REFERENCES
+
+1.  "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
+    The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
+
+2.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+
+3.  "Software Documentation for GCTP General Cartographic Transformation
+    Package", U.S. Geological Survey National Mapping Division, May 1982.
+*******************************************************************************/
+
+Proj4js.Proj.laea = {
+  S_POLE: 1,
+  N_POLE: 2,
+  EQUIT: 3,
+  OBLIQ: 4,
+
+
+/* Initialize the Lambert Azimuthal Equal Area projection
+  ------------------------------------------------------*/
+  init: function() {
+    var t = Math.abs(this.lat0);
+    if (Math.abs(t - Proj4js.common.HALF_PI) < Proj4js.common.EPSLN) {
+      this.mode = this.lat0 < 0. ? this.S_POLE : this.N_POLE;
+    } else if (Math.abs(t) < Proj4js.common.EPSLN) {
+      this.mode = this.EQUIT;
+    } else {
+      this.mode = this.OBLIQ;
+    }
+    if (this.es > 0) {
+      var sinphi;
+  
+      this.qp = Proj4js.common.qsfnz(this.e, 1.0);
+      this.mmf = .5 / (1. - this.es);
+      this.apa = this.authset(this.es);
+      switch (this.mode) {
+        case this.N_POLE:
+        case this.S_POLE:
+          this.dd = 1.;
+          break;
+        case this.EQUIT:
+          this.rq = Math.sqrt(.5 * this.qp);
+          this.dd = 1. / this.rq;
+          this.xmf = 1.;
+          this.ymf = .5 * this.qp;
+          break;
+        case this.OBLIQ:
+          this.rq = Math.sqrt(.5 * this.qp);
+          sinphi = Math.sin(this.lat0);
+          this.sinb1 = Proj4js.common.qsfnz(this.e, sinphi) / this.qp;
+          this.cosb1 = Math.sqrt(1. - this.sinb1 * this.sinb1);
+          this.dd = Math.cos(this.lat0) / (Math.sqrt(1. - this.es * sinphi * sinphi) * this.rq * this.cosb1);
+          this.ymf = (this.xmf = this.rq) / this.dd;
+          this.xmf *= this.dd;
+          break;
+      }
+    } else {
+      if (this.mode == this.OBLIQ) {
+        this.sinph0 = Math.sin(this.lat0);
+        this.cosph0 = Math.cos(this.lat0);
+      }
+    }
+  },
+
+/* Lambert Azimuthal Equal Area forward equations--mapping lat,long to x,y
+  -----------------------------------------------------------------------*/
+  forward: function(p) {
+
+    /* Forward equations
+      -----------------*/
+    var x,y;
+    var lam=p.x;
+    var phi=p.y;
+    lam = Proj4js.common.adjust_lon(lam - this.long0);
+    
+    if (this.sphere) {
+        var coslam, cosphi, sinphi;
+      
+        sinphi = Math.sin(phi);
+        cosphi = Math.cos(phi);
+        coslam = Math.cos(lam);
+        switch (this.mode) {
+          case this.EQUIT:
+            y = (this.mode == this.EQUIT) ? 1. + cosphi * coslam : 1. + this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
+            if (y <= Proj4js.common.EPSLN) {
+              Proj4js.reportError("laea:fwd:y less than eps");
+              return null;
+            }
+            y = Math.sqrt(2. / y);
+            x = y * cosphi * Math.sin(lam);
+            y *= (this.mode == this.EQUIT) ? sinphi : this.cosph0 * sinphi - this.sinph0 * cosphi * coslam;
+            break;
+          case this.N_POLE:
+            coslam = -coslam;
+          case this.S_POLE:
+            if (Math.abs(phi + this.phi0) < Proj4js.common.EPSLN) {
+              Proj4js.reportError("laea:fwd:phi < eps");
+              return null;
+            }
+            y = Proj4js.common.FORTPI - phi * .5;
+            y = 2. * ((this.mode == this.S_POLE) ? Math.cos(y) : Math.sin(y));
+            x = y * Math.sin(lam);
+            y *= coslam;
+            break;
+        }
+    } else {
+        var coslam, sinlam, sinphi, q, sinb=0.0, cosb=0.0, b=0.0;
+      
+        coslam = Math.cos(lam);
+        sinlam = Math.sin(lam);
+        sinphi = Math.sin(phi);
+        q = Proj4js.common.qsfnz(this.e, sinphi);
+        if (this.mode == this.OBLIQ || this.mode == this.EQUIT) {
+          sinb = q / this.qp;
+          cosb = Math.sqrt(1. - sinb * sinb);
+        }
+        switch (this.mode) {
+          case this.OBLIQ:
+            b = 1. + this.sinb1 * sinb + this.cosb1 * cosb * coslam;
+            break;
+          case this.EQUIT:
+            b = 1. + cosb * coslam;
+            break;
+          case this.N_POLE:
+            b = Proj4js.common.HALF_PI + phi;
+            q = this.qp - q;
+            break;
+          case this.S_POLE:
+            b = phi - Proj4js.common.HALF_PI;
+            q = this.qp + q;
+            break;
+        }
+        if (Math.abs(b) < Proj4js.common.EPSLN) {
+            Proj4js.reportError("laea:fwd:b < eps");
+            return null;
+        }
+        switch (this.mode) {
+          case this.OBLIQ:
+          case this.EQUIT:
+            b = Math.sqrt(2. / b);
+            if (this.mode == this.OBLIQ) {
+              y = this.ymf * b * (this.cosb1 * sinb - this.sinb1 * cosb * coslam);
+            } else {
+              y = (b = Math.sqrt(2. / (1. + cosb * coslam))) * sinb * this.ymf;
+            }
+            x = this.xmf * b * cosb * sinlam;
+            break;
+          case this.N_POLE:
+          case this.S_POLE:
+            if (q >= 0.) {
+              x = (b = Math.sqrt(q)) * sinlam;
+              y = coslam * ((this.mode == this.S_POLE) ? b : -b);
+            } else {
+              x = y = 0.;
+            }
+            break;
+        }
+    }
+
+    //v 1.0
+    /*
+    var sin_lat=Math.sin(lat);
+    var cos_lat=Math.cos(lat);
+
+    var sin_delta_lon=Math.sin(delta_lon);
+    var cos_delta_lon=Math.cos(delta_lon);
+
+    var g =this.sin_lat_o * sin_lat +this.cos_lat_o * cos_lat * cos_delta_lon;
+    if (g == -1.0) {
+      Proj4js.reportError("laea:fwd:Point projects to a circle of radius "+ 2.0 * R);
+      return null;
+    }
+    var ksp = this.a * Math.sqrt(2.0 / (1.0 + g));
+    var x = ksp * cos_lat * sin_delta_lon + this.x0;
+    var y = ksp * (this.cos_lat_o * sin_lat - this.sin_lat_o * cos_lat * cos_delta_lon) + this.y0;
+    */
+    p.x = this.a*x + this.x0;
+    p.y = this.a*y + this.y0;
+    return p;
+  },//lamazFwd()
+
+/* Inverse equations
+  -----------------*/
+  inverse: function(p) {
+    p.x -= this.x0;
+    p.y -= this.y0;
+    var x = p.x/this.a;
+    var y = p.y/this.a;
+    
+    if (this.sphere) {
+        var  cosz=0.0, rh, sinz=0.0;
+      
+        rh = Math.sqrt(x*x + y*y);
+        var phi = rh * .5;
+        if (phi > 1.) {
+          Proj4js.reportError("laea:Inv:DataError");
+          return null;
+        }
+        phi = 2. * Math.asin(phi);
+        if (this.mode == this.OBLIQ || this.mode == this.EQUIT) {
+          sinz = Math.sin(phi);
+          cosz = Math.cos(phi);
+        }
+        switch (this.mode) {
+        case this.EQUIT:
+          phi = (Math.abs(rh) <= Proj4js.common.EPSLN) ? 0. : Math.asin(y * sinz / rh);
+          x *= sinz;
+          y = cosz * rh;
+          break;
+        case this.OBLIQ:
+          phi = (Math.abs(rh) <= Proj4js.common.EPSLN) ? this.phi0 : Math.asin(cosz * sinph0 + y * sinz * cosph0 / rh);
+          x *= sinz * cosph0;
+          y = (cosz - Math.sin(phi) * sinph0) * rh;
+          break;
+        case this.N_POLE:
+          y = -y;
+          phi = Proj4js.common.HALF_PI - phi;
+          break;
+        case this.S_POLE:
+          phi -= Proj4js.common.HALF_PI;
+          break;
+        }
+        lam = (y == 0. && (this.mode == this.EQUIT || this.mode == this.OBLIQ)) ? 0. : Math.atan2(x, y);
+    } else {
+        var cCe, sCe, q, rho, ab=0.0;
+      
+        switch (this.mode) {
+          case this.EQUIT:
+          case this.OBLIQ:
+            x /= this.dd;
+            y *=  this.dd;
+            rho = Math.sqrt(x*x + y*y);
+            if (rho < Proj4js.common.EPSLN) {
+              p.x = 0.;
+              p.y = this.phi0;
+              return p;
+            }
+            sCe = 2. * Math.asin(.5 * rho / this.rq);
+            cCe = Math.cos(sCe);
+            x *= (sCe = Math.sin(sCe));
+            if (this.mode == this.OBLIQ) {
+              ab = cCe * this.sinb1 + y * sCe * this.cosb1 / rho
+              q = this.qp * ab;
+              y = rho * this.cosb1 * cCe - y * this.sinb1 * sCe;
+            } else {
+              ab = y * sCe / rho;
+              q = this.qp * ab;
+              y = rho * cCe;
+            }
+            break;
+          case this.N_POLE:
+            y = -y;
+          case this.S_POLE:
+            q = (x * x + y * y);
+            if (!q ) {
+              p.x = 0.;
+              p.y = this.phi0;
+              return p;
+            }
+            /*
+            q = this.qp - q;
+            */
+            ab = 1. - q / this.qp;
+            if (this.mode == this.S_POLE) {
+              ab = - ab;
+            }
+            break;
+        }
+        lam = Math.atan2(x, y);
+        phi = this.authlat(Math.asin(ab), this.apa);
+    }
+
+    /*
+    var Rh = Math.Math.sqrt(p.x *p.x +p.y * p.y);
+    var temp = Rh / (2.0 * this.a);
+
+    if (temp > 1) {
+      Proj4js.reportError("laea:Inv:DataError");
+      return null;
+    }
+
+    var z = 2.0 * Proj4js.common.asinz(temp);
+    var sin_z=Math.sin(z);
+    var cos_z=Math.cos(z);
+
+    var lon =this.long0;
+    if (Math.abs(Rh) > Proj4js.common.EPSLN) {
+       var lat = Proj4js.common.asinz(this.sin_lat_o * cos_z +this. cos_lat_o * sin_z *p.y / Rh);
+       var temp =Math.abs(this.lat0) - Proj4js.common.HALF_PI;
+       if (Math.abs(temp) > Proj4js.common.EPSLN) {
+          temp = cos_z -this.sin_lat_o * Math.sin(lat);
+          if(temp!=0.0) lon=Proj4js.common.adjust_lon(this.long0+Math.atan2(p.x*sin_z*this.cos_lat_o,temp*Rh));
+       } else if (this.lat0 < 0.0) {
+          lon = Proj4js.common.adjust_lon(this.long0 - Math.atan2(-p.x,p.y));
+       } else {
+          lon = Proj4js.common.adjust_lon(this.long0 + Math.atan2(p.x, -p.y));
+       }
+    } else {
+      lat = this.lat0;
+    }
+    */
+    //return(OK);
+    p.x = Proj4js.common.adjust_lon(this.long0+lam);
+    p.y = phi;
+    return p;
+  },//lamazInv()
+  
+/* determine latitude from authalic latitude */
+  P00: .33333333333333333333,
+  P01: .17222222222222222222,
+  P02: .10257936507936507936,
+  P10: .06388888888888888888,
+  P11: .06640211640211640211,
+  P20: .01641501294219154443,
+  
+  authset: function(es) {
+    var t;
+    var APA = new Array();
+    APA[0] = es * this.P00;
+    t = es * es;
+    APA[0] += t * this.P01;
+    APA[1] = t * this.P10;
+    t *= es;
+    APA[0] += t * this.P02;
+    APA[1] += t * this.P11;
+    APA[2] = t * this.P20;
+    return APA;
+  },
+  
+  authlat: function(beta, APA) {
+    var t = beta+beta;
+    return(beta + APA[0] * Math.sin(t) + APA[1] * Math.sin(t+t) + APA[2] * Math.sin(t+t+t));
+  }
+  
+};
+
+
+
+/* ======================================================================
+    projCode/aeqd.js
+   ====================================================================== */
+
+Proj4js.Proj.aeqd = {
+
+  init : function() {
+    this.sin_p12=Math.sin(this.lat0);
+    this.cos_p12=Math.cos(this.lat0);
+  },
+
+  forward: function(p) {
+    var lon=p.x;
+    var lat=p.y;
+    var ksp;
+
+    var sinphi=Math.sin(p.y);
+    var cosphi=Math.cos(p.y); 
+    var dlon = Proj4js.common.adjust_lon(lon - this.long0);
+    var coslon = Math.cos(dlon);
+    var g = this.sin_p12 * sinphi + this.cos_p12 * cosphi * coslon;
+    if (Math.abs(Math.abs(g) - 1.0) < Proj4js.common.EPSLN) {
+       ksp = 1.0;
+       if (g < 0.0) {
+         Proj4js.reportError("aeqd:Fwd:PointError");
+         return;
+       }
+    } else {
+       var z = Math.acos(g);
+       ksp = z/Math.sin(z);
+    }
+    p.x = this.x0 + this.a * ksp * cosphi * Math.sin(dlon);
+    p.y = this.y0 + this.a * ksp * (this.cos_p12 * sinphi - this.sin_p12 * cosphi * coslon);
+    return p;
+  },
+
+  inverse: function(p){
+    p.x -= this.x0;
+    p.y -= this.y0;
+
+    var rh = Math.sqrt(p.x * p.x + p.y *p.y);
+    if (rh > (2.0 * Proj4js.common.HALF_PI * this.a)) {
+       Proj4js.reportError("aeqdInvDataError");
+       return;
+    }
+    var z = rh / this.a;
+
+    var sinz=Math.sin(z);
+    var cosz=Math.cos(z);
+
+    var lon = this.long0;
+    var lat;
+    if (Math.abs(rh) <= Proj4js.common.EPSLN) {
+      lat = this.lat0;
+    } else {
+      lat = Proj4js.common.asinz(cosz * this.sin_p12 + (p.y * sinz * this.cos_p12) / rh);
+      var con = Math.abs(this.lat0) - Proj4js.common.HALF_PI;
+      if (Math.abs(con) <= Proj4js.common.EPSLN) {
+        if (lat0 >= 0.0) {
+          lon = Proj4js.common.adjust_lon(this.long0 + Math.atan2(p.x , -p.y));
+        } else {
+          lon = Proj4js.common.adjust_lon(this.long0 - Math.atan2(-p.x , p.y));
+        }
+      } else {
+        con = cosz - this.sin_p12 * Math.sin(lat);
+        if ((Math.abs(con) < Proj4js.common.EPSLN) && (Math.abs(p.x) < Proj4js.common.EPSLN)) {
+           //no-op, just keep the lon value as is
+        } else {
+          var temp = Math.atan2((p.x * sinz * this.cos_p12), (con * rh));
+          lon = Proj4js.common.adjust_lon(this.long0 + Math.atan2((p.x * sinz * this.cos_p12), (con * rh)));
+        }
+      }
+    }
+
+    p.x = lon;
+    p.y = lat;
+    return p;
+  } 
+};
+/* ======================================================================
+    projCode/moll.js
+   ====================================================================== */
+
+/*******************************************************************************
+NAME                            MOLLWEIDE
+
+PURPOSE:	Transforms input longitude and latitude to Easting and
+		Northing for the MOllweide projection.  The
+		longitude and latitude must be in radians.  The Easting
+		and Northing values will be returned in meters.
+
+PROGRAMMER              DATE
+----------              ----
+D. Steinwand, EROS      May, 1991;  Updated Sept, 1992; Updated Feb, 1993
+S. Nelson, EDC		Jun, 2993;	Made corrections in precision and
+					number of iterations.
+
+ALGORITHM REFERENCES
+
+1.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
+    U.S. Geological Survey Professional Paper 1453 , United State Government
+    Printing Office, Washington D.C., 1989.
+
+2.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
+    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
+    State Government Printing Office, Washington D.C., 1987.
+*******************************************************************************/
+
+Proj4js.Proj.moll = {
+
+  /* Initialize the Mollweide projection
+    ------------------------------------*/
+  init: function(){
+    //no-op
+  },
+
+  /* Mollweide forward equations--mapping lat,long to x,y
+    ----------------------------------------------------*/
+  forward: function(p) {
+
+    /* Forward equations
+      -----------------*/
+    var lon=p.x;
+    var lat=p.y;
+
+    var delta_lon = Proj4js.common.adjust_lon(lon - this.long0);
+    var theta = lat;
+    var con = Proj4js.common.PI * Math.sin(lat);
+
+    /* Iterate using the Newton-Raphson method to find theta
+      -----------------------------------------------------*/
+    for (var i=0;true;i++) {
+       var delta_theta = -(theta + Math.sin(theta) - con)/ (1.0 + Math.cos(theta));
+       theta += delta_theta;
+       if (Math.abs(delta_theta) < Proj4js.common.EPSLN) break;
+       if (i >= 50) {
+          Proj4js.reportError("moll:Fwd:IterationError");
+         //return(241);
+       }
+    }
+    theta /= 2.0;
+
+    /* If the latitude is 90 deg, force the x coordinate to be "0 + false easting"
+       this is done here because of precision problems with "cos(theta)"
+       --------------------------------------------------------------------------*/
+    if (Proj4js.common.PI/2 - Math.abs(lat) < Proj4js.common.EPSLN) delta_lon =0;
+    var x = 0.900316316158 * this.a * delta_lon * Math.cos(theta) + this.x0;
+    var y = 1.4142135623731 * this.a * Math.sin(theta) + this.y0;
+
+    p.x=x;
+    p.y=y;
+    return p;
+  },
+
+  inverse: function(p){
+    var theta;
+    var arg;
+
+    /* Inverse equations
+      -----------------*/
+    p.x-= this.x0;
+    //~ p.y -= this.y0;
+    var arg = p.y /  (1.4142135623731 * this.a);
+
+    /* Because of division by zero problems, 'arg' can not be 1.0.  Therefore
+       a number very close to one is used instead.
+       -------------------------------------------------------------------*/
+    if(Math.abs(arg) > 0.999999999999) arg=0.999999999999;
+    var theta =Math.asin(arg);
+    var lon = Proj4js.common.adjust_lon(this.long0 + (p.x / (0.900316316158 * this.a * Math.cos(theta))));
+    if(lon < (-Proj4js.common.PI)) lon= -Proj4js.common.PI;
+    if(lon > Proj4js.common.PI) lon= Proj4js.common.PI;
+    arg = (2.0 * theta + Math.sin(2.0 * theta)) / Proj4js.common.PI;
+    if(Math.abs(arg) > 1.0)arg=1.0;
+    var lat = Math.asin(arg);
+    //return(OK);
+
+    p.x=lon;
+    p.y=lat;
+    return p;
+  }
+};
+

Modified: branches/fusion-2.2/lib/proj4js-compressed.js
===================================================================
--- branches/fusion-2.2/lib/proj4js-compressed.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/lib/proj4js-compressed.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -9,7 +9,8 @@
                 Note: This program is an almost direct port of the C library
                 Proj4.
 */
-Proj4js={defaultDatum:'WGS84',transform:function(source,dest,point){if(!source.readyToUse||!dest.readyToUse){this.reportError("Proj4js initialization for "+source.srsCode+" not yet complete");return point;}
+Proj4js={defaultDatum:'WGS84',transform:function(source,dest,point){if(!source.readyToUse){this.reportError("Proj4js initialization for:"+source.srsCode+" not yet complete");return point;}
+if(!dest.readyToUse){this.reportError("Proj4js initialization for:"+dest.srsCode+" not yet complete");return point;}
 if((source.srsProjNumber=="900913"&&dest.datumCode!="WGS84")||(dest.srsProjNumber=="900913"&&source.datumCode!="WGS84")){var wgs84=Proj4js.WGS84;this.transform(source,wgs84,point);source=wgs84;}
 if(source.projName=="longlat"){point.x*=Proj4js.common.D2R;point.y*=Proj4js.common.D2R;}else{if(source.to_meter){point.x*=source.to_meter;point.y*=source.to_meter;}
 source.inverse(point);}
@@ -33,17 +34,25 @@
 Proj4js.extend(extended,parent);}
 Class.prototype=extended;return Class;},bind:function(func,object){var args=Array.prototype.slice.apply(arguments,[2]);return function(){var newArgs=args.concat(Array.prototype.slice.apply(arguments,[0]));return func.apply(object,newArgs);};},scriptName:"proj4js-compressed.js",defsLookupService:'http://spatialreference.org/ref',libPath:null,getScriptLocation:function(){if(this.libPath)return this.libPath;var scriptName=this.scriptName;var scriptNameLen=scriptName.length;var scripts=document.getElementsByTagName('script');for(var i=0;i<scripts.length;i++){var src=scripts[i].getAttribute('src');if(src){var index=src.lastIndexOf(scriptName);if((index>-1)&&(index+scriptNameLen==src.length)){this.libPath=src.slice(0,-scriptNameLen);break;}}}
 return this.libPath||"";},loadScript:function(url,onload,onfail,loadCheck){var script=document.createElement('script');script.defer=false;script.type="text/javascript";script.id=url;script.src=url;script.onload=onload;script.onerror=onfail;script.loadCheck=loadCheck;if(/MSIE/.test(navigator.userAgent)){script.onreadystatechange=this.checkReadyState;}
-document.getElementsByTagName('head')[0].appendChild(script);},checkReadyState:function(){if(this.readyState=='loaded'){if(!this.loadCheck()){this.onerror();}else{this.onload();}}}};Proj4js.Proj=Proj4js.Class({readyToUse:false,title:null,projName:null,units:null,datum:null,x0:0,y0:0,initialize:function(srsCode){this.srsCodeInput=srsCode;if(srsCode.indexOf('urn:')==0){var urn=srsCode.split(':');if((urn[1]=='ogc'||urn[1]=='x-ogc')&&(urn[2]=='def')&&(urn[3]=='crs')){srsCode=urn[4]+':'+urn[urn.length-1];}}else if(srsCode.indexOf('http://')==0){var url=srsCode.split('#');if(url[0].match(/epsg.org/)){srsCode='EPSG:'+url[1];}else if(url[0].match(/RIG.xml/)){srsCode='IGNF:'+url[1];}}
+document.getElementsByTagName('head')[0].appendChild(script);},checkReadyState:function(){if(this.readyState=='loaded'){if(!this.loadCheck()){this.onerror();}else{this.onload();}}}};Proj4js.Proj=Proj4js.Class({readyToUse:false,title:null,projName:null,units:null,datum:null,x0:0,y0:0,localCS:false,initialize:function(srsCode){this.srsCodeInput=srsCode;if((srsCode.indexOf('GEOGCS')>=0)||(srsCode.indexOf('GEOCCS')>=0)||(srsCode.indexOf('PROJCS')>=0)||(srsCode.indexOf('LOCAL_CS')>=0)){this.parseWKT(srsCode);this.datum=new Proj4js.datum(this);this.loadProjCode(this.projName);return;}
+if(srsCode.indexOf('urn:')==0){var urn=srsCode.split(':');if((urn[1]=='ogc'||urn[1]=='x-ogc')&&(urn[2]=='def')&&(urn[3]=='crs')){srsCode=urn[4]+':'+urn[urn.length-1];}}else if(srsCode.indexOf('http://')==0){var url=srsCode.split('#');if(url[0].match(/epsg.org/)){srsCode='EPSG:'+url[1];}else if(url[0].match(/RIG.xml/)){srsCode='IGNF:'+url[1];}}
 this.srsCode=srsCode.toUpperCase();if(this.srsCode.indexOf("EPSG")==0){this.srsCode=this.srsCode;this.srsAuth='epsg';this.srsProjNumber=this.srsCode.substring(5);}else if(this.srsCode.indexOf("IGNF")==0){this.srsCode=this.srsCode;this.srsAuth='IGNF';this.srsProjNumber=this.srsCode.substring(5);}else if(this.srsCode.indexOf("CRS")==0){this.srsCode=this.srsCode;this.srsAuth='CRS';this.srsProjNumber=this.srsCode.substring(4);}else{this.srsAuth='';this.srsProjNumber=this.srsCode;}
 this.loadProjDefinition();},loadProjDefinition:function(){if(Proj4js.defs[this.srsCode]){this.defsLoaded();return;}
 var url=Proj4js.getScriptLocation()+'defs/'+this.srsAuth.toUpperCase()+this.srsProjNumber+'.js';Proj4js.loadScript(url,Proj4js.bind(this.defsLoaded,this),Proj4js.bind(this.loadFromService,this),Proj4js.bind(this.checkDefsLoaded,this));},loadFromService:function(){var url=Proj4js.defsLookupService+'/'+this.srsAuth+'/'+this.srsProjNumber+'/proj4js/';Proj4js.loadScript(url,Proj4js.bind(this.defsLoaded,this),Proj4js.bind(this.defsFailed,this),Proj4js.bind(this.checkDefsLoaded,this));},defsLoaded:function(){this.parseDefs();this.loadProjCode(this.projName);},checkDefsLoaded:function(){if(Proj4js.defs[this.srsCode]){return true;}else{return false;}},defsFailed:function(){Proj4js.reportError('failed to load projection definition for: '+this.srsCode);Proj4js.defs[this.srsCode]=Proj4js.defs['WGS84'];this.defsLoaded();},loadProjCode:function(projName){if(Proj4js.Proj[projName]){this.initTransforms();return;}
-var url=Proj4js.getScriptLocation()+'projCode/'+projName+'.js';Proj4js.loadScript(url,Proj4js.bind(this.loadProjCodeSuccess,this,projName),Proj4js.bind(this.loadProjCodeFailure,this,projName),Proj4js.bind(this.checkCodeLoaded,this,projName));},loadProjCodeSuccess:function(projName){if(Proj4js.Proj[projName].dependsOn){this.loadProjCode(Proj4js.Proj[projName].dependsOn);}else{this.initTransforms();}},loadProjCodeFailure:function(projName){Proj4js.reportError("failed to find projection file for: "+projName);},checkCodeLoaded:function(projName){if(Proj4js.Proj[projName]){return true;}else{return false;}},initTransforms:function(){Proj4js.extend(this,Proj4js.Proj[this.projName]);this.init();this.readyToUse=true;},parseDefs:function(){this.defData=Proj4js.defs[this.srsCode];var paramName,paramVal;if(!this.defData){return;}
+var url=Proj4js.getScriptLocation()+'projCode/'+projName+'.js';Proj4js.loadScript(url,Proj4js.bind(this.loadProjCodeSuccess,this,projName),Proj4js.bind(this.loadProjCodeFailure,this,projName),Proj4js.bind(this.checkCodeLoaded,this,projName));},loadProjCodeSuccess:function(projName){if(Proj4js.Proj[projName].dependsOn){this.loadProjCode(Proj4js.Proj[projName].dependsOn);}else{this.initTransforms();}},loadProjCodeFailure:function(projName){Proj4js.reportError("failed to find projection file for: "+projName);},checkCodeLoaded:function(projName){if(Proj4js.Proj[projName]){return true;}else{return false;}},initTransforms:function(){Proj4js.extend(this,Proj4js.Proj[this.projName]);this.init();this.readyToUse=true;},wktRE:/^(\w+)\[(.*)\]$/,parseWKT:function(wkt){var wktMatch=wkt.match(this.wktRE);if(!wktMatch)return;var wktObject=wktMatch[1];var wktContent=wktMatch[2];var wktTemp=wktContent.split(",");var wktName=wktTemp.shift();wktName=wktName.replace(/^\"/,"");wktName=wktName.rep
 lace(/\"$/,"");var wktArray=new Array();var bkCount=0;var obj="";for(var i=0;i<wktTemp.length;++i){var token=wktTemp[i];for(var j=0;j<token.length;++j){if(token.charAt(j)=="[")++bkCount;if(token.charAt(j)=="]")--bkCount;}
+obj+=token;if(bkCount===0){wktArray.push(obj);obj="";}else{obj+=",";}}
+switch(wktObject){case'LOCAL_CS':this.projName='identity'
+this.localCS=true;this.srsCode=wktName;break;case'GEOGCS':this.projName='longlat'
+this.geocsCode=wktName;if(!this.srsCode)this.srsCode=wktName;break;case'PROJCS':this.srsCode=wktName;break;case'GEOCCS':break;case'PROJECTION':this.projName=Proj4js.wktProjections[wktName]
+break;case'DATUM':this.datumName=wktName;break;case'LOCAL_DATUM':this.datumCode='none';break;case'SPHEROID':this.ellps=wktName;this.a=parseFloat(wktArray.shift());this.rf=parseFloat(wktArray.shift());break;case'PRIMEM':this.from_greenwich=parseFloat(wktArray.shift());break;case'UNIT':this.units=wktName;this.unitsPerMeter=parseFloat(wktArray.shift());break;case'PARAMETER':var name=wktName;var value=parseFloat(parseFloat(wktArray.shift()));switch(name){case'false_easting':this.x0=value;break;case'false_northing':this.y0=value;break;case'scale_factor':this.k0=value;break;case'central_meridian':this.long0=value;break;case'latitude_of_origin':this.lat0=value;break;case'more_here':break;default:break;}
+break;case'TOWGS84':this.datum_params=wktArray;break;case'MORE_HERE':break;default:break;}
+for(var i=0;i<wktArray.length;++i){this.parseWKT(wktArray[i]);}},parseDefs:function(){this.defData=Proj4js.defs[this.srsCode];var paramName,paramVal;if(!this.defData){return;}
 var paramArray=this.defData.split("+");for(var prop=0;prop<paramArray.length;prop++){var property=paramArray[prop].split("=");paramName=property[0].toLowerCase();paramVal=property[1];switch(paramName.replace(/\s/gi,"")){case"":break;case"title":this.title=paramVal;break;case"proj":this.projName=paramVal.replace(/\s/gi,"");break;case"units":this.units=paramVal.replace(/\s/gi,"");break;case"datum":this.datumCode=paramVal.replace(/\s/gi,"");break;case"nadgrids":this.nagrids=paramVal.replace(/\s/gi,"");break;case"ellps":this.ellps=paramVal.replace(/\s/gi,"");break;case"a":this.a=parseFloat(paramVal);break;case"b":this.b=parseFloat(paramVal);break;case"rf":this.rf=parseFloat(paramVal);break;case"lat_0":this.lat0=paramVal*Proj4js.common.D2R;break;case"lat_1":this.lat1=paramVal*Proj4js.common.D2R;break;case"lat_2":this.lat2=paramVal*Proj4js.common.D2R;break;case"lat_ts":this.lat_ts=paramVal*Proj4js.common.D2R;break;case"lon_0":this.long0=paramVal*Proj4js.common.D2R;break;case"alpha
 ":this.alpha=parseFloat(paramVal)*Proj4js.common.D2R;break;case"lonc":this.longc=paramVal*Proj4js.common.D2R;break;case"x_0":this.x0=parseFloat(paramVal);break;case"y_0":this.y0=parseFloat(paramVal);break;case"k_0":this.k0=parseFloat(paramVal);break;case"k":this.k0=parseFloat(paramVal);break;case"r_a":this.R_A=true;break;case"zone":this.zone=parseInt(paramVal);break;case"south":this.utmSouth=true;break;case"towgs84":this.datum_params=paramVal.split(",");break;case"to_meter":this.to_meter=parseFloat(paramVal);break;case"from_greenwich":this.from_greenwich=paramVal*Proj4js.common.D2R;break;case"pm":paramVal=paramVal.replace(/\s/gi,"");this.from_greenwich=Proj4js.PrimeMeridian[paramVal]?Proj4js.PrimeMeridian[paramVal]:parseFloat(paramVal);this.from_greenwich*=Proj4js.common.D2R;break;case"no_defs":break;default:}}
 this.deriveConstants();},deriveConstants:function(){if(this.nagrids=='@null')this.datumCode='none';if(this.datumCode&&this.datumCode!='none'){var datumDef=Proj4js.Datum[this.datumCode];if(datumDef){this.datum_params=datumDef.towgs84?datumDef.towgs84.split(','):null;this.ellps=datumDef.ellipse;this.datumName=datumDef.datumName?datumDef.datumName:this.datumCode;}}
 if(!this.a){var ellipse=Proj4js.Ellipsoid[this.ellps]?Proj4js.Ellipsoid[this.ellps]:Proj4js.Ellipsoid['WGS84'];Proj4js.extend(this,ellipse);}
 if(this.rf&&!this.b)this.b=(1.0-1.0/this.rf)*this.a;if(Math.abs(this.a-this.b)<Proj4js.common.EPSLN){this.sphere=true;this.b=this.a;}
 this.a2=this.a*this.a;this.b2=this.b*this.b;this.es=(this.a2-this.b2)/this.a2;this.e=Math.sqrt(this.es);if(this.R_A){this.a*=1.-this.es*(Proj4js.common.SIXTH+this.es*(Proj4js.common.RA4+this.es*Proj4js.common.RA6));this.a2=this.a*this.a;this.b2=this.b*this.b;this.es=0.;}
-this.ep2=(this.a2-this.b2)/this.b2;if(!this.k0)this.k0=1.0;this.datum=new Proj4js.datum(this);}});Proj4js.Proj.longlat={init:function(){},forward:function(pt){return pt;},inverse:function(pt){return pt;}};Proj4js.Proj.identity=Proj4js.Proj.longlat;Proj4js.defs={'WGS84':"+title=long/lat:WGS84 +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees",'EPSG:4326':"+title=long/lat:WGS84 +proj=longlat +a=6378137.0 +b=6356752.31424518 +ellps=WGS84 +datum=WGS84 +units=degrees",'EPSG:4269':"+title=long/lat:NAD83 +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees",'EPSG:3785':"+title= Google Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"};Proj4js.defs['GOOGLE']=Proj4js.defs['EPSG:3785'];Proj4js.defs['EPSG:900913']=Proj4js.defs['EPSG:3785'];Proj4js.defs['EPSG:102113']=Proj4js.defs['EPSG:3785'];Proj4js.common={PI:3.141592653589793238,HALF_PI:1.570796326794896619,TWO_PI:6.28318
 5307179586477,FORTPI:0.78539816339744833,R2D:57.29577951308232088,D2R:0.01745329251994329577,SEC_TO_RAD:4.84813681109535993589914102357e-6,EPSLN:1.0e-10,MAX_ITER:20,COS_67P5:0.38268343236508977,AD_C:1.0026000,PJD_UNKNOWN:0,PJD_3PARAM:1,PJD_7PARAM:2,PJD_GRIDSHIFT:3,PJD_WGS84:4,PJD_NODATUM:5,SRS_WGS84_SEMIMAJOR:6378137.0,SIXTH:.1666666666666666667,RA4:.04722222222222222222,RA6:.02215608465608465608,RV4:.06944444444444444444,RV6:.04243827160493827160,msfnz:function(eccent,sinphi,cosphi){var con=eccent*sinphi;return cosphi/(Math.sqrt(1.0-con*con));},tsfnz:function(eccent,phi,sinphi){var con=eccent*sinphi;var com=.5*eccent;con=Math.pow(((1.0-con)/(1.0+con)),com);return(Math.tan(.5*(this.HALF_PI-phi))/con);},phi2z:function(eccent,ts){var eccnth=.5*eccent;var con,dphi;var phi=this.HALF_PI-2*Math.atan(ts);for(i=0;i<=15;i++){con=eccent*Math.sin(phi);dphi=this.HALF_PI-2*Math.atan(ts*(Math.pow(((1.0-con)/(1.0+con)),eccnth)))-phi;phi+=dphi;if(Math.abs(dphi)<=.0000000001)return phi;}
+this.ep2=(this.a2-this.b2)/this.b2;if(!this.k0)this.k0=1.0;this.datum=new Proj4js.datum(this);}});Proj4js.Proj.longlat={init:function(){},forward:function(pt){return pt;},inverse:function(pt){return pt;}};Proj4js.Proj.identity=Proj4js.Proj.longlat;Proj4js.defs={'WGS84':"+title=long/lat:WGS84 +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees",'EPSG:4326':"+title=long/lat:WGS84 +proj=longlat +a=6378137.0 +b=6356752.31424518 +ellps=WGS84 +datum=WGS84 +units=degrees",'EPSG:4269':"+title=long/lat:NAD83 +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees",'EPSG:3785':"+title= Google Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"};Proj4js.defs['GOOGLE']=Proj4js.defs['EPSG:3785'];Proj4js.defs['EPSG:900913']=Proj4js.defs['EPSG:3785'];Proj4js.defs['EPSG:102113']=Proj4js.defs['EPSG:3785'];Proj4js.common={PI:3.141592653589793238,HALF_PI:1.570796326794896619,TWO_PI:6.28318
 5307179586477,FORTPI:0.78539816339744833,R2D:57.29577951308232088,D2R:0.01745329251994329577,SEC_TO_RAD:4.84813681109535993589914102357e-6,EPSLN:1.0e-10,MAX_ITER:20,COS_67P5:0.38268343236508977,AD_C:1.0026000,PJD_UNKNOWN:0,PJD_3PARAM:1,PJD_7PARAM:2,PJD_GRIDSHIFT:3,PJD_WGS84:4,PJD_NODATUM:5,SRS_WGS84_SEMIMAJOR:6378137.0,SIXTH:.1666666666666666667,RA4:.04722222222222222222,RA6:.02215608465608465608,RV4:.06944444444444444444,RV6:.04243827160493827160,msfnz:function(eccent,sinphi,cosphi){var con=eccent*sinphi;return cosphi/(Math.sqrt(1.0-con*con));},tsfnz:function(eccent,phi,sinphi){var con=eccent*sinphi;var com=.5*eccent;con=Math.pow(((1.0-con)/(1.0+con)),com);return(Math.tan(.5*(this.HALF_PI-phi))/con);},phi2z:function(eccent,ts){var eccnth=.5*eccent;var con,dphi;var phi=this.HALF_PI-2*Math.atan(ts);for(var i=0;i<=15;i++){con=eccent*Math.sin(phi);dphi=this.HALF_PI-2*Math.atan(ts*(Math.pow(((1.0-con)/(1.0+con)),eccnth)))-phi;phi+=dphi;if(Math.abs(dphi)<=.0000000001)return phi;}
 alert("phi2z has NoConvergence");return(-9999);},qsfnz:function(eccent,sinphi){var con;if(eccent>1.0e-7){con=eccent*sinphi;return((1.0-eccent*eccent)*(sinphi/(1.0-con*con)-(.5/eccent)*Math.log((1.0-con)/(1.0+con))));}else{return(2.0*sinphi);}},asinz:function(x){if(Math.abs(x)>1.0){x=(x>1.0)?1.0:-1.0;}
 return Math.asin(x);},e0fn:function(x){return(1.0-0.25*x*(1.0+x/16.0*(3.0+1.25*x)));},e1fn:function(x){return(0.375*x*(1.0+0.25*x*(1.0+0.46875*x)));},e2fn:function(x){return(0.05859375*x*x*(1.0+0.75*x));},e3fn:function(x){return(x*x*x*(35.0/3072.0));},mlfn:function(e0,e1,e2,e3,phi){return(e0*phi-e1*Math.sin(2.0*phi)+e2*Math.sin(4.0*phi)-e3*Math.sin(6.0*phi));},srat:function(esinp,exp){return(Math.pow((1.0-esinp)/(1.0+esinp),exp));},sign:function(x){if(x<0.0)return(-1);else return(1);},adjust_lon:function(x){x=(Math.abs(x)<this.PI)?x:(x-(this.sign(x)*this.TWO_PI));return x;},adjust_lat:function(x){x=(Math.abs(x)<this.HALF_PI)?x:(x-(this.sign(x)*this.PI));return x;},latiso:function(eccent,phi,sinphi){if(Math.abs(phi)>this.HALF_PI)return+Number.NaN;if(phi==this.HALF_PI)return Number.POSITIVE_INFINITY;if(phi==-1.0*this.HALF_PI)return-1.0*Number.POSITIVE_INFINITY;var con=eccent*sinphi;return Math.log(Math.tan((this.HALF_PI+phi)/2.0))+eccent*Math.log((1.0-con)/(1.0+con))/2.0;},fL:
 function(x,L){return 2.0*Math.atan(x*Math.exp(L))-this.HALF_PI;},invlatiso:function(eccent,ts){var phi=this.fL(1.0,ts);var Iphi=0.0;var con=0.0;do{Iphi=phi;con=eccent*Math.sin(Iphi);phi=this.fL(Math.exp(eccent*Math.log((1.0+con)/(1.0-con))/2.0),ts)}while(Math.abs(phi-Iphi)>1.0e-12);return phi;},sinh:function(x)
 {var r=Math.exp(x);r=(r-1.0/r)/2.0;return r;},cosh:function(x)
@@ -88,7 +97,7 @@
 {var Dx_BF=this.datum_params[0];var Dy_BF=this.datum_params[1];var Dz_BF=this.datum_params[2];var Rx_BF=this.datum_params[3];var Ry_BF=this.datum_params[4];var Rz_BF=this.datum_params[5];var M_BF=this.datum_params[6];var x_out=M_BF*(p.x-Rz_BF*p.y+Ry_BF*p.z)+Dx_BF;var y_out=M_BF*(Rz_BF*p.x+p.y-Rx_BF*p.z)+Dy_BF;var z_out=M_BF*(-Ry_BF*p.x+Rx_BF*p.y+p.z)+Dz_BF;p.x=x_out;p.y=y_out;p.z=z_out;}},geocentric_from_wgs84:function(p){if(this.datum_type==Proj4js.common.PJD_3PARAM)
 {p.x-=this.datum_params[0];p.y-=this.datum_params[1];p.z-=this.datum_params[2];}
 else if(this.datum_type==Proj4js.common.PJD_7PARAM)
-{var Dx_BF=this.datum_params[0];var Dy_BF=this.datum_params[1];var Dz_BF=this.datum_params[2];var Rx_BF=this.datum_params[3];var Ry_BF=this.datum_params[4];var Rz_BF=this.datum_params[5];var M_BF=this.datum_params[6];var x_tmp=(p.x-Dx_BF)/M_BF;var y_tmp=(p.y-Dy_BF)/M_BF;var z_tmp=(p.z-Dz_BF)/M_BF;p.x=x_tmp+Rz_BF*y_tmp-Ry_BF*z_tmp;p.y=-Rz_BF*x_tmp+y_tmp+Rx_BF*z_tmp;p.z=Ry_BF*x_tmp-Rx_BF*y_tmp+z_tmp;}}});Proj4js.Point=Proj4js.Class({initialize:function(x,y,z){if(typeof x=='object'){this.x=x[0];this.y=x[1];this.z=x[2]||0.0;}else if(typeof x=='string'){var coords=x.split(',');this.x=parseFloat(coords[0]);this.y=parseFloat(coords[1]);this.z=parseFloat(coords[2])||0.0;}else{this.x=x;this.y=y;this.z=z||0.0;}},clone:function(){return new Proj4js.Point(this.x,this.y,this.z);},toString:function(){return("x="+this.x+",y="+this.y);},toShortString:function(){return(this.x+", "+this.y);}});Proj4js.PrimeMeridian={"greenwich":0.0,"lisbon":-9.131906111111,"paris":2.337229166667,"bogota":-74.
 080916666667,"madrid":-3.687938888889,"rome":12.452333333333,"bern":7.439583333333,"jakarta":106.807719444444,"ferro":-17.666666666667,"brussels":4.367975,"stockholm":18.058277777778,"athens":23.7163375,"oslo":10.722916666667};Proj4js.Ellipsoid={"MERIT":{a:6378137.0,rf:298.257,ellipseName:"MERIT 1983"},"SGS85":{a:6378136.0,rf:298.257,ellipseName:"Soviet Geodetic System 85"},"GRS80":{a:6378137.0,rf:298.257222101,ellipseName:"GRS 1980(IUGG, 1980)"},"IAU76":{a:6378140.0,rf:298.257,ellipseName:"IAU 1976"},"airy":{a:6377563.396,b:6356256.910,ellipseName:"Airy 1830"},"APL4.":{a:6378137,rf:298.25,ellipseName:"Appl. Physics. 1965"},"NWL9D":{a:6378145.0,rf:298.25,ellipseName:"Naval Weapons Lab., 1965"},"mod_airy":{a:6377340.189,b:6356034.446,ellipseName:"Modified Airy"},"andrae":{a:6377104.43,rf:300.0,ellipseName:"Andrae 1876 (Den., Iclnd.)"},"aust_SA":{a:6378160.0,rf:298.25,ellipseName:"Australian Natl & S. Amer. 1969"},"GRS67":{a:6378160.0,rf:298.2471674270,ellipseName:"GRS 67(IUGG
  1967)"},"bessel":{a:6377397.155,rf:299.1528128,ellipseName:"Bessel 1841"},"bess_nam":{a:6377483.865,rf:299.1528128,ellipseName:"Bessel 1841 (Namibia)"},"clrk66":{a:6378206.4,b:6356583.8,ellipseName:"Clarke 1866"},"clrk80":{a:6378249.145,rf:293.4663,ellipseName:"Clarke 1880 mod."},"CPM":{a:6375738.7,rf:334.29,ellipseName:"Comm. des Poids et Mesures 1799"},"delmbr":{a:6376428.0,rf:311.5,ellipseName:"Delambre 1810 (Belgium)"},"engelis":{a:6378136.05,rf:298.2566,ellipseName:"Engelis 1985"},"evrst30":{a:6377276.345,rf:300.8017,ellipseName:"Everest 1830"},"evrst48":{a:6377304.063,rf:300.8017,ellipseName:"Everest 1948"},"evrst56":{a:6377301.243,rf:300.8017,ellipseName:"Everest 1956"},"evrst69":{a:6377295.664,rf:300.8017,ellipseName:"Everest 1969"},"evrstSS":{a:6377298.556,rf:300.8017,ellipseName:"Everest (Sabah & Sarawak)"},"fschr60":{a:6378166.0,rf:298.3,ellipseName:"Fischer (Mercury Datum) 1960"},"fschr60m":{a:6378155.0,rf:298.3,ellipseName:"Fischer 1960"},"fschr68":{a:6378150.0
 ,rf:298.3,ellipseName:"Fischer 1968"},"helmert":{a:6378200.0,rf:298.3,ellipseName:"Helmert 1906"},"hough":{a:6378270.0,rf:297.0,ellipseName:"Hough"},"intl":{a:6378388.0,rf:297.0,ellipseName:"International 1909 (Hayford)"},"kaula":{a:6378163.0,rf:298.24,ellipseName:"Kaula 1961"},"lerch":{a:6378139.0,rf:298.257,ellipseName:"Lerch 1979"},"mprts":{a:6397300.0,rf:191.0,ellipseName:"Maupertius 1738"},"new_intl":{a:6378157.5,b:6356772.2,ellipseName:"New International 1967"},"plessis":{a:6376523.0,rf:6355863.0,ellipseName:"Plessis 1817 (France)"},"krass":{a:6378245.0,rf:298.3,ellipseName:"Krassovsky, 1942"},"SEasia":{a:6378155.0,b:6356773.3205,ellipseName:"Southeast Asia"},"walbeck":{a:6376896.0,b:6355834.8467,ellipseName:"Walbeck"},"WGS60":{a:6378165.0,rf:298.3,ellipseName:"WGS 60"},"WGS66":{a:6378145.0,rf:298.25,ellipseName:"WGS 66"},"WGS72":{a:6378135.0,rf:298.26,ellipseName:"WGS 72"},"WGS84":{a:6378137.0,rf:298.257223563,ellipseName:"WGS 84"},"sphere":{a:6370997.0,b:6370997.0,el
 lipseName:"Normal Sphere (r=6370997)"}};Proj4js.Datum={"WGS84":{towgs84:"0,0,0",ellipse:"WGS84",datumName:"WGS84"},"GGRS87":{towgs84:"-199.87,74.79,246.62",ellipse:"GRS80",datumName:"Greek_Geodetic_Reference_System_1987"},"NAD83":{towgs84:"0,0,0",ellipse:"GRS80",datumName:"North_American_Datum_1983"},"NAD27":{nadgrids:"@conus, at alaska, at ntv2_0.gsb, at ntv1_can.dat",ellipse:"clrk66",datumName:"North_American_Datum_1927"},"potsdam":{towgs84:"606.0,23.0,413.0",ellipse:"bessel",datumName:"Potsdam Rauenberg 1950 DHDN"},"carthage":{towgs84:"-263.0,6.0,431.0",ellipse:"clark80",datumName:"Carthage 1934 Tunisia"},"hermannskogel":{towgs84:"653.0,-212.0,449.0",ellipse:"bessel",datumName:"Hermannskogel"},"ire65":{towgs84:"482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",ellipse:"mod_airy",datumName:"Ireland 1965"},"nzgd49":{towgs84:"59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993",ellipse:"intl",datumName:"New Zealand Geodetic Datum 1949"},"OSGB36":{towgs84:"446.448,-125.157,542.060,0.1502,0.2
 470,0.8421,-20.4894",ellipse:"airy",datumName:"Airy 1830"}};Proj4js.WGS84=new Proj4js.Proj('WGS84');Proj4js.Datum['OSB36']=Proj4js.Datum['OSGB36'];Proj4js.Proj.aea={init:function(){if(Math.abs(this.lat1+this.lat2)<Proj4js.common.EPSLN){Proj4js.reportError("aeaInitEqualLatitudes");return;}
+{var Dx_BF=this.datum_params[0];var Dy_BF=this.datum_params[1];var Dz_BF=this.datum_params[2];var Rx_BF=this.datum_params[3];var Ry_BF=this.datum_params[4];var Rz_BF=this.datum_params[5];var M_BF=this.datum_params[6];var x_tmp=(p.x-Dx_BF)/M_BF;var y_tmp=(p.y-Dy_BF)/M_BF;var z_tmp=(p.z-Dz_BF)/M_BF;p.x=x_tmp+Rz_BF*y_tmp-Ry_BF*z_tmp;p.y=-Rz_BF*x_tmp+y_tmp+Rx_BF*z_tmp;p.z=Ry_BF*x_tmp-Rx_BF*y_tmp+z_tmp;}}});Proj4js.Point=Proj4js.Class({initialize:function(x,y,z){if(typeof x=='object'){this.x=x[0];this.y=x[1];this.z=x[2]||0.0;}else if(typeof x=='string'){var coords=x.split(',');this.x=parseFloat(coords[0]);this.y=parseFloat(coords[1]);this.z=parseFloat(coords[2])||0.0;}else{this.x=x;this.y=y;this.z=z||0.0;}},clone:function(){return new Proj4js.Point(this.x,this.y,this.z);},toString:function(){return("x="+this.x+",y="+this.y);},toShortString:function(){return(this.x+", "+this.y);}});Proj4js.PrimeMeridian={"greenwich":0.0,"lisbon":-9.131906111111,"paris":2.337229166667,"bogota":-74.
 080916666667,"madrid":-3.687938888889,"rome":12.452333333333,"bern":7.439583333333,"jakarta":106.807719444444,"ferro":-17.666666666667,"brussels":4.367975,"stockholm":18.058277777778,"athens":23.7163375,"oslo":10.722916666667};Proj4js.Ellipsoid={"MERIT":{a:6378137.0,rf:298.257,ellipseName:"MERIT 1983"},"SGS85":{a:6378136.0,rf:298.257,ellipseName:"Soviet Geodetic System 85"},"GRS80":{a:6378137.0,rf:298.257222101,ellipseName:"GRS 1980(IUGG, 1980)"},"IAU76":{a:6378140.0,rf:298.257,ellipseName:"IAU 1976"},"airy":{a:6377563.396,b:6356256.910,ellipseName:"Airy 1830"},"APL4.":{a:6378137,rf:298.25,ellipseName:"Appl. Physics. 1965"},"NWL9D":{a:6378145.0,rf:298.25,ellipseName:"Naval Weapons Lab., 1965"},"mod_airy":{a:6377340.189,b:6356034.446,ellipseName:"Modified Airy"},"andrae":{a:6377104.43,rf:300.0,ellipseName:"Andrae 1876 (Den., Iclnd.)"},"aust_SA":{a:6378160.0,rf:298.25,ellipseName:"Australian Natl & S. Amer. 1969"},"GRS67":{a:6378160.0,rf:298.2471674270,ellipseName:"GRS 67(IUGG
  1967)"},"bessel":{a:6377397.155,rf:299.1528128,ellipseName:"Bessel 1841"},"bess_nam":{a:6377483.865,rf:299.1528128,ellipseName:"Bessel 1841 (Namibia)"},"clrk66":{a:6378206.4,b:6356583.8,ellipseName:"Clarke 1866"},"clrk80":{a:6378249.145,rf:293.4663,ellipseName:"Clarke 1880 mod."},"CPM":{a:6375738.7,rf:334.29,ellipseName:"Comm. des Poids et Mesures 1799"},"delmbr":{a:6376428.0,rf:311.5,ellipseName:"Delambre 1810 (Belgium)"},"engelis":{a:6378136.05,rf:298.2566,ellipseName:"Engelis 1985"},"evrst30":{a:6377276.345,rf:300.8017,ellipseName:"Everest 1830"},"evrst48":{a:6377304.063,rf:300.8017,ellipseName:"Everest 1948"},"evrst56":{a:6377301.243,rf:300.8017,ellipseName:"Everest 1956"},"evrst69":{a:6377295.664,rf:300.8017,ellipseName:"Everest 1969"},"evrstSS":{a:6377298.556,rf:300.8017,ellipseName:"Everest (Sabah & Sarawak)"},"fschr60":{a:6378166.0,rf:298.3,ellipseName:"Fischer (Mercury Datum) 1960"},"fschr60m":{a:6378155.0,rf:298.3,ellipseName:"Fischer 1960"},"fschr68":{a:6378150.0
 ,rf:298.3,ellipseName:"Fischer 1968"},"helmert":{a:6378200.0,rf:298.3,ellipseName:"Helmert 1906"},"hough":{a:6378270.0,rf:297.0,ellipseName:"Hough"},"intl":{a:6378388.0,rf:297.0,ellipseName:"International 1909 (Hayford)"},"kaula":{a:6378163.0,rf:298.24,ellipseName:"Kaula 1961"},"lerch":{a:6378139.0,rf:298.257,ellipseName:"Lerch 1979"},"mprts":{a:6397300.0,rf:191.0,ellipseName:"Maupertius 1738"},"new_intl":{a:6378157.5,b:6356772.2,ellipseName:"New International 1967"},"plessis":{a:6376523.0,rf:6355863.0,ellipseName:"Plessis 1817 (France)"},"krass":{a:6378245.0,rf:298.3,ellipseName:"Krassovsky, 1942"},"SEasia":{a:6378155.0,b:6356773.3205,ellipseName:"Southeast Asia"},"walbeck":{a:6376896.0,b:6355834.8467,ellipseName:"Walbeck"},"WGS60":{a:6378165.0,rf:298.3,ellipseName:"WGS 60"},"WGS66":{a:6378145.0,rf:298.25,ellipseName:"WGS 66"},"WGS72":{a:6378135.0,rf:298.26,ellipseName:"WGS 72"},"WGS84":{a:6378137.0,rf:298.257223563,ellipseName:"WGS 84"},"sphere":{a:6370997.0,b:6370997.0,el
 lipseName:"Normal Sphere (r=6370997)"}};Proj4js.Datum={"WGS84":{towgs84:"0,0,0",ellipse:"WGS84",datumName:"WGS84"},"GGRS87":{towgs84:"-199.87,74.79,246.62",ellipse:"GRS80",datumName:"Greek_Geodetic_Reference_System_1987"},"NAD83":{towgs84:"0,0,0",ellipse:"GRS80",datumName:"North_American_Datum_1983"},"NAD27":{nadgrids:"@conus, at alaska, at ntv2_0.gsb, at ntv1_can.dat",ellipse:"clrk66",datumName:"North_American_Datum_1927"},"potsdam":{towgs84:"606.0,23.0,413.0",ellipse:"bessel",datumName:"Potsdam Rauenberg 1950 DHDN"},"carthage":{towgs84:"-263.0,6.0,431.0",ellipse:"clark80",datumName:"Carthage 1934 Tunisia"},"hermannskogel":{towgs84:"653.0,-212.0,449.0",ellipse:"bessel",datumName:"Hermannskogel"},"ire65":{towgs84:"482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",ellipse:"mod_airy",datumName:"Ireland 1965"},"nzgd49":{towgs84:"59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993",ellipse:"intl",datumName:"New Zealand Geodetic Datum 1949"},"OSGB36":{towgs84:"446.448,-125.157,542.060,0.1502,0.2
 470,0.8421,-20.4894",ellipse:"airy",datumName:"Airy 1830"}};Proj4js.WGS84=new Proj4js.Proj('WGS84');Proj4js.Datum['OSB36']=Proj4js.Datum['OSGB36'];Proj4js.wktProjections={"Lambert Tangential Conformal Conic Projection":"lcc","Mercator":"merc","Transverse_Mercator":"tmerc","Transverse Mercator":"tmerc","Lambert Azimuthal Equal Area":"laea","Universal Transverse Mercator System":"utm"};Proj4js.Proj.aea={init:function(){if(Math.abs(this.lat1+this.lat2)<Proj4js.common.EPSLN){Proj4js.reportError("aeaInitEqualLatitudes");return;}
 this.temp=this.b/this.a;this.es=1.0-Math.pow(this.temp,2);this.e3=Math.sqrt(this.es);this.sin_po=Math.sin(this.lat1);this.cos_po=Math.cos(this.lat1);this.t1=this.sin_po;this.con=this.sin_po;this.ms1=Proj4js.common.msfnz(this.e3,this.sin_po,this.cos_po);this.qs1=Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);this.sin_po=Math.sin(this.lat2);this.cos_po=Math.cos(this.lat2);this.t2=this.sin_po;this.ms2=Proj4js.common.msfnz(this.e3,this.sin_po,this.cos_po);this.qs2=Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);this.sin_po=Math.sin(this.lat0);this.cos_po=Math.cos(this.lat0);this.t3=this.sin_po;this.qs0=Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);if(Math.abs(this.lat1-this.lat2)>Proj4js.common.EPSLN){this.ns0=(this.ms1*this.ms1-this.ms2*this.ms2)/(this.qs2-this.qs1);}else{this.ns0=this.con;}
 this.c=this.ms1*this.ms1+this.ns0*this.qs1;this.rh=this.a*Math.sqrt(this.c-this.ns0*this.qs0)/this.ns0;},forward:function(p){var lon=p.x;var lat=p.y;this.sin_phi=Math.sin(lat);this.cos_phi=Math.cos(lat);var qs=Proj4js.common.qsfnz(this.e3,this.sin_phi,this.cos_phi);var rh1=this.a*Math.sqrt(this.c-this.ns0*qs)/this.ns0;var theta=this.ns0*Proj4js.common.adjust_lon(lon-this.long0);var x=rh1*Math.sin(theta)+this.x0;var y=this.rh-rh1*Math.cos(theta)+this.y0;p.x=x;p.y=y;return p;},inverse:function(p){var rh1,qs,con,theta,lon,lat;p.x-=this.x0;p.y=this.rh-p.y+this.y0;if(this.ns0>=0){rh1=Math.sqrt(p.x*p.x+p.y*p.y);con=1.0;}else{rh1=-Math.sqrt(p.x*p.x+p.y*p.y);con=-1.0;}
 theta=0.0;if(rh1!=0.0){theta=Math.atan2(con*p.x,con*p.y);}
@@ -109,7 +118,7 @@
 this.lat0=0.0;this.long0=((6*Math.abs(this.zone))-183)*Proj4js.common.D2R;this.x0=500000.0;this.y0=this.utmSouth?10000000.0:0.0;this.k0=0.9996;Proj4js.Proj['tmerc'].init.apply(this);this.forward=Proj4js.Proj['tmerc'].forward;this.inverse=Proj4js.Proj['tmerc'].inverse;}};Proj4js.Proj.eqdc={init:function(){if(!this.mode)this.mode=0;this.temp=this.b/this.a;this.es=1.0-Math.pow(this.temp,2);this.e=Math.sqrt(this.es);this.e0=Proj4js.common.e0fn(this.es);this.e1=Proj4js.common.e1fn(this.es);this.e2=Proj4js.common.e2fn(this.es);this.e3=Proj4js.common.e3fn(this.es);this.sinphi=Math.sin(this.lat1);this.cosphi=Math.cos(this.lat1);this.ms1=Proj4js.common.msfnz(this.e,this.sinphi,this.cosphi);this.ml1=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat1);if(this.mode!=0){if(Math.abs(this.lat1+this.lat2)<Proj4js.common.EPSLN){Proj4js.reportError("eqdc:Init:EqualLatitudes");}
 this.sinphi=Math.sin(this.lat2);this.cosphi=Math.cos(this.lat2);this.ms2=Proj4js.common.msfnz(this.e,this.sinphi,this.cosphi);this.ml2=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat2);if(Math.abs(this.lat1-this.lat2)>=Proj4js.common.EPSLN){this.ns=(this.ms1-this.ms2)/(this.ml2-this.ml1);}else{this.ns=this.sinphi;}}else{this.ns=this.sinphi;}
 this.g=this.ml1+this.ms1/this.ns;this.ml0=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat0);this.rh=this.a*(this.g-this.ml0);},forward:function(p){var lon=p.x;var lat=p.y;var ml=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,lat);var rh1=this.a*(this.g-ml);var theta=this.ns*Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+rh1*Math.sin(theta);var y=this.y0+this.rh-rh1*Math.cos(theta);p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y=this.rh-p.y+this.y0;var con,rh1;if(this.ns>=0){var rh1=Math.sqrt(p.x*p.x+p.y*p.y);var con=1.0;}else{rh1=-Math.sqrt(p.x*p.x+p.y*p.y);con=-1.0;}
-var theta=0.0;if(rh1!=0.0)theta=Math.atan2(con*p.x,con*p.y);var ml=this.g-rh1/this.a;var lat=this.phi3z(this.ml,this.e0,this.e1,this.e2,this.e3);var lon=Proj4js.common.adjust_lon(this.long0+theta/this.ns);p.x=lon;p.y=lat;return p;},phi3z:function(ml,e0,e1,e2,e3){var phi;var dphi;phi=ml;for(var i=0;i<15;i++){dphi=(ml+e1*Math.sin(2.0*phi)-e2*Math.sin(4.0*phi)+e3*Math.sin(6.0*phi))/e0-phi;phi+=dphi;if(Math.abs(dphi)<=.0000000001){return phi;}}
+var theta=0.0;if(rh1!=0.0)theta=Math.atan2(con*p.x,con*p.y);var ml=this.g-rh1/this.a;var lat=this.phi3z(ml,this.e0,this.e1,this.e2,this.e3);var lon=Proj4js.common.adjust_lon(this.long0+theta/this.ns);p.x=lon;p.y=lat;return p;},phi3z:function(ml,e0,e1,e2,e3){var phi;var dphi;phi=ml;for(var i=0;i<15;i++){dphi=(ml+e1*Math.sin(2.0*phi)-e2*Math.sin(4.0*phi)+e3*Math.sin(6.0*phi))/e0-phi;phi+=dphi;if(Math.abs(dphi)<=.0000000001){return phi;}}
 Proj4js.reportError("PHI3Z-CONV:Latitude failed to converge after 15 iterations");return null;}};Proj4js.Proj.tmerc={init:function(){this.e0=Proj4js.common.e0fn(this.es);this.e1=Proj4js.common.e1fn(this.es);this.e2=Proj4js.common.e2fn(this.es);this.e3=Proj4js.common.e3fn(this.es);this.ml0=this.a*Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat0);},forward:function(p){var lon=p.x;var lat=p.y;var delta_lon=Proj4js.common.adjust_lon(lon-this.long0);var con;var x,y;var sin_phi=Math.sin(lat);var cos_phi=Math.cos(lat);if(this.sphere){var b=cos_phi*Math.sin(delta_lon);if((Math.abs(Math.abs(b)-1.0))<.0000000001){Proj4js.reportError("tmerc:forward: Point projects into infinity");return(93);}else{x=.5*this.a*this.k0*Math.log((1.0+b)/(1.0-b));con=Math.acos(cos_phi*Math.cos(delta_lon)/Math.sqrt(1.0-b*b));if(lat<0)con=-con;y=this.a*this.k0*(con-this.lat0);}}else{var al=cos_phi*delta_lon;var als=Math.pow(al,2);var c=this.ep2*Math.pow(cos_phi,2);var tq=Math.tan(lat);var t=Math.
 pow(tq,2);con=1.0-this.es*Math.pow(sin_phi,2);var n=this.a/Math.sqrt(con);var ml=this.a*Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,lat);x=this.k0*n*al*(1.0+als/6.0*(1.0-t+c+als/20.0*(5.0-18.0*t+Math.pow(t,2)+72.0*c-58.0*this.ep2)))+this.x0;y=this.k0*(ml-this.ml0+n*tq*(als*(0.5+als/24.0*(5.0-t+9.0*c+4.0*Math.pow(c,2)+als/30.0*(61.0-58.0*t+Math.pow(t,2)+600.0*c-330.0*this.ep2)))))+this.y0;}
 p.x=x;p.y=y;return p;},inverse:function(p){var con,phi;var delta_phi;var i;var max_iter=6;var lat,lon;if(this.sphere){var f=Math.exp(p.x/(this.a*this.k0));var g=.5*(f-1/f);var temp=this.lat0+p.y/(this.a*this.k0);var h=Math.cos(temp);con=Math.sqrt((1.0-h*h)/(1.0+g*g));lat=Proj4js.common.asinz(con);if(temp<0)
 lat=-lat;if((g==0)&&(h==0)){lon=this.long0;}else{lon=Proj4js.common.adjust_lon(Math.atan2(g,h)+this.long0);}}else{var x=p.x-this.x0;var y=p.y-this.y0;con=(this.ml0+y/this.k0)/this.a;phi=con;for(i=0;true;i++){delta_phi=((con+this.e1*Math.sin(2.0*phi)-this.e2*Math.sin(4.0*phi)+this.e3*Math.sin(6.0*phi))/this.e0)-phi;phi+=delta_phi;if(Math.abs(delta_phi)<=Proj4js.common.EPSLN)break;if(i>=max_iter){Proj4js.reportError("tmerc:inverse: Latitude failed to converge");return(95);}}
@@ -117,9 +126,8 @@
 p.x=lon;p.y=lat;return p;}};Proj4js.defs["GOOGLE"]="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs";Proj4js.defs["EPSG:900913"]=Proj4js.defs["GOOGLE"];Proj4js.Proj.gstmerc={init:function(){var temp=this.b/this.a;this.e=Math.sqrt(1.0-temp*temp);this.lc=this.long0;this.rs=Math.sqrt(1.0+this.e*this.e*Math.pow(Math.cos(this.lat0),4.0)/(1.0-this.e*this.e));var sinz=Math.sin(this.lat0);var pc=Math.asin(sinz/this.rs);var sinzpc=Math.sin(pc);this.cp=Proj4js.common.latiso(0.0,pc,sinzpc)-this.rs*Proj4js.common.latiso(this.e,this.lat0,sinz);this.n2=this.k0*this.a*Math.sqrt(1.0-this.e*this.e)/(1.0-this.e*this.e*sinz*sinz);this.xs=this.x0;this.ys=this.y0-this.n2*pc;if(!this.title)this.title="Gauss Schreiber transverse mercator";},forward:function(p){var lon=p.x;var lat=p.y;var L=this.rs*(lon-this.lc);var Ls=this.cp+(this.rs*Proj4js.common.latiso(this.e,lat,Math.sin(lat)));var lat1=Math.asin(Math.sin(L)/Proj4js.common.cosh(
 Ls));var Ls1=Proj4js.common.latiso(0.0,lat1,Math.sin(lat1));p.x=this.xs+(this.n2*Ls1);p.y=this.ys+(this.n2*Math.atan(Proj4js.common.sinh(Ls)/Math.cos(L)));return p;},inverse:function(p){var x=p.x;var y=p.y;var L=Math.atan(Proj4js.common.sinh((x-this.xs)/this.n2)/Math.cos((y-this.ys)/this.n2));var lat1=Math.asin(Math.sin((y-this.ys)/this.n2)/Proj4js.common.cosh((x-this.xs)/this.n2));var LC=Proj4js.common.latiso(0.0,lat1,Math.sin(lat1));p.x=this.lc+L/this.rs;p.y=Proj4js.common.invlatiso(this.e,(LC-this.cp)/this.rs);return p;}};Proj4js.Proj.ortho={init:function(def){;this.sin_p14=Math.sin(this.lat0);this.cos_p14=Math.cos(this.lat0);},forward:function(p){var sinphi,cosphi;var dlon;var coslon;var ksp;var g;var lon=p.x;var lat=p.y;dlon=Proj4js.common.adjust_lon(lon-this.long0);sinphi=Math.sin(lat);cosphi=Math.cos(lat);coslon=Math.cos(dlon);g=this.sin_p14*sinphi+this.cos_p14*cosphi*coslon;ksp=1.0;if((g>0)||(Math.abs(g)<=Proj4js.common.EPSLN)){var x=this.a*ksp*cosphi*Math.sin(dlon);
 var y=this.y0+this.a*ksp*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon);}else{Proj4js.reportError("orthoFwdPointError");}
 p.x=x;p.y=y;return p;},inverse:function(p){var rh;var z;var sinz,cosz;var temp;var con;var lon,lat;p.x-=this.x0;p.y-=this.y0;rh=Math.sqrt(p.x*p.x+p.y*p.y);if(rh>this.a+.0000001){Proj4js.reportError("orthoInvDataError");}
 z=Proj4js.common.asinz(rh/this.a);sinz=Math.sin(z);cosz=Math.cos(z);lon=this.long0;if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.lat0;}
-lat=Proj4js.common.asinz(cosz*this.sin_p14+(p.y*sinz*this.cos_p14)/rh);con=Math.abs(lat0)-Proj4js.common.HALF_PI;if(Math.abs(con)<=Proj4js.common.EPSLN){if(this.lat0>=0){lon=Proj4js.common.adjust_lon(this.long0+Math.atan2(p.x,-p.y));}else{lon=Proj4js.common.adjust_lon(this.long0-Math.atan2(-p.x,p.y));}}
-con=cosz-this.sin_p14*Math.sin(lat);if((Math.abs(con)>=Proj4js.common.EPSLN)||(Math.abs(x)>=Proj4js.common.EPSLN)){lon=Proj4js.common.adjust_lon(this.long0+Math.atan2((p.x*sinz*this.cos_p14),(con*rh)));}
-p.x=lon;p.y=lat;return p;}};Proj4js.Proj.somerc={init:function(){var phy0=this.lat0;this.lambda0=this.long0;var sinPhy0=Math.sin(phy0);var semiMajorAxis=this.a;var invF=this.rf;var flattening=1/invF;var e2=2*flattening-Math.pow(flattening,2);var e=this.e=Math.sqrt(e2);this.R=semiMajorAxis*Math.sqrt(1-e2)/(1-e2*Math.pow(sinPhy0,2.0));this.alpha=Math.sqrt(1+e2/(1-e2)*Math.pow(Math.cos(phy0),4.0));this.b0=Math.asin(sinPhy0/this.alpha);this.K=Math.log(Math.tan(Math.PI/4.0+this.b0/2.0))
+lat=Proj4js.common.asinz(cosz*this.sin_p14+(p.y*sinz*this.cos_p14)/rh);con=Math.abs(this.lat0)-Proj4js.common.HALF_PI;if(Math.abs(con)<=Proj4js.common.EPSLN){if(this.lat0>=0){lon=Proj4js.common.adjust_lon(this.long0+Math.atan2(p.x,-p.y));}else{lon=Proj4js.common.adjust_lon(this.long0-Math.atan2(-p.x,p.y));}}
+con=cosz-this.sin_p14*Math.sin(lat);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.somerc={init:function(){var phy0=this.lat0;this.lambda0=this.long0;var sinPhy0=Math.sin(phy0);var semiMajorAxis=this.a;var invF=this.rf;var flattening=1/invF;var e2=2*flattening-Math.pow(flattening,2);var e=this.e=Math.sqrt(e2);this.R=this.k0*semiMajorAxis*Math.sqrt(1-e2)/(1-e2*Math.pow(sinPhy0,2.0));this.alpha=Math.sqrt(1+e2/(1-e2)*Math.pow(Math.cos(phy0),4.0));this.b0=Math.asin(sinPhy0/this.alpha);this.K=Math.log(Math.tan(Math.PI/4.0+this.b0/2.0))
 -this.alpha*Math.log(Math.tan(Math.PI/4.0+phy0/2.0))
 +this.alpha*e/2*Math.log((1+e*sinPhy0)/(1-e*sinPhy0));},forward:function(p){var Sa1=Math.log(Math.tan(Math.PI/4.0-p.y/2.0));var Sa2=this.e/2.0*Math.log((1+this.e*Math.sin(p.y))/(1-this.e*Math.sin(p.y)));var S=-this.alpha*(Sa1+Sa2)+this.K;var b=2.0*(Math.atan(Math.exp(S))-Math.PI/4.0);var I=this.alpha*(p.x-this.lambda0);var rotI=Math.atan(Math.sin(I)/(Math.sin(this.b0)*Math.tan(b)+
 Math.cos(this.b0)*Math.cos(I)));var rotB=Math.asin(Math.cos(this.b0)*Math.sin(b)-
@@ -152,7 +160,7 @@
 th_n_re=1;th_n_im=0;var den_re=this.B_re[1];var den_im=this.B_im[1];for(n=2;n<=6;n++){th_n_re1=th_n_re*th_re-th_n_im*th_im;th_n_im1=th_n_im*th_re+th_n_re*th_im;th_n_re=th_n_re1;th_n_im=th_n_im1;den_re=den_re+n*(this.B_re[n]*th_n_re-this.B_im[n]*th_n_im);den_im=den_im+n*(this.B_im[n]*th_n_re+this.B_re[n]*th_n_im);}
 var den2=den_re*den_re+den_im*den_im;th_re=(num_re*den_re+num_im*den_im)/den2;th_im=(num_im*den_re-num_re*den_im)/den2;}
 var d_psi=th_re;var d_lambda=th_im;var d_psi_n=1;var d_phi=0;for(n=1;n<=9;n++){d_psi_n=d_psi_n*d_psi;d_phi=d_phi+this.D[n]*d_psi_n;}
-var lat=this.lat0+(d_phi*Proj4js.common.SEC_TO_RAD*1E5);var lon=this.long0+d_lambda;p.x=lon;p.y=lat;return p;}};Proj4js.Proj.mill={init:function(){},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+this.a*dlon;var y=this.y0+this.a*Math.log(Math.tan((Proj4js.common.PI/4.0)+(lat/2.5)))*1.25;p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var lon=Proj4js.common.adjust_lon(this.long0+p.x/this.a);var lat=2.5*(Math.atan(Math.exp(0.8*p.y/this.a))-Proj4js.common.PI/4.0);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.gnom={init:function(def){this.sin_p14=Math.sin(this.lat0);this.cos_p14=Math.cos(this.lat0);this.infinity_dist=1000*this.a;},forward:function(p){var sinphi,cosphi;var dlon;var coslon;var ksp;var g;var lon=p.x;var lat=p.y;dlon=Proj4js.common.adjust_lon(lon-this.long0);sinphi=Math.sin(lat);cosphi=Math.cos(lat);coslon=Math.cos(dlon);g=this.sin_p14*sinphi+this.cos_p14*cosphi*coslon;ksp=1.0;if((g>0)||(M
 ath.abs(g)<=Proj4js.common.EPSLN)){x=this.x0+this.a*ksp*cosphi*Math.sin(dlon)/g;y=this.y0+this.a*ksp*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon)/g;}else{Proj4js.reportError("orthoFwdPointError");x=this.x0+this.infinity_dist*cosphi*Math.sin(dlon);y=this.y0+this.infinity_dist*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon);}
+var lat=this.lat0+(d_phi*Proj4js.common.SEC_TO_RAD*1E5);var lon=this.long0+d_lambda;p.x=lon;p.y=lat;return p;}};Proj4js.Proj.mill={init:function(){},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+this.a*dlon;var y=this.y0+this.a*Math.log(Math.tan((Proj4js.common.PI/4.0)+(lat/2.5)))*1.25;p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var lon=Proj4js.common.adjust_lon(this.long0+p.x/this.a);var lat=2.5*(Math.atan(Math.exp(0.8*p.y/this.a))-Proj4js.common.PI/4.0);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.gnom={init:function(def){this.sin_p14=Math.sin(this.lat0);this.cos_p14=Math.cos(this.lat0);this.infinity_dist=1000*this.a;this.rc=1;},forward:function(p){var sinphi,cosphi;var dlon;var coslon;var ksp;var g;var lon=p.x;var lat=p.y;dlon=Proj4js.common.adjust_lon(lon-this.long0);sinphi=Math.sin(lat);cosphi=Math.cos(lat);coslon=Math.cos(dlon);g=this.sin_p14*sinphi+this.cos_p14*cosphi*coslon;ksp=1.0;if
 ((g>0)||(Math.abs(g)<=Proj4js.common.EPSLN)){x=this.x0+this.a*ksp*cosphi*Math.sin(dlon)/g;y=this.y0+this.a*ksp*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon)/g;}else{Proj4js.reportError("orthoFwdPointError");x=this.x0+this.infinity_dist*cosphi*Math.sin(dlon);y=this.y0+this.infinity_dist*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon);}
 p.x=x;p.y=y;return p;},inverse:function(p){var rh;var z;var sinc,cosc;var c;var lon,lat;p.x=(p.x-this.x0)/this.a;p.y=(p.y-this.y0)/this.a;p.x/=this.k0;p.y/=this.k0;if((rh=Math.sqrt(p.x*p.x+p.y*p.y))){c=Math.atan2(rh,this.rc);sinc=Math.sin(c);cosc=Math.cos(c);lat=Proj4js.common.asinz(cosc*this.sin_p14+(p.y*sinc*this.cos_p14)/rh);lon=Math.atan2(p.x*sinc,rh*this.cos_p14*cosc-p.y*this.sin_p14*sinc);lon=Proj4js.common.adjust_lon(this.long0+lon);}else{lat=this.phic0;lon=0.0;}
 p.x=lon;p.y=lat;return p;}};Proj4js.Proj.sinu={init:function(){this.R=6370997.0;},forward:function(p){var x,y,delta_lon;var lon=p.x;var lat=p.y;delta_lon=Proj4js.common.adjust_lon(lon-this.long0);x=this.R*delta_lon*Math.cos(lat)+this.x0;y=this.R*lat+this.y0;p.x=x;p.y=y;return p;},inverse:function(p){var lat,temp,lon;p.x-=this.x0;p.y-=this.y0;lat=p.y/this.R;if(Math.abs(lat)>Proj4js.common.HALF_PI){Proj4js.reportError("sinu:Inv:DataError");}
 temp=Math.abs(lat)-Proj4js.common.HALF_PI;if(Math.abs(temp)>Proj4js.common.EPSLN){temp=this.long0+p.x/(this.R*Math.cos(lat));lon=Proj4js.common.adjust_lon(temp);}else{lon=this.long0;}
@@ -161,7 +169,7 @@
 var al=.5*Math.abs((Proj4js.common.PI/dlon)-(dlon/Proj4js.common.PI));var asq=al*al;var sinth=Math.sin(theta);var costh=Math.cos(theta);var g=costh/(sinth+costh-1.0);var gsq=g*g;var m=g*(2.0/sinth-1.0);var msq=m*m;var con=Proj4js.common.PI*this.R*(al*(g-msq)+Math.sqrt(asq*(g-msq)*(g-msq)-(msq+asq)*(gsq-msq)))/(msq+asq);if(dlon<0){con=-con;}
 x=this.x0+con;con=Math.abs(con/(Proj4js.common.PI*this.R));if(lat>=0){y=this.y0+Proj4js.common.PI*this.R*Math.sqrt(1.0-con*con-2.0*al*con);}else{y=this.y0-Proj4js.common.PI*this.R*Math.sqrt(1.0-con*con-2.0*al*con);}
 p.x=x;p.y=y;return p;},inverse:function(p){var dlon;var xx,yy,xys,c1,c2,c3;var al,asq;var a1;var m1;var con;var th1;var d;p.x-=this.x0;p.y-=this.y0;con=Proj4js.common.PI*this.R;xx=p.x/con;yy=p.y/con;xys=xx*xx+yy*yy;c1=-Math.abs(yy)*(1.0+xys);c2=c1-2.0*yy*yy+xx*xx;c3=-2.0*c1+1.0+2.0*yy*yy+xys*xys;d=yy*yy/c3+(2.0*c2*c2*c2/c3/c3/c3-9.0*c1*c2/c3/c3)/27.0;a1=(c1-c2*c2/3.0/c3)/c3;m1=2.0*Math.sqrt(-a1/3.0);con=((3.0*d)/a1)/m1;if(Math.abs(con)>1.0){if(con>=0.0){con=1.0;}else{con=-1.0;}}
-th1=Math.acos(con)/3.0;if(p.y>=0){lat=(-m1*Math.cos(th1+Proj4js.common.PI/3.0)-c2/3.0/c3)*Proj4js.common.PI;}else{lat=-(-m1*Math.cos(th1+PI/3.0)-c2/3.0/c3)*Proj4js.common.PI;}
+th1=Math.acos(con)/3.0;if(p.y>=0){lat=(-m1*Math.cos(th1+Proj4js.common.PI/3.0)-c2/3.0/c3)*Proj4js.common.PI;}else{lat=-(-m1*Math.cos(th1+Proj4js.common.PI/3.0)-c2/3.0/c3)*Proj4js.common.PI;}
 if(Math.abs(xx)<Proj4js.common.EPSLN){lon=this.long0;}
 lon=Proj4js.common.adjust_lon(this.long0+Proj4js.common.PI*(xys-1.0+Math.sqrt(1.0+2.0*(xx*xx-yy*yy)+xys*xys))/2.0/xx);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.cea={init:function(){},forward:function(p){var lon=p.x;var lat=p.y;dlon=Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+this.a*dlon*Math.cos(this.lat_ts);var y=this.y0+this.a*Math.sin(lat)/Math.cos(this.lat_ts);p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var lon=Proj4js.common.adjust_lon(this.long0+(p.x/this.a)/Math.cos(this.lat_ts));var lat=Math.asin((p.y/this.a)*Math.cos(this.lat_ts));p.x=lon;p.y=lat;return p;}};Proj4js.Proj.eqc={init:function(){if(!this.x0)this.x0=0;if(!this.y0)this.y0=0;if(!this.lat0)this.lat0=0;if(!this.long0)this.long0=0;if(!this.lat_ts)this.lat_ts=0;if(!this.title)this.title="Equidistant Cylindrical (Plate Carre)";this.rc=Math.cos(this.lat_ts);},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var dlat=Proj4js.common.
 adjust_lat(lat-this.lat0);p.x=this.x0+(this.a*dlon*this.rc);p.y=this.y0+(this.a*dlat);return p;},inverse:function(p){var x=p.x;var y=p.y;p.x=Proj4js.common.adjust_lon(this.long0+((x-this.x0)/(this.a*this.rc)));p.y=Proj4js.common.adjust_lat(this.lat0+((y-this.y0)/(this.a)));return p;}};Proj4js.Proj.cass={init:function(){if(!this.sphere){this.en=this.pj_enfn(this.es)
 this.m0=this.pj_mlfn(this.lat0,Math.sin(this.lat0),Math.cos(this.lat0),this.en);}},C1:.16666666666666666666,C2:.00833333333333333333,C3:.04166666666666666666,C4:.33333333333333333333,C5:.06666666666666666666,forward:function(p){var x,y;var lam=p.x;var phi=p.y;lam=Proj4js.common.adjust_lon(lam-this.long0);if(this.sphere){x=Math.asin(Math.cos(phi)*Math.sin(lam));y=Math.atan2(Math.tan(phi),Math.cos(lam))-this.phi0;}else{this.n=Math.sin(phi);this.c=Math.cos(phi);y=this.pj_mlfn(phi,this.n,this.c,this.en);this.n=1./Math.sqrt(1.-this.es*this.n*this.n);this.tn=Math.tan(phi);this.t=this.tn*this.tn;this.a1=lam*this.c;this.c*=this.es*this.c/(1-this.es);this.a2=this.a1*this.a1;x=this.n*this.a1*(1.-this.a2*this.t*(this.C1-(8.-this.t+8.*this.c)*this.a2*this.C2));y-=this.m0-this.n*this.tn*this.a2*(.5+(5.-this.t+6.*this.c)*this.a2*this.C3);}
@@ -187,7 +195,7 @@
 this.f0=ms1/(this.ns*Math.pow(ts1,this.ns));this.rh=this.a*this.f0*Math.pow(ts0,this.ns);if(!this.title)this.title="Lambert Conformal Conic";},forward:function(p){var lon=p.x;var lat=p.y;if(lat<=90.0&&lat>=-90.0&&lon<=180.0&&lon>=-180.0){}else{Proj4js.reportError("lcc:forward: llInputOutOfRange: "+lon+" : "+lat);return null;}
 var con=Math.abs(Math.abs(lat)-Proj4js.common.HALF_PI);var ts,rh1;if(con>Proj4js.common.EPSLN){ts=Proj4js.common.tsfnz(this.e,lat,Math.sin(lat));rh1=this.a*this.f0*Math.pow(ts,this.ns);}else{con=lat*this.ns;if(con<=0){Proj4js.reportError("lcc:forward: No Projection");return null;}
 rh1=0;}
-var theta=this.ns*Proj4js.common.adjust_lon(lon-this.long0);p.x=this.k0*(rh1*Math.sin(theta))+this.x0;p.y=this.k0*(this.rh-rh1*Math.cos(theta))+this.y0;return p;},inverse:function(p){var rh1,con,ts;var lat,lon;x=(p.x-this.x0)/this.k0;y=(this.rh-(p.y-this.y0)/this.k0);if(this.ns>0){rh1=Math.sqrt(x*x+y*y);con=1.0;}else{rh1=-Math.sqrt(x*x+y*y);con=-1.0;}
+var theta=this.ns*Proj4js.common.adjust_lon(lon-this.long0);p.x=this.k0*(rh1*Math.sin(theta))+this.x0;p.y=this.k0*(this.rh-rh1*Math.cos(theta))+this.y0;return p;},inverse:function(p){var rh1,con,ts;var lat,lon;var x=(p.x-this.x0)/this.k0;var y=(this.rh-(p.y-this.y0)/this.k0);if(this.ns>0){rh1=Math.sqrt(x*x+y*y);con=1.0;}else{rh1=-Math.sqrt(x*x+y*y);con=-1.0;}
 var theta=0.0;if(rh1!=0){theta=Math.atan2((con*x),(con*y));}
 if((rh1!=0)||(this.ns>0.0)){con=1.0/this.ns;ts=Math.pow((rh1/(this.a*this.f0)),con);lat=Proj4js.common.phi2z(this.e,ts);if(lat==-9999)return null;}else{lat=-Proj4js.common.HALF_PI;}
 lon=Proj4js.common.adjust_lon(theta/this.ns+this.long0);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.laea={S_POLE:1,N_POLE:2,EQUIT:3,OBLIQ:4,init:function(){var t=Math.abs(this.lat0);if(Math.abs(t-Proj4js.common.HALF_PI)<Proj4js.common.EPSLN){this.mode=this.lat0<0.?this.S_POLE:this.N_POLE;}else if(Math.abs(t)<Proj4js.common.EPSLN){this.mode=this.EQUIT;}else{this.mode=this.OBLIQ;}

Modified: branches/fusion-2.2/templates/mapserver/standard/ApplicationDefinition.xml
===================================================================
--- branches/fusion-2.2/templates/mapserver/standard/ApplicationDefinition.xml	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/templates/mapserver/standard/ApplicationDefinition.xml	2010-09-24 18:32:16 UTC (rev 2234)
@@ -14,7 +14,7 @@
         <Type>MapServer</Type>
         <SingleTile>true</SingleTile>
         <Extension>
-            <MapFile>/ms4w/apps/gmap/htdocs/gmap_groups.map</MapFile>
+            <MapFile>/ms4w/Apache/htdocs/gmap/htdocs/gmap_groups.map</MapFile>
         </Extension>
       </Map>
     </MapGroup>
@@ -23,7 +23,7 @@
         <Type>MapServer</Type>
         <SingleTile>true</SingleTile>
         <Extension>
-            <MapFile>/ms4w/apps/gmap/htdocs/gmap75.map</MapFile>
+            <MapFile>/ms4w/Apache/htdocs/gmap/htdocs/gmap75.map</MapFile>
             <!--ProjectionCode>EPSG:42304</ProjectionCode-->
             <ProjectionDef>+title=LCC +proj=lcc +lat_1=49 +lat_2=77 +lat_0=49 +lon_0=-95 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs</ProjectionDef>
         </Extension>
@@ -34,7 +34,7 @@
         <Type>MapServer</Type>
         <SingleTile>true</SingleTile>
         <Extension>
-            <MapFile>/ms4w/apps/gmap/htdocs/gmapLonLat2.map</MapFile>
+            <MapFile>/ms4w/Apache/htdocs/gmap/htdocs/gmapLonLat2.map</MapFile>
         </Extension>
       </Map>
     </MapGroup>
@@ -60,7 +60,7 @@
         <Type>MapServer</Type>
         <SingleTile>true</SingleTile>
         <Extension>
-            <MapFile>/ms4w/apps/gmap/htdocs/gmapLonLat.map</MapFile>
+            <MapFile>/ms4w/Apache/htdocs/gmap/htdocs/gmapLonLat.map</MapFile>
             <Options>
               <isBaseLayer>false</isBaseLayer>
               <singleTile>true</singleTile>
@@ -106,7 +106,7 @@
         <Type>MapServer</Type>
         <SingleTile>true</SingleTile>
         <Extension>
-            <MapFile>/ms4w/apps/gmap/htdocs/gmap75_key.map</MapFile>
+            <MapFile>/ms4w/Apache/htdocs/gmap/htdocs/gmap75_key.map</MapFile>
         </Extension>
       </Map>
     </MapGroup>

Modified: branches/fusion-2.2/text/en
===================================================================
--- branches/fusion-2.2/text/en	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/text/en	2010-09-24 18:32:16 UTC (rev 2234)
@@ -332,3 +332,18 @@
 
 # Localized Icon Files
 POWEREDBYICON           = PoweredBy_en.gif
+
+# Quick Plot UI
+QUICKPLOT_HEADER        = Quick Plot
+QUICKPLOT_TITLE         = Title
+QUICKPLOT_SUBTITLE      = Sub title
+QUICKPLOT_PAPER_SIZE    = Paper size
+QUICKPLOT_SCALING       = Scaling
+QUICKPLOT_DPI           = Print DPI
+QUICKPLOT_GENERATE      = Generate
+QUICKPLOT_ADVANCED_OPTIONS = Advanced options
+QUICKPLOT_PRINT         = Print
+QUICKPLOT_CANCEL        = Cancel
+QUICKPLOT_PREVIEW_ERROR = The application resources required to generate the plot exceed the settings defined by the administrator
+QUICKPLOT_RESOLUTION_WARNING = The current settings exceed the map resolution. Zooming out or increasing the scaling will help create a more legible plot
+QUICKPLOT_SCALE_LABEL   = Scale

Modified: branches/fusion-2.2/text/en.json
===================================================================
--- branches/fusion-2.2/text/en.json	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/text/en.json	2010-09-24 18:32:16 UTC (rev 2234)
@@ -59,5 +59,20 @@
 'printShowLegend':'Show Legend?',
 'printShowNorthArrow':'Show North Arrow?',
 
+'quickPlotResolutionWarning':'The current settings exceed the map resolution. Zooming out or increasing the scaling will help create a more legible plot',
+'noCommercialMapLayers':'NONE',
+'googleStreet':'Google Street',
+'googleSatellite':'Google Satellite',
+'googleTerrain':'Google Terrain',
+'googleHybrid':'Google Hybrid',
+'yahooStreet':'Yahoo Street',
+'yahooSatellite':'Yahoo Satellite',
+'yahooHybrid':'Yahoo Hybrid',
+'bingStreet':'Bing Street',
+'bingSatellite':'Bing Satellite',
+'bingHybrid':'Bing Hybrid',
+'openStreetMap':'Open Street Map',
+'openStreetMapOsmarender':'Open Street Map (Osmarender)',
+'openStreetMapCycleMap':'Open Street Map (CycleMap)',
 'end': ''
 };

Modified: branches/fusion-2.2/text/fr
===================================================================
--- branches/fusion-2.2/text/fr	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/text/fr	2010-09-24 18:32:16 UTC (rev 2234)
@@ -333,3 +333,18 @@
 
 # Localized Icon Files
 POWEREDBYICON           = PoweredBy_en.gif
+
+# Quick Plot UI
+QUICKPLOT_HEADER        = Quick Plot
+QUICKPLOT_TITLE         = Title
+QUICKPLOT_SUBTITLE      = Sub title
+QUICKPLOT_PAPER_SIZE    = Paper size
+QUICKPLOT_SCALING       = Scaling
+QUICKPLOT_DPI           = Print DPI
+QUICKPLOT_GENERATE      = Generate
+QUICKPLOT_ADVANCED_OPTIONS = Advanced options
+QUICKPLOT_PRINT         = Print
+QUICKPLOT_CANCEL        = Cancel
+QUICKPLOT_PREVIEW_ERROR = The application resources required to generate the plot exceed the settings defined by the administrator
+QUICKPLOT_RESOLUTION_WARNING = The current settings exceed the map resolution. Zooming out or increasing the scaling will help create a more legible plot
+QUICKPLOT_SCALE_LABEL   = Scale

Modified: branches/fusion-2.2/text/fr.json
===================================================================
--- branches/fusion-2.2/text/fr.json	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/text/fr.json	2010-09-24 18:32:16 UTC (rev 2234)
@@ -50,5 +50,20 @@
 'printGenerate': 'Generate',
 'maptipLinkText': 'Cliquer pour plus d information',
 
+'quickPlotResolutionWarning':'The current settings exceed the map resolution. Zooming out or increasing the scaling will help create a more legible plot',
+'noCommercialMapLayers':'NONE',
+'googleStreet':'Google Street',
+'googleSatellite':'Google Satellite',
+'googleTerrain':'Google Terrain',
+'googleHybrid':'Google Hybrid',
+'yahooStreet':'Yahoo Street',
+'yahooSatellite':'Yahoo Satellite',
+'yahooHybrid':'Yahoo Hybrid',
+'bingStreet':'Bing Street',
+'bingSatellite':'Bing Satellite',
+'bingHybrid':'Bing Hybrid',
+'openStreetMap':'Open Street Map',
+'openStreetMapOsmarender':'Open Street Map (Osmarender)',
+'openStreetMapCycleMap':'Open Street Map (CycleMap)',
 'end': ''
 };

Modified: branches/fusion-2.2/widgets/BasemapSwitcher.js
===================================================================
--- branches/fusion-2.2/widgets/BasemapSwitcher.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/BasemapSwitcher.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -43,12 +43,16 @@
             'G_NORMAL_MAP': null,
             'G_SATELLITE_MAP': null,
             'G_HYBRID_MAP': null,
+            'G_PHYSICAL_MAP': null,
             'YAHOO_MAP_REG': null,
             'YAHOO_MAP_SAT': null,
             'YAHOO_MAP_HYB': null,
             'Road': null,
             'Aerial': null,
             'Hybrid': null,
+            'Mapnik': null,
+            'Osmarender': null,
+            'CycleMap': null,
             'None': null
         };
     },
@@ -62,13 +66,13 @@
             var map = maps[i];
             switch (map.layerType) {
                 case 'MapGuide':
-                    this.options['None'] = 'None';
+                    this.options['None'] = OpenLayers.i18n('noCommercialMapLayers');
                     this.baseMaps['None'] = map;
                     break;
                 case 'Google':
                     // if user didn't indicate basemap types, use the default Google Street
                     if (!map.mapTag.extension.Options || !map.mapTag.extension.Options[0].type) {
-                        this.options['G_NORMAL_MAP'] = "Google Street";
+                        this.options['G_NORMAL_MAP'] = OpenLayers.i18n('googleStreet');
                         this.baseMaps['G_NORMAL_MAP'] = map;
 
                         // The first non-MapGuide basemap will be the default basemap
@@ -79,26 +83,41 @@
                     else {
                         switch (map.mapTag.extension.Options[0].type[0]) {
                             case 'G_NORMAL_MAP':
-                                if (map.mapTag.extension.Options[0].name)
+                                if (map.mapTag.extension.Options[0].name) {
                                     this.options['G_NORMAL_MAP'] = map.mapTag.extension.Options[0].name[0];
-                                else
-                                    this.options['G_NORMAL_MAP'] = "Google Street";
+                                }
+                                else {
+                                    this.options['G_NORMAL_MAP'] = OpenLayers.i18n('googleStreet');
+                                }
                                 this.baseMaps['G_NORMAL_MAP'] = map;
                                 break;
                             case 'G_SATELLITE_MAP':
-                                if (map.mapTag.extension.Options[0].name)
+                                if (map.mapTag.extension.Options[0].name) {
                                     this.options['G_SATELLITE_MAP'] = map.mapTag.extension.Options[0].name[0];
-                                else
-                                    this.options['G_SATELLITE_MAP'] = "Google Satellite";
+                                }
+                                else {
+                                    this.options['G_SATELLITE_MAP'] = OpenLayers.i18n('googleSatellite');
+                                }
                                 this.baseMaps['G_SATELLITE_MAP'] = map;
                                 break;
                             case 'G_HYBRID_MAP':
-                                if (map.mapTag.extension.Options[0].name)
+                                if (map.mapTag.extension.Options[0].name) {
                                     this.options['G_HYBRID_MAP'] = map.mapTag.extension.Options[0].name[0];
-                                else
-                                    this.options['G_HYBRID_MAP'] = "Google Hybrid";
+                                }
+                                else {
+                                    this.options['G_HYBRID_MAP'] = OpenLayers.i18n('googleHybrid');
+                                }
                                 this.baseMaps['G_HYBRID_MAP'] = map;
                                 break;
+                            case 'G_PHYSICAL_MAP':
+                                if (map.mapTag.extension.Options[0].name) {
+                                    this.options['G_PHYSICAL_MAP'] = map.mapTag.extension.Options[0].name[0];
+                                }
+                                else {
+                                    this.options['G_PHYSICAL_MAP'] = OpenLayers.i18n('googleTerrain');
+                                }
+                                this.baseMaps['G_PHYSICAL_MAP'] = map;
+                                break;
                             default:
                                 break;
                         }
@@ -113,7 +132,7 @@
                 case 'Yahoo':
                     // if user didn't indicate basemap types, use the default Yahoo Street
                     if (!map.mapTag.extension.Options || !map.mapTag.extension.Options[0].type) {
-                        this.options['YAHOO_MAP_REG'] = "Yahoo Street";
+                        this.options['YAHOO_MAP_REG'] = OpenLayers.i18n('yahooStreet');
                         this.baseMaps['YAHOO_MAP_REG'] = map;
 
                         // The first non-MapGuide basemap will be the default basemap
@@ -124,24 +143,30 @@
                     else {
                         switch (map.mapTag.extension.Options[0].type[0]) {
                             case 'YAHOO_MAP_REG':
-                                if (map.mapTag.extension.Options[0].name)
+                                if (map.mapTag.extension.Options[0].name) {
                                     this.options['YAHOO_MAP_REG'] = map.mapTag.extension.Options[0].name[0];
-                                else
+                                }
+                                else {
                                     this.options['YAHOO_MAP_REG'] = "Yahoo Street";
+                                }
                                 this.baseMaps['YAHOO_MAP_REG'] = map;
                                 break;
                             case 'YAHOO_MAP_SAT':
-                                if (map.mapTag.extension.Options[0].name)
+                                if (map.mapTag.extension.Options[0].name) {
                                     this.options['YAHOO_MAP_SAT'] = map.mapTag.extension.Options[0].name[0];
-                                else
-                                    this.options['YAHOO_MAP_SAT'] = "Yahoo Satellite";
+                                }
+                                else {
+                                    this.options['YAHOO_MAP_SAT'] = OpenLayers.i18n('yahooStreet');
+                                }
                                 this.baseMaps['YAHOO_MAP_SAT'] = map;
                                 break;
                             case 'YAHOO_MAP_HYB':
-                                if (map.mapTag.extension.Options[0].name)
+                                if (map.mapTag.extension.Options[0].name) {
                                     this.options['YAHOO_MAP_HYB'] = map.mapTag.extension.Options[0].name[0];
-                                else
-                                    this.options['YAHOO_MAP_HYB'] = "Yahoo Hybrid";
+                                }
+                                else {
+                                    this.options['YAHOO_MAP_HYB'] = OpenLayers.i18n('yahooHybrid');
+                                }
                                 this.baseMaps['YAHOO_MAP_HYB'] = map;
                                 break;
                             default:
@@ -156,7 +181,7 @@
                 case 'VirtualEarth':
                     // if user didn't indicate basemap types, use the default Bing Street
                     if (!map.mapTag.extension.Options || !map.mapTag.extension.Options[0].type) {
-                        this.options['Road'] = "Bing Street";
+                        this.options['Road'] = OpenLayers.i18n('bingStreet');
                         this.baseMaps['Road'] = map;
                         // The first non-MapGuide basemap will be the default basemap
                         if (!this.defaultBasemap) {
@@ -167,24 +192,30 @@
 
                         switch (map.mapTag.extension.Options[0].type[0]) {
                             case 'Road':
-                                if (map.mapTag.extension.Options[0].name)
+                                if (map.mapTag.extension.Options[0].name) {
                                     this.options['Road'] = map.mapTag.extension.Options[0].name[0];
-                                else
-                                    this.options['Road'] = "Bing Street";
+                                }
+                                else {
+                                    this.options['Road'] = OpenLayers.i18n('bingStreet');
+                                }
                                 this.baseMaps['Road'] = map;
                                 break;
                             case 'Aerial':
-                                if (map.mapTag.extension.Options[0].name)
+                                if (map.mapTag.extension.Options[0].name) {
                                     this.options['Aerial'] = map.mapTag.extension.Options[0].name[0];
-                                else
-                                    this.options['Aerial'] = "Bing Satellite";
+                                }
+                                else {
+                                    this.options['Aerial'] = OpenLayers.i18n('bingSatellite');
+                                }
                                 this.baseMaps['Aerial'] = map;
                                 break;
                             case 'Hybrid':
-                                if (map.mapTag.extension.Options[0].name)
+                                if (map.mapTag.extension.Options[0].name) {
                                     this.options['Hybrid'] = map.mapTag.extension.Options[0].name[0];
-                                else
-                                    this.options['Hybrid'] = "Bing Hybrid";
+                                }
+                                else {
+                                    this.options['Hybrid'] = OpenLayers.i18n('bingHybrid');
+                                }
                                 this.baseMaps['Hybrid'] = map;
                                 break;
                             default:
@@ -196,6 +227,55 @@
                         }
                     }
                     break;
+                case 'OpenStreetMap':
+                    // if user didn't indicate basemap types, use the default OSM Mapnik render
+                    if (!map.mapTag.extension.Options || !map.mapTag.extension.Options[0].type) {
+                        this.options['Mapnik'] = OpenLayers.i18n('openStreetMap');
+                        this.baseMaps['Mapnik'] = map;
+                        // The first non-MapGuide basemap will be the default basemap
+                        if (!this.defaultBasemap) {
+                            this.defaultBasemap = "Mapnik";
+                        }
+                    }
+                    else {
+
+                        switch (map.mapTag.extension.Options[0].type[0]) {
+                            case 'Mapnik':
+                                if (map.mapTag.extension.Options[0].name) {
+                                    this.options['Mapnik'] = map.mapTag.extension.Options[0].name[0];
+                                }
+                                else {
+                                    this.options['Mapnik'] =  OpenLayers.i18n('openStreetMap');
+                                }
+                                this.baseMaps['Mapnik'] = map;
+                                break;
+                            case 'Osmarender':
+                                if (map.mapTag.extension.Options[0].name) {
+                                    this.options['Osmarender'] = map.mapTag.extension.Options[0].name[0];
+                                }
+                                else {
+                                    this.options['Osmarender'] = OpenLayers.i18n('openStreetMapOsmarender');
+                                }
+                                this.baseMaps['Osmarender'] = map;
+                                break;
+                            case 'CycleMap':
+                                if (map.mapTag.extension.Options[0].name) {
+                                    this.options['CycleMap'] = map.mapTag.extension.Options[0].name[0];
+                                }
+                                else {
+                                    this.options['CycleMap'] =  OpenLayers.i18n('openStreetMapCycleMap');
+                                }
+                                this.baseMaps['CycleMap'] = map;
+                                break;
+                            default:
+                                break;
+                        }
+                        // The first non-MapGuide basemap will be the default basemap
+                        if (!this.defaultBasemap) {
+                            this.defaultBasemap = map.mapTag.extension.Options[0].type[0];
+                        }
+                    }
+                    break;
                 default:
                     break;
             }

Modified: branches/fusion-2.2/widgets/BufferPanel/Buffer.php
===================================================================
--- branches/fusion-2.2/widgets/BufferPanel/Buffer.php	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/BufferPanel/Buffer.php	2010-09-24 18:32:16 UTC (rev 2234)
@@ -87,7 +87,7 @@
         $layers = $map->GetLayers();
         $layer = FindLayer($layers, $bufferName);
 
-        $layerNames = split(",", $layersParam);
+        $layerNames = explode(",", $layersParam);
 
         // convert distance to meters
         if($units == "mi")              //miles

Modified: branches/fusion-2.2/widgets/BufferPanel/BufferPanel.templ
===================================================================
--- branches/fusion-2.2/widgets/BufferPanel/BufferPanel.templ	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/BufferPanel/BufferPanel.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -173,14 +173,15 @@
 
 function GetParent()
 {
-    if (popup) {
-        return opener;
-    } else if (parent.Fusion) {
-        return parent;
-    } else if (parent.parent.Fusion) {
-        return parent.parent;
-    }
-    return null;
+	if(popup)
+		return opener;
+	else
+	{
+		var node = parent;
+		while (!node.Fusion && node.parent && node != node.parent)
+			node = node.parent;
+		return node;
+	}
 }
 
 function PickColor(what, allowTransparency, transparent)

Modified: branches/fusion-2.2/widgets/BufferPanel/BufferReport.templ
===================================================================
--- branches/fusion-2.2/widgets/BufferPanel/BufferReport.templ	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/BufferPanel/BufferReport.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -47,11 +47,16 @@
 }
 
 function GetParent()
-{
-    if(popup)
-        return opener;
-    else
-        return parent.parent;
+{debugger;
+	if(popup)
+		return opener;
+	else
+	{
+		var node = parent;
+		while (!node.Fusion && node.parent)
+			node = node.parent;
+		return node;
+	}
 }
 
 </script>

Modified: branches/fusion-2.2/widgets/BufferPanel/ErrorPage.templ
===================================================================
--- branches/fusion-2.2/widgets/BufferPanel/ErrorPage.templ	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/BufferPanel/ErrorPage.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -49,10 +49,15 @@
 
 function GetParent()
 {
-    if(popup)
-        return opener;
-    else
-        return parent.parent;
+	if(popup)
+		return opener;
+	else
+	{
+		var node = parent;
+		while (!node.fusion && node.parent)
+			node = node.parent;
+		return node;
+	}
 }
 
 </script>

Modified: branches/fusion-2.2/widgets/Measure.js
===================================================================
--- branches/fusion-2.2/widgets/Measure.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/Measure.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -80,6 +80,9 @@
         if(json.SegmentLabels){
             this.segmentLabels = (json.SegmentLabels[0].toLowerCase == "true" && json.SegmentLabels[0]) ? true : false;
         }
+        if(json.Geodesic){
+            this.geodesic = (json.Geodesic[0].toLowerCase == "false") ? false : true;
+        }
         this.sTarget = json.Target ? json.Target[0] : "";
         this.sBaseUrl = Fusion.getFusionURL() + 'widgets/Measure/Measure.php';
 
@@ -636,8 +639,12 @@
      * Subsequent calls from a ViewOptions widget would override the value specified.
      */
     setUnits: function(units) {
-      units = (units == Fusion.UNKNOWN)?Fusion.unitFromName(this.getMap().getUnits()):units;
+      var map = this.getMap();
+      units = (units == Fusion.UNKNOWN)?Fusion.unitFromName(map.getUnits()):units;
       this.setParameter('Units', Fusion.unitName(units));
+      if (map.oMapOL.baseLayer.projection.proj && map.oMapOL.baseLayer.projection.proj.localCS) {
+        this.geodesic = false;
+      }
     },
 
     setParameter: function(param, value) {

Deleted: branches/fusion-2.2/widgets/QuickPlot/GeneratePicture.php
===================================================================
--- trunk/widgets/QuickPlot/GeneratePicture.php	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/QuickPlot/GeneratePicture.php	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1,182 +0,0 @@
-<?php
-    $fusionMGpath = '../../layers/MapGuide/php/';
-    include $fusionMGpath . 'Utilities.php';
-
-    $fusionMGpath = '../../layers/MapGuide/php/';
-    include $fusionMGpath . 'Common.php';
-    
-    $sessionID = "";
-    $mapName   = "";
-    $rotation  = 0.0;
-    $printDpi  = 300;
-    $scaleDenominator = 0;
-    $captureBox;
-    $normalizedCapture;
-    $printSize;
-    $paperSize;
-    
-    GetParameters();
-    GenerateMap($printSize);
-?>
-
-<?php    
-    function GetParameters()
-    {
-        global $sessionID, $mapName, $printDpi, $rotation, $paperSize, $captureBox, $printSize, $scaleDenominator, $normalizedCapture;
-        $args = $_GET;
-        if ($_SERVER["REQUEST_METHOD"] == "POST")
-        {
-            $args = $_POST;
-        }
-        
-        // Not necessary to validate the parameters    	
-        $sessionID   = $args["session_id"];
-        $mapName     = $args["map_name"];
-        $rotation    = floatval($args["rotation"]);
-        $printDpi    = intval($args["print_dpi"]);
-
-        $scaleDenominator = intval($args["scale_denominator"]);
-
-        $array       = explode(",", $args["paper_size"]);
-        $paperSize   = new Size(floatval($array[0]), floatval($array[1]));
-        $printSize   = new Size($paperSize->width / 25.4 * $printDpi, $paperSize->height / 25.4 * $printDpi);
-        
-        $array       = explode(",", $args["box"]);
-        $captureBox  = CreatePolygon($array);
-        
-        $array       = explode(",", $args["normalized_box"]);
-        $normalizedCapture = CreatePolygon($array);
-    }
-    
-    function CreatePolygon($coordinates)
-    {
-        $geometryFactory      = new MgGeometryFactory();
-        $coordinateCollection = new MgCoordinateCollection();
-        $linearRingCollection = new MgLinearRingCollection();
-        
-        for ($index = 0; $index < count($coordinates); ++$index)
-        {
-            $coordinate = $geometryFactory->CreateCoordinateXY(floatval($coordinates[$index]), floatval($coordinates[++$index]));
-            $coordinateCollection->Add($coordinate);
-        }
-        
-        $coordinateCollection->Add($geometryFactory->CreateCoordinateXY(floatval($coordinates[0]), floatval($coordinates[1])));
-        
-        $linearRingCollection = $geometryFactory->CreateLinearRing($coordinateCollection);
-        $captureBox           = $geometryFactory->CreatePolygon($linearRingCollection, null);
-        
-        return $captureBox;
-    }
-
-    function GenerateMap($size)
-    {
-        global $sessionID, $mapName, $captureBox, $printSize, $normalizedCapture, $rotation, $scaleDenominator, $printDpi;
-        
-        $userInfo         = new MgUserInformation($sessionID);
-        $siteConnection   = new MgSiteConnection();
-        $siteConnection->Open($userInfo);
-        $resourceService  = $siteConnection->CreateService(MgServiceType::ResourceService);
-        $renderingService = $siteConnection->CreateService(MgServiceType::RenderingService);
-        
-        $map = new MgMap();
-        $map->Open($resourceService, $mapName);
-        
-        $selection        = new MgSelection($map);
-        $color            = new MgColor(255, 255, 255);
-        
-        // Calculate the generated picture size
-        $envelope         = $captureBox->Envelope();
-        $normalizedE      = $normalizedCapture->Envelope();
-        $size1            = new Size($envelope->getWidth(), $envelope->getHeight());
-        $size2            = new Size($normalizedE->getWidth(), $normalizedE->getHeight());
-        $toSize           = new Size($size1->width / $size2->width * $size->width, $size1->height / $size2->height * $size->height);
-        $center           = $captureBox->GetCentroid()->GetCoordinate();
-        
-        // Get the map agent url
-        // Get the correct http protocal
-        $mapAgent = "http";
-        if ($_SERVER["HTTPS"] == "on")
-        {
-            $mapAgent .= "s";
-        }
-        // Get the correct port number
-		$mapAgent .= "://127.0.0.1:" . $_SERVER["SERVER_PORT"];
-        // Get the correct virtual directory
-        $mapAgent .= substr($_SERVER["REQUEST_URI"], 0, strpos($_SERVER["REQUEST_URI"], "/", 1));
-        $mapAgent .="/mapagent/mapagent.fcgi?VERSION=1.0.0&OPERATION=GETMAPIMAGE" .
-                    "&SESSION=$sessionID" .  
-                    "&MAPNAME=$mapName" .
-                    "&FORMAT=PNG" .
-                    "&SETVIEWCENTERX=" . $center->GetX() .
-                    "&SETVIEWCENTERY=" . $center->GetY() .
-                    "&SETVIEWSCALE=$scaleDenominator" . 
-                    "&SETDISPLAYDPI=$printDpi" . 
-                    "&SETDISPLAYWIDTH=$toSize->width" . 
-                    "&SETDISPLAYHEIGHT=$toSize->height" . 
-                    "&CLIP=0";
-
-        $image = imagecreatefrompng($mapAgent);
-        // Rotate the picture back to be normalized
-        $normalizedImg = imagerotate($image, -$rotation, 0);
-        // Free the original image
-        imagedestroy($image);
-        // Crop the normalized image
-        $croppedImg = imagecreatetruecolor($size->width, $size->height);
-        imagecopy($croppedImg, $normalizedImg, 0, 0, (imagesx($normalizedImg) - $size->width) / 2, (imagesy($normalizedImg) - $size->height) / 2, $size->width, $size->height);
-        // Free the normalized image
-        imagedestroy($normalizedImg);
-        // Draw the north arrow on the map
-        DrawNorthArrow($croppedImg);
-
-        header ("Content-type: image/png"); 
-        imagepng($croppedImg);
-        imagedestroy($croppedImg);
-    }
-    
-    function DrawNorthArrow($map)
-    {
-        global $paperSize, $rotation;
-        
-        // Load the north arrow image which has a 300 dpi resolution
-        $na         = imagecreatefrompng("./north_arrow.png");
-        // Rotate the north arrow according to the capture rotation
-        $transparent= imagecolortransparent($na);
-        $rotatedNa  = imagerotate($na, -$rotation, $transparent);
-        // Free the north arrow image
-        imagedestroy($na);
-        // Get the size of north arrow image
-        $naWidth    = imagesx($rotatedNa);
-        $naHeight   = imagesy($rotatedNa);
-        // Get the map size
-        $mapWidth   = imagesx($map);
-        $mapHeight  = imagesy($map);
-        // Get the logical resolution of map
-        $resolution = $mapWidth * 25.4 / $paperSize->width;
-        // On printed paper, north arrow is located at the right bottom corner with 6 MM margin
-        $naRes      = 300;
-        $naMargin   = 12;
-        // Calculate the margin as pixels according to the resolutions
-        $margin     = $resolution * $naMargin / 25.4;
-        // Get the width of the north arrow on the map picture
-        $drawWidth  = $naWidth * $resolution / $naRes;
-        $drawHeight = $naHeight * $resolution / $naRes;
-        // Draw the north arrow on the map picture
-        imagecopyresized($map, $rotatedNa, $mapWidth - $drawWidth - $margin, $mapHeight - $drawHeight - $margin, 0, 0, $drawWidth, $drawHeight, $naWidth, $naHeight);
-        // Free the north arrow image
-        imagedestroy($rotatedNa); 
-    }
-?>
-
-<?php    
-    class Size
-    {
-        public $width;
-        public $height;
-        
-        public function __construct($width, $height)
-        {
-            $this->width  = $width;
-            $this->height = $height;
-        }
-    }
-?>
\ No newline at end of file

Copied: branches/fusion-2.2/widgets/QuickPlot/GeneratePicture.php (from rev 2233, trunk/widgets/QuickPlot/GeneratePicture.php)
===================================================================
--- branches/fusion-2.2/widgets/QuickPlot/GeneratePicture.php	                        (rev 0)
+++ branches/fusion-2.2/widgets/QuickPlot/GeneratePicture.php	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,182 @@
+<?php
+    $fusionMGpath = '../../layers/MapGuide/php/';
+    include $fusionMGpath . 'Utilities.php';
+
+    $fusionMGpath = '../../layers/MapGuide/php/';
+    include $fusionMGpath . 'Common.php';
+    
+    $sessionID = "";
+    $mapName   = "";
+    $rotation  = 0.0;
+    $printDpi  = 300;
+    $scaleDenominator = 0;
+    $captureBox;
+    $normalizedCapture;
+    $printSize;
+    $paperSize;
+    
+    GetParameters();
+    GenerateMap($printSize);
+?>
+
+<?php    
+    function GetParameters()
+    {
+        global $sessionID, $mapName, $printDpi, $rotation, $paperSize, $captureBox, $printSize, $scaleDenominator, $normalizedCapture;
+        $args = $_GET;
+        if ($_SERVER["REQUEST_METHOD"] == "POST")
+        {
+            $args = $_POST;
+        }
+        
+        // Not necessary to validate the parameters    	
+        $sessionID   = $args["session_id"];
+        $mapName     = $args["map_name"];
+        $rotation    = floatval($args["rotation"]);
+        $printDpi    = intval($args["print_dpi"]);
+
+        $scaleDenominator = intval($args["scale_denominator"]);
+
+        $array       = explode(",", $args["paper_size"]);
+        $paperSize   = new Size(floatval($array[0]), floatval($array[1]));
+        $printSize   = new Size($paperSize->width / 25.4 * $printDpi, $paperSize->height / 25.4 * $printDpi);
+        
+        $array       = explode(",", $args["box"]);
+        $captureBox  = CreatePolygon($array);
+        
+        $array       = explode(",", $args["normalized_box"]);
+        $normalizedCapture = CreatePolygon($array);
+    }
+    
+    function CreatePolygon($coordinates)
+    {
+        $geometryFactory      = new MgGeometryFactory();
+        $coordinateCollection = new MgCoordinateCollection();
+        $linearRingCollection = new MgLinearRingCollection();
+        
+        for ($index = 0; $index < count($coordinates); ++$index)
+        {
+            $coordinate = $geometryFactory->CreateCoordinateXY(floatval($coordinates[$index]), floatval($coordinates[++$index]));
+            $coordinateCollection->Add($coordinate);
+        }
+        
+        $coordinateCollection->Add($geometryFactory->CreateCoordinateXY(floatval($coordinates[0]), floatval($coordinates[1])));
+        
+        $linearRingCollection = $geometryFactory->CreateLinearRing($coordinateCollection);
+        $captureBox           = $geometryFactory->CreatePolygon($linearRingCollection, null);
+        
+        return $captureBox;
+    }
+
+    function GenerateMap($size)
+    {
+        global $sessionID, $mapName, $captureBox, $printSize, $normalizedCapture, $rotation, $scaleDenominator, $printDpi;
+        
+        $userInfo         = new MgUserInformation($sessionID);
+        $siteConnection   = new MgSiteConnection();
+        $siteConnection->Open($userInfo);
+        $resourceService  = $siteConnection->CreateService(MgServiceType::ResourceService);
+        $renderingService = $siteConnection->CreateService(MgServiceType::RenderingService);
+        
+        $map = new MgMap();
+        $map->Open($resourceService, $mapName);
+        
+        $selection        = new MgSelection($map);
+        $color            = new MgColor(255, 255, 255);
+        
+        // Calculate the generated picture size
+        $envelope         = $captureBox->Envelope();
+        $normalizedE      = $normalizedCapture->Envelope();
+        $size1            = new Size($envelope->getWidth(), $envelope->getHeight());
+        $size2            = new Size($normalizedE->getWidth(), $normalizedE->getHeight());
+        $toSize           = new Size($size1->width / $size2->width * $size->width, $size1->height / $size2->height * $size->height);
+        $center           = $captureBox->GetCentroid()->GetCoordinate();
+        
+        // Get the map agent url
+        // Get the correct http protocal
+        $mapAgent = "http";
+        if ($_SERVER["HTTPS"] == "on")
+        {
+            $mapAgent .= "s";
+        }
+        // Get the correct port number
+		$mapAgent .= "://127.0.0.1:" . $_SERVER["SERVER_PORT"];
+        // Get the correct virtual directory
+        $mapAgent .= substr($_SERVER["REQUEST_URI"], 0, strpos($_SERVER["REQUEST_URI"], "/", 1));
+        $mapAgent .="/mapagent/mapagent.fcgi?VERSION=1.0.0&OPERATION=GETMAPIMAGE" .
+                    "&SESSION=$sessionID" .  
+                    "&MAPNAME=$mapName" .
+                    "&FORMAT=PNG" .
+                    "&SETVIEWCENTERX=" . $center->GetX() .
+                    "&SETVIEWCENTERY=" . $center->GetY() .
+                    "&SETVIEWSCALE=$scaleDenominator" . 
+                    "&SETDISPLAYDPI=$printDpi" . 
+                    "&SETDISPLAYWIDTH=$toSize->width" . 
+                    "&SETDISPLAYHEIGHT=$toSize->height" . 
+                    "&CLIP=0";
+
+        $image = imagecreatefrompng($mapAgent);
+        // Rotate the picture back to be normalized
+        $normalizedImg = imagerotate($image, -$rotation, 0);
+        // Free the original image
+        imagedestroy($image);
+        // Crop the normalized image
+        $croppedImg = imagecreatetruecolor($size->width, $size->height);
+        imagecopy($croppedImg, $normalizedImg, 0, 0, (imagesx($normalizedImg) - $size->width) / 2, (imagesy($normalizedImg) - $size->height) / 2, $size->width, $size->height);
+        // Free the normalized image
+        imagedestroy($normalizedImg);
+        // Draw the north arrow on the map
+        DrawNorthArrow($croppedImg);
+
+        header ("Content-type: image/png"); 
+        imagepng($croppedImg);
+        imagedestroy($croppedImg);
+    }
+    
+    function DrawNorthArrow($map)
+    {
+        global $paperSize, $rotation;
+        
+        // Load the north arrow image which has a 300 dpi resolution
+        $na         = imagecreatefrompng("./north_arrow.png");
+        // Rotate the north arrow according to the capture rotation
+        $transparent= imagecolortransparent($na);
+        $rotatedNa  = imagerotate($na, -$rotation, $transparent);
+        // Free the north arrow image
+        imagedestroy($na);
+        // Get the size of north arrow image
+        $naWidth    = imagesx($rotatedNa);
+        $naHeight   = imagesy($rotatedNa);
+        // Get the map size
+        $mapWidth   = imagesx($map);
+        $mapHeight  = imagesy($map);
+        // Get the logical resolution of map
+        $resolution = $mapWidth * 25.4 / $paperSize->width;
+        // On printed paper, north arrow is located at the right bottom corner with 6 MM margin
+        $naRes      = 300;
+        $naMargin   = 12;
+        // Calculate the margin as pixels according to the resolutions
+        $margin     = $resolution * $naMargin / 25.4;
+        // Get the width of the north arrow on the map picture
+        $drawWidth  = $naWidth * $resolution / $naRes;
+        $drawHeight = $naHeight * $resolution / $naRes;
+        // Draw the north arrow on the map picture
+        imagecopyresized($map, $rotatedNa, $mapWidth - $drawWidth - $margin, $mapHeight - $drawHeight - $margin, 0, 0, $drawWidth, $drawHeight, $naWidth, $naHeight);
+        // Free the north arrow image
+        imagedestroy($rotatedNa); 
+    }
+?>
+
+<?php    
+    class Size
+    {
+        public $width;
+        public $height;
+        
+        public function __construct($width, $height)
+        {
+            $this->width  = $width;
+            $this->height = $height;
+        }
+    }
+?>
\ No newline at end of file

Deleted: branches/fusion-2.2/widgets/QuickPlot/MapCapturer.js
===================================================================
--- trunk/widgets/QuickPlot/MapCapturer.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/QuickPlot/MapCapturer.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1,853 +0,0 @@
-/**
- * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
- */
- 
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Handler/Drag.js
- * @requires OpenLayers/Handler/Feature.js
- */
-
-/**
- * Class: OpenLayers.Control.MapCapturer
- * The MapCapturer control shows a box on the map to illustrate the area that will be captured.
- * Normally the capture information will be used to print the map. If the MapCapturer is configured not
- * show the capture box, then the current viewport will be used as the capture area.
- * 
- * The user can move or rotate the capture box to change the area he'd like to capture.
- * And the user can hold SHIFT key to snapp to a certain angle when he is rotating the capture box
- *
- * Inherits From:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.MapCapturer = OpenLayers.Class(OpenLayers.Control, {
-    /**
-     * Property: layer
-     * {<OpenLayers.Layer.Vector>}
-     */
-    layer: null,
-    
-    /**
-     * Property: feature. The active feature which is repsonding to mouse action
-     * {<OpenLayers.Feature.Vector>}
-     */
-    feature: null,
-
-    /**
-     * Property: captureBox. It's the feature represnting the capture area
-     * {<OpenLayers.Feature.Vector>}
-     */
-    captureBox: null,
-    
-    /**
-     * Property: rotateHandle. It's the feature representing a rotate handle
-     * (<OpenLayers.Feature.Vector)
-     */
-    rotateHandle: null,
-    
-    /**
-     * Property: rotateHandleStart. It's the feature representing the center point of capture box.
-     * And it's also the start point of the rotate handle.
-     * (<OpenLayers.Feature.Vector>)
-     */
-    rotateHandleStart: null,
-    
-    /**
-     * Property: rotateHandleEnd. It's the feature responding to the rotate command.
-     * (<OpenLayers.Feature.Vector>)
-     */
-    rotateHandleEnd: null,
-
-    /**
-     * Property: snappingLine. It's the feature indicating a certain angle to snap to. It shows up in the rotate process
-     * (<OpenLayers.Feature.Vector>)
-     */
-    snappingLine: null,
-    
-    /**
-     * Property: rotation. The rotation of the capture box
-     * {float}
-     */	
-    rotation: 0.0,
-    
-    /**
-     * Property: rotateHandleLength. Defines the length of the rotate handle 
-     * in pixel. default is 30 pixels
-     * {int}
-     */	
-    rotateHandleLength: 30,
-    
-    /**
-     * Property: captureBoxStyle. Style for the capture box
-     * {<OpenLayers.Style>}
-     */	
-    captureBoxStyle: null,
-    
-    /**
-     * Property: rotateHandleStyle. Style for the rotate handle
-     * (<OpenLayers.Style>)
-     */
-    rotateHandleStyle: null,
-    
-    /**
-     * Property: rotateHandlePointStyle. Style for the snap handle's start and end points
-     * (<OpenLayers.Style>)
-     */
-    rotateHandlePointStyle: null,
-    
-    /**
-     * Property: snappingLineStyle. Style for the snapping line
-     * (<OpenLayers.Style>)
-     */
-    snappingLineStyle: null,
-
-    /**
-     * Indicates if the capture box is enabled. An enabled capture box will show up on the map
-     * {bool}
-     */	
-    enabled: false,
-    
-    /**
-     * Property: warningMessage. The warning message when the capture box cannot display completely in current zoom level
-     * (string)
-     */
-    warningMessage: OpenLayers.i18n("quickPlotResolutionWarning"),
-    
-    /**
-     * Property: rotateSnappingStep. Defines the rotate snapping angle step. In degrees
-     * (int)
-     */
-    rotateSnappingStep: 45,
-    
-    /**
-     * Property: rotateSnappingTolerance. Defines the rotate snapping tolerance. In degress
-     */
-    rotateSnappingTolerance: 2,
-    
-    /**
-     * Property: lastPixel. The last position the mouse action was responded
-     * {<OpenLayers.Pixel>}
-     */
-    lastPixel: null,
-
-    /**
-     * Constructor: OpenLayers.Control.DragFeature
-     * Create a new control to drag features.
-     *
-     * Parameters:
-     * map - The widget map which encapsulates an OpenLayers.Map
-     *
-     * options - {Object} Optional object whose properties will be set on the control.
-     */
-    initialize: function(map, options) 
-    {
-        OpenLayers.Control.prototype.initialize.apply(this, [options]);
-        
-        // Initialize the styles
-        this.captureBoxStyle = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
-        this.captureBoxStyle.fillOpacity    = 0.8;
-        this.captureBoxStyle.fillColor      = "#476387";
-        this.captureBoxStyle.strokeColor    = "#39506F";
-        
-        this.rotateHandleStyle              = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
-        this.rotateHandleStyle.strokeColor  = "#39506F";
-        this.rotateHandlePointStyle             = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
-        this.rotateHandlePointStyle.strokeColor = "#39506F";
-        this.rotateHandlePointStyle.fillOpacity = 1.0;
-        this.rotateHandlePointStyle.fillColor   = "#476387";
-        this.rotateHandlePointStyle.pointRadius = 4;
-        
-        this.snappingLineStyle = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
-        this.snappingLineStyle.strokeOpacity   = 0.8;
-        this.snappingLineStyle.strokeColor     = "black";
-        this.snappingLineStyle.strokeDashstyle = "dot";
-
-        
-        // The cursor styles
-        this.cursorMove   = "move";
-        this.cursorRotate = "url(../../../Widgets/QuickPlot/rotate.cur), default";
-        
-        // The widget map
-        this.wMap = map;
-        
-        // Create a new layer to show the capture box
-        this.layer  = new OpenLayers.Layer.Vector("Map Capturer Layer");
-        map.oMapOL.addLayer(this.layer);
-        
-        // Create the features
-        this.captureBox        = new OpenLayers.Feature.Vector(null, null, this.captureBoxStyle);
-        this.rotateHandle      = new OpenLayers.Feature.Vector(null, null, this.rotateHandleStyle);
-        this.rotateHandleStart = new OpenLayers.Feature.Vector(null, null, this.rotateHandlePointStyle);
-        this.rotateHandleEnd   = new OpenLayers.Feature.Vector(null, null, this.rotateHandlePointStyle);
-        this.snappingLine      = new OpenLayers.Feature.Vector(null, null, this.snappingLineStyle);
-        
-        // Add the features into the layer
-        this.layer.addFeatures([this.captureBox, this.rotateHandle, this.rotateHandleStart, this.rotateHandleEnd, this.snappingLine]);
-
-        // Overwrite layer's drawFeatures method to consider the map capturer's enable / disable
-        this.layer.drawFeature = (function(f, item, style)
-                {
-                    if (this.enabled)
-                    {
-                        f.apply(this.layer, Array.prototype.slice.call(arguments, 1));
-                    }
-                }).bind(this, this.layer.drawFeature);
-        this.handlers = 
-        {
-            drag: new OpenLayers.Handler.Drag(
-                this, OpenLayers.Util.extend({
-                    down: this.downFeature,
-                    up: this.upFeature,
-                    out: this.cancel,
-                    done: this.doneDragging
-                }, this.dragCallbacks)),
-            feature: new OpenLayers.Handler.Feature(
-                this, this.layer, OpenLayers.Util.extend({
-                    over: this.overFeature,
-                    out: this.outFeature
-                }, this.featureCallbacks),
-                {geometryTypes: this.geometryTypes}
-            )
-        };
-
-        // List to the mouse move event
-        this.handlers.drag.move = this.mouseMove.bind(this);
-        
-        // Listen to MAP_EXTENTS_CHANGED event to refresh the outer box because the 'delta' is fixed regardless current scale
-        var oMap = this.wMap.oMapOL;
-        oMap.events.register("zoomend", this, this.drawFeatures.bind(this));
-    },
-    
-    /**
-     * APIMethod: destroy
-     * Take care of things that are not handled in superclass
-     */
-    destroy: function() 
-    {
-        this.layer = null;
-        OpenLayers.Control.prototype.destroy.apply(this, []);
-    },
-
-    /**
-     * APIMethod: activate
-     * Activate the control and the feature handler.
-     * 
-     * Returns:
-     * {Boolean} Successfully activated the control and feature handler.
-     */
-    activate: function() 
-    {
-        return (this.handlers.feature.activate() &&
-                OpenLayers.Control.prototype.activate.apply(this, arguments));
-    },
-
-    /**
-     * APIMethod: deactivate
-     * Deactivate the control and all handlers.
-     * 
-     * Returns:
-     * {Boolean} Successfully deactivated the control.
-     */
-    deactivate: function() {
-        // The return from the handlers is unimportant in this case
-        this.handlers.feature.deactivate();
-        this.handlers.drag.deactivate();
-        this.feature   = null;
-        this.dragging  = false;
-        this.lastPixel = null;
-
-        return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
-    },
-
-    /**
-     * Method: overFeature
-     * Called when the feature handler detects a mouse-over on a feature.
-     *     This enables the drag control if the event target is the outer polygon,
-     *		and the rotate control will be activated if the event target is the inner polygon
-     *
-     * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>} The selected feature.
-     */
-    overFeature: function(feature) 
-    {
-        // The feature that the cursor stops on
-        this.stopFeature = feature;
-        
-        if(!this.handlers.drag.dragging) 
-        {
-            this.feature = feature;
-            this.handlers.drag.activate();
-            this.over = true;
-            
-            this.setCursor(); 
-        } 
-        else 
-        {
-            if(this.captureBox.id == feature.id || this.rotateHandleEnd.id == feature.id) 
-            {
-                this.over = true;
-            } 
-            else 
-            {
-                this.over = false;
-            }
-        }
-    },
-    
-    /**
-     * Method: dragging
-     * Check if it's currently in dragging to move mode
-     */
-    dragging: function() 
-    {
-        if (this.feature && this.captureBox)
-        {
-            return this.feature.id == this.captureBox.id || this.feature.id == this.rotateHandleStart.id;
-        }
-        
-        return false;
-    },
-    
-    /**
-     * Method: dragging
-     * Check if it's currently in dragging to rotate mode
-     */
-    rotating: function() 
-    {
-        return this.feature && this.rotateHandleEnd && this.feature.id == this.rotateHandleEnd.id;
-    },
-
-    /**
-     * Method: downFeature
-     * Called when the drag handler detects a mouse-down.
-     *
-     * Parameters:
-     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
-     */
-    downFeature: function(pixel) 
-    {
-        this.setCursor();
-        this.lastPixel = pixel;
-    },
-    
-    /**
-     * Method: setCursor
-     * Set the cursor according to current action: moving or rotating
-     */
-    setCursor: function() 
-    {
-        if (this.dragging())
-        {
-            this.wMap.setCursor(this.cursorMove);
-        }
-        else if (this.rotating())
-        {
-            this.wMap.setCursor(this.cursorRotate);
-        }
-    },
-    /**
-     * Method: moveFeature
-     * Called when the drag handler detects a mouse-move.  Also calls the
-     *     optional onDrag method.
-     */
-    mouseMove: function(evt) 
-    {
-        if (this.dragging()) 
-        {
-            this.moveFeature(evt);
-        }
-        else if (this.rotating()) 
-        {
-            this.rotateFeature(evt);
-        }
-    },
-    
-    /**
-     * Method: moveFeature
-     *  Move the feature according to the mouse-move
-     */
-    moveFeature: function(evt) 
-    {
-        pixel     = evt.xy;
-        var res   = this.wMap.getResolution();
-        var delta = {x:res * (pixel.x - this.lastPixel.x), y:res * (this.lastPixel.y - pixel.y)};
-        
-        var features = this.layer.features;
-        for (var i = 0; i < features.length; ++i)
-        {
-            // Don't touch the snapping line
-            if (features[i].geometry != null && features[i].id != this.snappingLine.id)
-            {
-                features[i].geometry.move(delta.x, delta.y);
-                this.layer.drawFeature(features[i]);
-            }
-        }
-        
-        this.lastPixel = pixel;
-    },
-    
-    /**
-     * Method: moveFeature
-     * Called when the drag handler detects a mouse-move.  Also calls the
-     *     optional onDrag method.
-     */
-    rotateFeature: function(evt)
-    {
-        pixel = evt.xy;
-        var centroid   = this.captureBox.geometry.getCentroid();
-        var origin     = this.map.getViewPortPxFromLonLat(new OpenLayers.LonLat(centroid.x, centroid.y));
-        var angle      = this.calculateAngle(pixel, origin);
-        var rotation   = this.rotation + angle;
-
-        if (evt.shiftKey)
-        {
-            var a = rotation % this.rotateSnappingStep;
-            var b = Math.round(rotation / this.rotateSnappingStep);
-            var targetRotation = rotation;
-            
-            if (Math.abs(a) <= this.rotateSnappingTolerance || Math.abs(a)>= this.rotateSnappingStep - this.rotateSnappingTolerance)
-            {
-                targetRotation = b * this.rotateSnappingStep;
-                
-                // Draw the snapping guide
-                if (this.snappingLine.geometry == null)
-                {
-                    this.drawSnappingHint(targetRotation);
-                }
-            }
-            else
-            {
-                this.clearSnappingHint();
-            }
-            
-            angle = targetRotation - this.rotation;
-        }
-        else
-        {
-            this.clearSnappingHint();
-        }
-        
-        this.rotation += angle;
-        
-        var features = this.layer.features;
-        for (var i = 0; i < features.length; ++i)
-        {
-            // Don't touch the snapping line here because the snapping line is controlled only by drawSnappingHint
-            if (features[i].geometry != null && features[i].id != this.snappingLine.id)
-            {
-                features[i].geometry.rotate(angle, centroid);
-                this.layer.drawFeature(features[i]);
-            }
-        }
-
-        this.lastPixel = angle == 0 ? this.lastPixel : pixel;
-    },
-    
-    /**
-     * Method: drawSnappingHint
-     * Draw the snapping line
-     */
-    drawSnappingHint: function(angle)
-    {
-        var viewSize = this.wMap.getCurrentExtents().getSize();
-        var length   = Math.sqrt(Math.pow(viewSize.w, 2) + Math.pow(viewSize.h, 2));
-        var origin   = this.captureBox.geometry.getCentroid();
-        
-        var points   = [];
-        points.push(new OpenLayers.Geometry.Point(origin.x - length, origin.y));
-        points.push(new OpenLayers.Geometry.Point(origin.x + length, origin.y));
-        var hint     = new OpenLayers.Geometry.LineString(points);
-        
-        hint.rotate(angle + 90, origin);
-        
-        this.snappingLine.geometry = hint;
-        this.layer.drawFeature(this.snappingLine);
-    },
-    
-    /**
-     * Method: clearSnappingHint
-     * Clear the snapping line
-     */
-    clearSnappingHint: function()
-    {
-        if (this.snappingLine != null && this.snappingLine.geometry != null)
-        {
-            this.layer.eraseFeatures([this.snappingLine]);
-            this.snappingLine.geometry = null;
-        }
-    },
-    
-    /**
-     * Method: calculateAngle
-     * Calculates the rotate angle, in degree and counterclockwise
-     */
-    calculateAngle: function(pixel, origin)
-    {
-        var angle1 = Math.atan2(pixel.y - origin.y, pixel.x - origin.x);
-        var angle2 = Math.atan2(this.lastPixel.y - origin.y, this.lastPixel.x - origin.x);
-        return (angle2 - angle1) * 180 / Math.PI;
-    },
-
-    /**
-     * Method: upFeature
-     * Called when the drag handler detects a mouse-up.
-     * 
-     * Parameters:
-     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
-     */
-    upFeature: function(pixel) 
-    {
-        if(!this.over) 
-        {
-            this.handlers.drag.deactivate();
-        }
-        else
-        {
-            // Set the last-stop feature to be the active one
-            this.feature = this.stopFeature;
-            // Set the correct cursor
-            this.setCursor();
-        }
-        
-        this.clearSnappingHint();
-    },
-
-    /**
-     * Method: outFeature
-     * Called when the feature handler detects a mouse-out on a feature.
-     *
-     * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left.
-     */
-    outFeature: function(feature) 
-    {
-        if(!this.handlers.drag.dragging) 
-        {
-            this.over = false;
-            this.handlers.drag.deactivate();
-            this.wMap.setCursor("auto");            
-            this.feature = null;
-        } 
-        else 
-        {
-            if(this.feature.id == feature.id) 
-            {
-                this.over = false;
-            }
-        }
-    },
-        
-    /**
-     * Method: cancel
-     * Called when the drag handler detects a mouse-out (from the map viewport).
-     */
-    cancel: function() 
-    {
-        this.handlers.drag.deactivate();
-        this.over = false;
-    },
-
-    /**
-     * Method: setMap
-     * Set the map property for the control and all handlers.
-     *
-     * Parameters: 
-     * map - {<OpenLayers.Map>} The control's map.
-     */
-    setMap: function(map) 
-    {
-        this.handlers.drag.setMap(map);
-        this.handlers.feature.setMap(map);
-        OpenLayers.Control.prototype.setMap.apply(this, arguments);
-    },
-
-    /**
-     * Method: setRegion
-     * Set the size of the capture box. Then the box will be redrawn on the map
-     *
-     * Parameters: 
-     * paperSize - {<OpenLayers.Size>} The paper size, in mm
-     * scaleDenominator - The denominator of target scale
-     */
-    setSize: function(paperSize, scaleDenominator) 
-    {
-        this.paperSize        = paperSize;
-        this.scaleDenominator = scaleDenominator;
-        this.drawFeatures();
-        // Active the handler
-        this.activate();
-    },
-    
-    /**
-     * Method: drawFeatures
-     * Draw the capture box, rotate handle etc. on the map
-     */
-    drawFeatures: function()
-    {
-        // The paper size is not set yet, so don't draw the features
-        if (!this.paperSize)
-        {
-            return;
-        }
-        
-        // Clear the previous drawn features
-        this.clearFeatures();
-                
-        this.createCaptureBox();
-        this.createRotateHandle();
-        
-        // Draw the box only when control is enabled and the resolution is valid
-        if (this.enabled) 
-        {
-            if (this.validateResolution())
-            {
-                this.layer.features.each(function(item){item.layer.drawFeature(item);});
-                this.wMap.message.hide();
-            }
-            else
-            {
-                this.wMap.message.warn(this.warningMessage);
-            }
-        }
-    },
-    
-    /**
-     * Method: clearFeatures:
-     * Clear the capture box, rotate handle etc. from the map
-     */
-    clearFeatures: function()
-    {
-        // Clear the previous drawn features
-        var features = this.layer.features;
-        var toErase  = [];
-        var feature  = null;
-        
-        for (var i = 0; i < features.length; ++i)
-        {
-            feature = features[i];
-            if (feature.geometry != null)
-            {
-                toErase.push(feature);
-            }
-        }
-        
-        this.layer.eraseFeatures(toErase);
-    },
-    
-    /**
-     * Method: createCaptureBox
-     * Create the capture box feature
-     */
-    createCaptureBox: function()
-    {
-        var origin   = null;
-        var rotation = 0;
-        
-        if (this.captureBox.geometry != null)
-        {
-            origin   = this.captureBox.geometry.getCentroid();
-            rotation = this.rotation;
-        }
-        else
-        {
-            origin   = this.wMap.getCurrentCenter();
-        }
-        
-        var factor = this.scaleDenominator / (this.wMap.getMetersPerUnit() * 1000 * 2);
-        
-        var pointList = [];
-        pointList.push(new OpenLayers.Geometry.Point(origin.x - this.paperSize.w * factor, origin.y - this.paperSize.h * factor));
-        pointList.push(new OpenLayers.Geometry.Point(origin.x + this.paperSize.w * factor, origin.y - this.paperSize.h * factor));
-        pointList.push(new OpenLayers.Geometry.Point(origin.x + this.paperSize.w * factor, origin.y + this.paperSize.h * factor));
-        pointList.push(new OpenLayers.Geometry.Point(origin.x - this.paperSize.w * factor, origin.y + this.paperSize.h * factor));
-        pointList.push(pointList[0]);
-        
-        var box = new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(pointList));
-        
-        if (rotation != 0)
-        {
-            box.rotate(rotation, box.getCentroid());
-        }
-        
-        this.captureBox.geometry = box;
-    },
-
-    /**
-     * Method: createRotateHandle
-     * Create the rotate handle feature
-     */
-    createRotateHandle: function()
-    {
-        var box        = this.captureBox.geometry.clone();
-        var startPoint = box.getCentroid();
-        
-        if (this.rotation != 0)
-        {
-            box.rotate(-this.rotation, startPoint);
-        }
-        
-        var length = this.rotateHandleLength * this.wMap.getResolution();
-        
-        var endPoint   = new OpenLayers.Geometry.Point(startPoint.x, startPoint.y + box.getBounds().getHeight() / 2 + length);
-        var line       = new OpenLayers.Geometry.LineString([startPoint.clone(), endPoint.clone()]);
-        
-        if (this.rotation != 0)
-        {
-            endPoint.rotate(this.rotation, startPoint);
-            line.rotate(this.rotation, startPoint);
-        }
-        
-        this.rotateHandle.geometry      = line;
-        this.rotateHandleStart.geometry = startPoint;
-        this.rotateHandleEnd.geometry   = endPoint;
-    },
-    
-    /**
-     * Method: validateResolution
-     * Check if the capture box could display completely on current screen view port.
-     * If it cannot, then an warning message will show up to warn the user. Then the user could zoom out to get
-     * the box back
-     * 
-     * Returns:
-     * (Boolean) True if the box can display completely, otherwise false.
-     *
-     */
-    validateResolution: function() 
-    {
-        if (this.captureBox)
-        {
-            var screenSize = this.map.getExtent().getSize();
-            var boxSize    = this.captureBox.geometry.getBounds().getSize();
-            
-            if (boxSize.w < screenSize.w || boxSize.h < screenSize.h)
-            {
-                return true;
-            }
-            else
-            {
-                return false;
-            }
-        }
-    },
-    
-    /**
-     * Method: getCaptureBox
-     * Get the capture area.
-     */
-    getCaptureBox: function()
-    {
-        var geometry;
-        // The capture box is not enabled, so just use the current viewport as capture box
-        if (!this.enabled)
-        {
-            geometry = this.wMap.getCurrentExtents().toGeometry(); 
-        }
-        else
-        {
-            geometry = this.captureBox.geometry;
-        }
-        
-        var info     = "";
-        var vertices = geometry.getVertices();
-        var vertex   = null;
-        
-        for (var i = 0; i < vertices.length; ++i)
-        {
-            vertex = vertices[i];
-            info += vertex.x + "," + vertex.y + ",";
-        }
-        
-        // Remove the last ","
-        info = info.substr(0, info.length - 1);
-        
-        return {geometry:geometry, params:info};
-    },
-    
-    /**
-     * Method: getNormalizedCapture
-     * Get the normalized capture box
-     */
-    getNormalizedCapture: function()
-    {
-        var info   = "";
-        var geometry = null;
-        if (!this.enabled)
-        {
-            geometry = this.wMap.getCurrentExtents().toGeometry();
-            // Calculate the scale denominator
-            
-        }
-        else
-        {
-            geometry = this.captureBox.geometry.clone();
-            geometry.rotate(-this.rotation, geometry.getCentroid());
-        }
-        
-        var vertices = geometry.getVertices();
-        var vertex   = null;
-        
-        for (var i = 0; i < vertices.length; ++i)
-        {
-            vertex = vertices[i];
-            info += vertex.x + "," + vertex.y + ",";
-        }
-        
-        // Remove the last ","
-        info = info.substr(0, info.length - 1);
-        
-        return {geometry:geometry, params:info};
-    },
-    
-    /**
-     * Method: getCaptureRotation
-     * Get the capture rotation
-     */
-    getCaptureRotation: function()
-    {
-        if (this.enabled)
-        {
-            return this.rotation;
-        }
-        else
-        {
-            return 0.0;
-        }
-    },
-    
-    /**
-     * Method: enable
-     * Enable the capture box to display it on the map
-     */
-    enable: function()
-    {
-        // Reset everything first
-        this.disable();
-        this.enabled = true;
-    },
-    
-    /**
-     * Method: disable
-     * Disable the capture box. Then the capture box will not show up on the Map,
-     * 		and the current view port is treated as the capture area
-     */
-    disable: function()
-    {
-        this.enabled  = false;
-
-        this.wMap.message.hide();
-        this.clearFeatures();
-        this.rotation = 0;
-        
-        var features = this.layer.features;
-        for (var i = 0; i < features.length; ++i)
-        {
-            features[i].geometry = null;
-        }
-    },
-    
-    /**
-     * Property: CLASS_NAME. The class name
-     */
-    CLASS_NAME: "OpenLayers.Control.MapCapturer"
-});
-

Copied: branches/fusion-2.2/widgets/QuickPlot/MapCapturer.js (from rev 2233, trunk/widgets/QuickPlot/MapCapturer.js)
===================================================================
--- branches/fusion-2.2/widgets/QuickPlot/MapCapturer.js	                        (rev 0)
+++ branches/fusion-2.2/widgets/QuickPlot/MapCapturer.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,853 @@
+/**
+ * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
+ */
+ 
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Drag.js
+ * @requires OpenLayers/Handler/Feature.js
+ */
+
+/**
+ * Class: OpenLayers.Control.MapCapturer
+ * The MapCapturer control shows a box on the map to illustrate the area that will be captured.
+ * Normally the capture information will be used to print the map. If the MapCapturer is configured not
+ * show the capture box, then the current viewport will be used as the capture area.
+ * 
+ * The user can move or rotate the capture box to change the area he'd like to capture.
+ * And the user can hold SHIFT key to snapp to a certain angle when he is rotating the capture box
+ *
+ * Inherits From:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.MapCapturer = OpenLayers.Class(OpenLayers.Control, {
+    /**
+     * Property: layer
+     * {<OpenLayers.Layer.Vector>}
+     */
+    layer: null,
+    
+    /**
+     * Property: feature. The active feature which is repsonding to mouse action
+     * {<OpenLayers.Feature.Vector>}
+     */
+    feature: null,
+
+    /**
+     * Property: captureBox. It's the feature represnting the capture area
+     * {<OpenLayers.Feature.Vector>}
+     */
+    captureBox: null,
+    
+    /**
+     * Property: rotateHandle. It's the feature representing a rotate handle
+     * (<OpenLayers.Feature.Vector)
+     */
+    rotateHandle: null,
+    
+    /**
+     * Property: rotateHandleStart. It's the feature representing the center point of capture box.
+     * And it's also the start point of the rotate handle.
+     * (<OpenLayers.Feature.Vector>)
+     */
+    rotateHandleStart: null,
+    
+    /**
+     * Property: rotateHandleEnd. It's the feature responding to the rotate command.
+     * (<OpenLayers.Feature.Vector>)
+     */
+    rotateHandleEnd: null,
+
+    /**
+     * Property: snappingLine. It's the feature indicating a certain angle to snap to. It shows up in the rotate process
+     * (<OpenLayers.Feature.Vector>)
+     */
+    snappingLine: null,
+    
+    /**
+     * Property: rotation. The rotation of the capture box
+     * {float}
+     */	
+    rotation: 0.0,
+    
+    /**
+     * Property: rotateHandleLength. Defines the length of the rotate handle 
+     * in pixel. default is 30 pixels
+     * {int}
+     */	
+    rotateHandleLength: 30,
+    
+    /**
+     * Property: captureBoxStyle. Style for the capture box
+     * {<OpenLayers.Style>}
+     */	
+    captureBoxStyle: null,
+    
+    /**
+     * Property: rotateHandleStyle. Style for the rotate handle
+     * (<OpenLayers.Style>)
+     */
+    rotateHandleStyle: null,
+    
+    /**
+     * Property: rotateHandlePointStyle. Style for the snap handle's start and end points
+     * (<OpenLayers.Style>)
+     */
+    rotateHandlePointStyle: null,
+    
+    /**
+     * Property: snappingLineStyle. Style for the snapping line
+     * (<OpenLayers.Style>)
+     */
+    snappingLineStyle: null,
+
+    /**
+     * Indicates if the capture box is enabled. An enabled capture box will show up on the map
+     * {bool}
+     */	
+    enabled: false,
+    
+    /**
+     * Property: warningMessage. The warning message when the capture box cannot display completely in current zoom level
+     * (string)
+     */
+    warningMessage: OpenLayers.i18n("quickPlotResolutionWarning"),
+    
+    /**
+     * Property: rotateSnappingStep. Defines the rotate snapping angle step. In degrees
+     * (int)
+     */
+    rotateSnappingStep: 45,
+    
+    /**
+     * Property: rotateSnappingTolerance. Defines the rotate snapping tolerance. In degress
+     */
+    rotateSnappingTolerance: 2,
+    
+    /**
+     * Property: lastPixel. The last position the mouse action was responded
+     * {<OpenLayers.Pixel>}
+     */
+    lastPixel: null,
+
+    /**
+     * Constructor: OpenLayers.Control.DragFeature
+     * Create a new control to drag features.
+     *
+     * Parameters:
+     * map - The widget map which encapsulates an OpenLayers.Map
+     *
+     * options - {Object} Optional object whose properties will be set on the control.
+     */
+    initialize: function(map, options) 
+    {
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        
+        // Initialize the styles
+        this.captureBoxStyle = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
+        this.captureBoxStyle.fillOpacity    = 0.8;
+        this.captureBoxStyle.fillColor      = "#476387";
+        this.captureBoxStyle.strokeColor    = "#39506F";
+        
+        this.rotateHandleStyle              = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
+        this.rotateHandleStyle.strokeColor  = "#39506F";
+        this.rotateHandlePointStyle             = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
+        this.rotateHandlePointStyle.strokeColor = "#39506F";
+        this.rotateHandlePointStyle.fillOpacity = 1.0;
+        this.rotateHandlePointStyle.fillColor   = "#476387";
+        this.rotateHandlePointStyle.pointRadius = 4;
+        
+        this.snappingLineStyle = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style["default"]);
+        this.snappingLineStyle.strokeOpacity   = 0.8;
+        this.snappingLineStyle.strokeColor     = "black";
+        this.snappingLineStyle.strokeDashstyle = "dot";
+
+        
+        // The cursor styles
+        this.cursorMove   = "move";
+        this.cursorRotate = "url(../../../Widgets/QuickPlot/rotate.cur), default";
+        
+        // The widget map
+        this.wMap = map;
+        
+        // Create a new layer to show the capture box
+        this.layer  = new OpenLayers.Layer.Vector("Map Capturer Layer");
+        map.oMapOL.addLayer(this.layer);
+        
+        // Create the features
+        this.captureBox        = new OpenLayers.Feature.Vector(null, null, this.captureBoxStyle);
+        this.rotateHandle      = new OpenLayers.Feature.Vector(null, null, this.rotateHandleStyle);
+        this.rotateHandleStart = new OpenLayers.Feature.Vector(null, null, this.rotateHandlePointStyle);
+        this.rotateHandleEnd   = new OpenLayers.Feature.Vector(null, null, this.rotateHandlePointStyle);
+        this.snappingLine      = new OpenLayers.Feature.Vector(null, null, this.snappingLineStyle);
+        
+        // Add the features into the layer
+        this.layer.addFeatures([this.captureBox, this.rotateHandle, this.rotateHandleStart, this.rotateHandleEnd, this.snappingLine]);
+
+        // Overwrite layer's drawFeatures method to consider the map capturer's enable / disable
+        this.layer.drawFeature = (function(f, item, style)
+                {
+                    if (this.enabled)
+                    {
+                        f.apply(this.layer, Array.prototype.slice.call(arguments, 1));
+                    }
+                }).bind(this, this.layer.drawFeature);
+        this.handlers = 
+        {
+            drag: new OpenLayers.Handler.Drag(
+                this, OpenLayers.Util.extend({
+                    down: this.downFeature,
+                    up: this.upFeature,
+                    out: this.cancel,
+                    done: this.doneDragging
+                }, this.dragCallbacks)),
+            feature: new OpenLayers.Handler.Feature(
+                this, this.layer, OpenLayers.Util.extend({
+                    over: this.overFeature,
+                    out: this.outFeature
+                }, this.featureCallbacks),
+                {geometryTypes: this.geometryTypes}
+            )
+        };
+
+        // List to the mouse move event
+        this.handlers.drag.move = this.mouseMove.bind(this);
+        
+        // Listen to MAP_EXTENTS_CHANGED event to refresh the outer box because the 'delta' is fixed regardless current scale
+        var oMap = this.wMap.oMapOL;
+        oMap.events.register("zoomend", this, this.drawFeatures.bind(this));
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Take care of things that are not handled in superclass
+     */
+    destroy: function() 
+    {
+        this.layer = null;
+        OpenLayers.Control.prototype.destroy.apply(this, []);
+    },
+
+    /**
+     * APIMethod: activate
+     * Activate the control and the feature handler.
+     * 
+     * Returns:
+     * {Boolean} Successfully activated the control and feature handler.
+     */
+    activate: function() 
+    {
+        return (this.handlers.feature.activate() &&
+                OpenLayers.Control.prototype.activate.apply(this, arguments));
+    },
+
+    /**
+     * APIMethod: deactivate
+     * Deactivate the control and all handlers.
+     * 
+     * Returns:
+     * {Boolean} Successfully deactivated the control.
+     */
+    deactivate: function() {
+        // The return from the handlers is unimportant in this case
+        this.handlers.feature.deactivate();
+        this.handlers.drag.deactivate();
+        this.feature   = null;
+        this.dragging  = false;
+        this.lastPixel = null;
+
+        return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
+    },
+
+    /**
+     * Method: overFeature
+     * Called when the feature handler detects a mouse-over on a feature.
+     *     This enables the drag control if the event target is the outer polygon,
+     *		and the rotate control will be activated if the event target is the inner polygon
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The selected feature.
+     */
+    overFeature: function(feature) 
+    {
+        // The feature that the cursor stops on
+        this.stopFeature = feature;
+        
+        if(!this.handlers.drag.dragging) 
+        {
+            this.feature = feature;
+            this.handlers.drag.activate();
+            this.over = true;
+            
+            this.setCursor(); 
+        } 
+        else 
+        {
+            if(this.captureBox.id == feature.id || this.rotateHandleEnd.id == feature.id) 
+            {
+                this.over = true;
+            } 
+            else 
+            {
+                this.over = false;
+            }
+        }
+    },
+    
+    /**
+     * Method: dragging
+     * Check if it's currently in dragging to move mode
+     */
+    dragging: function() 
+    {
+        if (this.feature && this.captureBox)
+        {
+            return this.feature.id == this.captureBox.id || this.feature.id == this.rotateHandleStart.id;
+        }
+        
+        return false;
+    },
+    
+    /**
+     * Method: dragging
+     * Check if it's currently in dragging to rotate mode
+     */
+    rotating: function() 
+    {
+        return this.feature && this.rotateHandleEnd && this.feature.id == this.rotateHandleEnd.id;
+    },
+
+    /**
+     * Method: downFeature
+     * Called when the drag handler detects a mouse-down.
+     *
+     * Parameters:
+     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
+     */
+    downFeature: function(pixel) 
+    {
+        this.setCursor();
+        this.lastPixel = pixel;
+    },
+    
+    /**
+     * Method: setCursor
+     * Set the cursor according to current action: moving or rotating
+     */
+    setCursor: function() 
+    {
+        if (this.dragging())
+        {
+            this.wMap.setCursor(this.cursorMove);
+        }
+        else if (this.rotating())
+        {
+            this.wMap.setCursor(this.cursorRotate);
+        }
+    },
+    /**
+     * Method: moveFeature
+     * Called when the drag handler detects a mouse-move.  Also calls the
+     *     optional onDrag method.
+     */
+    mouseMove: function(evt) 
+    {
+        if (this.dragging()) 
+        {
+            this.moveFeature(evt);
+        }
+        else if (this.rotating()) 
+        {
+            this.rotateFeature(evt);
+        }
+    },
+    
+    /**
+     * Method: moveFeature
+     *  Move the feature according to the mouse-move
+     */
+    moveFeature: function(evt) 
+    {
+        pixel     = evt.xy;
+        var res   = this.wMap.getResolution();
+        var delta = {x:res * (pixel.x - this.lastPixel.x), y:res * (this.lastPixel.y - pixel.y)};
+        
+        var features = this.layer.features;
+        for (var i = 0; i < features.length; ++i)
+        {
+            // Don't touch the snapping line
+            if (features[i].geometry != null && features[i].id != this.snappingLine.id)
+            {
+                features[i].geometry.move(delta.x, delta.y);
+                this.layer.drawFeature(features[i]);
+            }
+        }
+        
+        this.lastPixel = pixel;
+    },
+    
+    /**
+     * Method: moveFeature
+     * Called when the drag handler detects a mouse-move.  Also calls the
+     *     optional onDrag method.
+     */
+    rotateFeature: function(evt)
+    {
+        pixel = evt.xy;
+        var centroid   = this.captureBox.geometry.getCentroid();
+        var origin     = this.map.getViewPortPxFromLonLat(new OpenLayers.LonLat(centroid.x, centroid.y));
+        var angle      = this.calculateAngle(pixel, origin);
+        var rotation   = this.rotation + angle;
+
+        if (evt.shiftKey)
+        {
+            var a = rotation % this.rotateSnappingStep;
+            var b = Math.round(rotation / this.rotateSnappingStep);
+            var targetRotation = rotation;
+            
+            if (Math.abs(a) <= this.rotateSnappingTolerance || Math.abs(a)>= this.rotateSnappingStep - this.rotateSnappingTolerance)
+            {
+                targetRotation = b * this.rotateSnappingStep;
+                
+                // Draw the snapping guide
+                if (this.snappingLine.geometry == null)
+                {
+                    this.drawSnappingHint(targetRotation);
+                }
+            }
+            else
+            {
+                this.clearSnappingHint();
+            }
+            
+            angle = targetRotation - this.rotation;
+        }
+        else
+        {
+            this.clearSnappingHint();
+        }
+        
+        this.rotation += angle;
+        
+        var features = this.layer.features;
+        for (var i = 0; i < features.length; ++i)
+        {
+            // Don't touch the snapping line here because the snapping line is controlled only by drawSnappingHint
+            if (features[i].geometry != null && features[i].id != this.snappingLine.id)
+            {
+                features[i].geometry.rotate(angle, centroid);
+                this.layer.drawFeature(features[i]);
+            }
+        }
+
+        this.lastPixel = angle == 0 ? this.lastPixel : pixel;
+    },
+    
+    /**
+     * Method: drawSnappingHint
+     * Draw the snapping line
+     */
+    drawSnappingHint: function(angle)
+    {
+        var viewSize = this.wMap.getCurrentExtents().getSize();
+        var length   = Math.sqrt(Math.pow(viewSize.w, 2) + Math.pow(viewSize.h, 2));
+        var origin   = this.captureBox.geometry.getCentroid();
+        
+        var points   = [];
+        points.push(new OpenLayers.Geometry.Point(origin.x - length, origin.y));
+        points.push(new OpenLayers.Geometry.Point(origin.x + length, origin.y));
+        var hint     = new OpenLayers.Geometry.LineString(points);
+        
+        hint.rotate(angle + 90, origin);
+        
+        this.snappingLine.geometry = hint;
+        this.layer.drawFeature(this.snappingLine);
+    },
+    
+    /**
+     * Method: clearSnappingHint
+     * Clear the snapping line
+     */
+    clearSnappingHint: function()
+    {
+        if (this.snappingLine != null && this.snappingLine.geometry != null)
+        {
+            this.layer.eraseFeatures([this.snappingLine]);
+            this.snappingLine.geometry = null;
+        }
+    },
+    
+    /**
+     * Method: calculateAngle
+     * Calculates the rotate angle, in degree and counterclockwise
+     */
+    calculateAngle: function(pixel, origin)
+    {
+        var angle1 = Math.atan2(pixel.y - origin.y, pixel.x - origin.x);
+        var angle2 = Math.atan2(this.lastPixel.y - origin.y, this.lastPixel.x - origin.x);
+        return (angle2 - angle1) * 180 / Math.PI;
+    },
+
+    /**
+     * Method: upFeature
+     * Called when the drag handler detects a mouse-up.
+     * 
+     * Parameters:
+     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
+     */
+    upFeature: function(pixel) 
+    {
+        if(!this.over) 
+        {
+            this.handlers.drag.deactivate();
+        }
+        else
+        {
+            // Set the last-stop feature to be the active one
+            this.feature = this.stopFeature;
+            // Set the correct cursor
+            this.setCursor();
+        }
+        
+        this.clearSnappingHint();
+    },
+
+    /**
+     * Method: outFeature
+     * Called when the feature handler detects a mouse-out on a feature.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left.
+     */
+    outFeature: function(feature) 
+    {
+        if(!this.handlers.drag.dragging) 
+        {
+            this.over = false;
+            this.handlers.drag.deactivate();
+            this.wMap.setCursor("auto");            
+            this.feature = null;
+        } 
+        else 
+        {
+            if(this.feature.id == feature.id) 
+            {
+                this.over = false;
+            }
+        }
+    },
+        
+    /**
+     * Method: cancel
+     * Called when the drag handler detects a mouse-out (from the map viewport).
+     */
+    cancel: function() 
+    {
+        this.handlers.drag.deactivate();
+        this.over = false;
+    },
+
+    /**
+     * Method: setMap
+     * Set the map property for the control and all handlers.
+     *
+     * Parameters: 
+     * map - {<OpenLayers.Map>} The control's map.
+     */
+    setMap: function(map) 
+    {
+        this.handlers.drag.setMap(map);
+        this.handlers.feature.setMap(map);
+        OpenLayers.Control.prototype.setMap.apply(this, arguments);
+    },
+
+    /**
+     * Method: setRegion
+     * Set the size of the capture box. Then the box will be redrawn on the map
+     *
+     * Parameters: 
+     * paperSize - {<OpenLayers.Size>} The paper size, in mm
+     * scaleDenominator - The denominator of target scale
+     */
+    setSize: function(paperSize, scaleDenominator) 
+    {
+        this.paperSize        = paperSize;
+        this.scaleDenominator = scaleDenominator;
+        this.drawFeatures();
+        // Active the handler
+        this.activate();
+    },
+    
+    /**
+     * Method: drawFeatures
+     * Draw the capture box, rotate handle etc. on the map
+     */
+    drawFeatures: function()
+    {
+        // The paper size is not set yet, so don't draw the features
+        if (!this.paperSize)
+        {
+            return;
+        }
+        
+        // Clear the previous drawn features
+        this.clearFeatures();
+                
+        this.createCaptureBox();
+        this.createRotateHandle();
+        
+        // Draw the box only when control is enabled and the resolution is valid
+        if (this.enabled) 
+        {
+            if (this.validateResolution())
+            {
+                this.layer.features.each(function(item){item.layer.drawFeature(item);});
+                this.wMap.message.hide();
+            }
+            else
+            {
+                this.wMap.message.warn(this.warningMessage);
+            }
+        }
+    },
+    
+    /**
+     * Method: clearFeatures:
+     * Clear the capture box, rotate handle etc. from the map
+     */
+    clearFeatures: function()
+    {
+        // Clear the previous drawn features
+        var features = this.layer.features;
+        var toErase  = [];
+        var feature  = null;
+        
+        for (var i = 0; i < features.length; ++i)
+        {
+            feature = features[i];
+            if (feature.geometry != null)
+            {
+                toErase.push(feature);
+            }
+        }
+        
+        this.layer.eraseFeatures(toErase);
+    },
+    
+    /**
+     * Method: createCaptureBox
+     * Create the capture box feature
+     */
+    createCaptureBox: function()
+    {
+        var origin   = null;
+        var rotation = 0;
+        
+        if (this.captureBox.geometry != null)
+        {
+            origin   = this.captureBox.geometry.getCentroid();
+            rotation = this.rotation;
+        }
+        else
+        {
+            origin   = this.wMap.getCurrentCenter();
+        }
+        
+        var factor = this.scaleDenominator / (this.wMap.getMetersPerUnit() * 1000 * 2);
+        
+        var pointList = [];
+        pointList.push(new OpenLayers.Geometry.Point(origin.x - this.paperSize.w * factor, origin.y - this.paperSize.h * factor));
+        pointList.push(new OpenLayers.Geometry.Point(origin.x + this.paperSize.w * factor, origin.y - this.paperSize.h * factor));
+        pointList.push(new OpenLayers.Geometry.Point(origin.x + this.paperSize.w * factor, origin.y + this.paperSize.h * factor));
+        pointList.push(new OpenLayers.Geometry.Point(origin.x - this.paperSize.w * factor, origin.y + this.paperSize.h * factor));
+        pointList.push(pointList[0]);
+        
+        var box = new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(pointList));
+        
+        if (rotation != 0)
+        {
+            box.rotate(rotation, box.getCentroid());
+        }
+        
+        this.captureBox.geometry = box;
+    },
+
+    /**
+     * Method: createRotateHandle
+     * Create the rotate handle feature
+     */
+    createRotateHandle: function()
+    {
+        var box        = this.captureBox.geometry.clone();
+        var startPoint = box.getCentroid();
+        
+        if (this.rotation != 0)
+        {
+            box.rotate(-this.rotation, startPoint);
+        }
+        
+        var length = this.rotateHandleLength * this.wMap.getResolution();
+        
+        var endPoint   = new OpenLayers.Geometry.Point(startPoint.x, startPoint.y + box.getBounds().getHeight() / 2 + length);
+        var line       = new OpenLayers.Geometry.LineString([startPoint.clone(), endPoint.clone()]);
+        
+        if (this.rotation != 0)
+        {
+            endPoint.rotate(this.rotation, startPoint);
+            line.rotate(this.rotation, startPoint);
+        }
+        
+        this.rotateHandle.geometry      = line;
+        this.rotateHandleStart.geometry = startPoint;
+        this.rotateHandleEnd.geometry   = endPoint;
+    },
+    
+    /**
+     * Method: validateResolution
+     * Check if the capture box could display completely on current screen view port.
+     * If it cannot, then an warning message will show up to warn the user. Then the user could zoom out to get
+     * the box back
+     * 
+     * Returns:
+     * (Boolean) True if the box can display completely, otherwise false.
+     *
+     */
+    validateResolution: function() 
+    {
+        if (this.captureBox)
+        {
+            var screenSize = this.map.getExtent().getSize();
+            var boxSize    = this.captureBox.geometry.getBounds().getSize();
+            
+            if (boxSize.w < screenSize.w || boxSize.h < screenSize.h)
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    },
+    
+    /**
+     * Method: getCaptureBox
+     * Get the capture area.
+     */
+    getCaptureBox: function()
+    {
+        var geometry;
+        // The capture box is not enabled, so just use the current viewport as capture box
+        if (!this.enabled)
+        {
+            geometry = this.wMap.getCurrentExtents().toGeometry(); 
+        }
+        else
+        {
+            geometry = this.captureBox.geometry;
+        }
+        
+        var info     = "";
+        var vertices = geometry.getVertices();
+        var vertex   = null;
+        
+        for (var i = 0; i < vertices.length; ++i)
+        {
+            vertex = vertices[i];
+            info += vertex.x + "," + vertex.y + ",";
+        }
+        
+        // Remove the last ","
+        info = info.substr(0, info.length - 1);
+        
+        return {geometry:geometry, params:info};
+    },
+    
+    /**
+     * Method: getNormalizedCapture
+     * Get the normalized capture box
+     */
+    getNormalizedCapture: function()
+    {
+        var info   = "";
+        var geometry = null;
+        if (!this.enabled)
+        {
+            geometry = this.wMap.getCurrentExtents().toGeometry();
+            // Calculate the scale denominator
+            
+        }
+        else
+        {
+            geometry = this.captureBox.geometry.clone();
+            geometry.rotate(-this.rotation, geometry.getCentroid());
+        }
+        
+        var vertices = geometry.getVertices();
+        var vertex   = null;
+        
+        for (var i = 0; i < vertices.length; ++i)
+        {
+            vertex = vertices[i];
+            info += vertex.x + "," + vertex.y + ",";
+        }
+        
+        // Remove the last ","
+        info = info.substr(0, info.length - 1);
+        
+        return {geometry:geometry, params:info};
+    },
+    
+    /**
+     * Method: getCaptureRotation
+     * Get the capture rotation
+     */
+    getCaptureRotation: function()
+    {
+        if (this.enabled)
+        {
+            return this.rotation;
+        }
+        else
+        {
+            return 0.0;
+        }
+    },
+    
+    /**
+     * Method: enable
+     * Enable the capture box to display it on the map
+     */
+    enable: function()
+    {
+        // Reset everything first
+        this.disable();
+        this.enabled = true;
+    },
+    
+    /**
+     * Method: disable
+     * Disable the capture box. Then the capture box will not show up on the Map,
+     * 		and the current view port is treated as the capture area
+     */
+    disable: function()
+    {
+        this.enabled  = false;
+
+        this.wMap.message.hide();
+        this.clearFeatures();
+        this.rotation = 0;
+        
+        var features = this.layer.features;
+        for (var i = 0; i < features.length; ++i)
+        {
+            features[i].geometry = null;
+        }
+    },
+    
+    /**
+     * Property: CLASS_NAME. The class name
+     */
+    CLASS_NAME: "OpenLayers.Control.MapCapturer"
+});
+

Deleted: branches/fusion-2.2/widgets/QuickPlot/PreviewDialog.js
===================================================================
--- trunk/widgets/QuickPlot/PreviewDialog.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/QuickPlot/PreviewDialog.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1,368 +0,0 @@
-/**
- * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
- */
-
-var PreviewDialog = function(options)
-{
-    this.initialize(options);
-};
-
-PreviewDialog.prototype = 
-{
-    jxDialog : null,
-    previewFrame : null,
-    innerDoc : null,
-    indicator : null,
-    previewPicture : null,
-    printPicture : null,
-    topLeftXYLabel : null,
-    bottomRightXYLabel : null,
-    previewContainer : null,
-    pictureContainer : null,
-    printButton : null,
-    cancelButton : null,
-    loadingErrorMessage : null,
-    printStyle: null,
-    previewStyle: null,
-    // The offset from the border of the paper, in px 
-    csLabelOffset : 5,
-    // The print margin, in inches
-    printMargin: 0,
-    mapInfo : {sessionID: "", name: ""},
-    captureInfo : {topLeftCs : {x : 0, y : 0}, bottomRightCs : {x : 0, y : 0}, paperSize:{w : 0, h : 0}, scaleDenominator : 0, rotation : 0, params1 : "", params2 : ""},
-    params : null,
-    
-    // The callback will be called right after the JxDialog content has been loaded.
-    // The callback accepts 1 parameter: windowName (string)
-    // Here it is used to submit the quick plot form to the preview frame.
-    contentLoadedCallback : null,
-    
-    initialize : function(options)
-    {
-        this.mapInfo      = options.mapInfo;
-        this.captureInfo  = options.captureInfo;
-        this.params       = options.params;
-        
-        this.jxDialog = new Jx.Dialog(
-        {
-            modal: true,
-            width:400,
-            height: 400,
-            content: '<table border="0" cellspacing="0" cellpadding="0" id="PreviewContainer">' + 
-                     '	<tr>' + 
-                     '		<td>' + 
-                     '			<iframe id="PreviewFrame" scrolling="no" frameborder="0" style="border: 0px; width: 400px; height: 300px;" src="about:blank"></iframe>' +
-                     '		</td>' +
-                     '  </tr>' +
-                     '</table>'
-        });
-        
-        this.jxDialog.addEvent("open", this.jxDialogOpened.bind(this, true));
-        this.jxDialog.addEvent("contentLoaded", this.jxDialogContentLoaded.bind(this));
-        // Listen to the fade complete event to close the dialog
-        var o = this.jxDialog.domObj.get("tween").addEvent("complete", this.closeJxDialog.bind(this));
-    },
-    
-    open : function(contentLoadedCallback)
-    {
-        this.contentLoadedCallback = contentLoadedCallback;
-        this.jxDialog.loadContent(this.jxDialog.content);
-        this.jxDialog.open();
-    },
-    
-    print : function()
-    {
-        //
-        this.previewFrame.contentWindow.doPrint();
-    },
-    
-    cancel : function()
-    {
-        this.indicator.style.display     = "inline";
-        this.indicator.style.visibility  = "visible";
-        this.indicator.setOpacity(1);
-        
-        this.loadingErrorMessage.fade(0);
-        this.loadingErrorMessage.style.display = "none";
-        // Hide the picture but don't set the 'display' style property to avoid messing the print layout up
-        this.printPicture.style.height   = "0px";
-        
-        if (this.topLeftXYLabel && this.bottomRightXYLabel)
-        {
-            this.topLeftXYLabel.setOpacity(0);
-            this.bottomRightXYLabel.setOpacity(0);
-            this.printLabel.setOpacity(0);
-            // Remove the labels
-            this.topLeftXYLabel.parentNode.removeChild(this.topLeftXYLabel);
-            this.topLeftXYLabel     = null;
-            this.bottomRightXYLabel.parentNode.removeChild(this.bottomRightXYLabel);
-            this.bottomRightXYLabel = null;
-            this.printLabel.parentNode.removeChild(this.printLabel);
-            this.printLabel         = null;
-        }
-        
-        this.isClosing = true;
-        this.jxDialog.blanket.fade(0);
-        this.jxDialog.domObj.fade(0);
-    },
-    
-    jxDialogContentLoaded : function()
-    {
-        // Set the window name for the preview frame
-        this.previewFrame = $("PreviewFrame");
-        this.previewFrame.contentWindow.name = "QuickPlotPreviewFrame";
-        
-        // Inform the listener that the content is ready, then the Quick Plot panel can submit its data to the preview frame
-        if (this.contentLoadedCallback)
-        {
-            this.contentLoadedCallback(this.previewFrame.contentWindow.name);
-        }
-    },
-    
-    jxDialogOpened : function(setFrameUrl)
-    {
-        if (this.previewInnerIsLoaded)
-        {
-            // Resize the preview frame according to the monitor resolution
-            this.innerDoc         = this.previewFrame.contentWindow.document;
-            var box       = $(document.body).getDimensions();
-            // Width of preview dialog = screen width * factor
-            var factor    = 0.5;
-            this.previewContainer = $(this.innerDoc.getElementById("PreviewContainer"));
-            this.previewContainer.style.width = box.width * factor + "px";
-            this.pictureContainer = $(this.innerDoc.getElementById("PictureContainer"));
-            var pcBox = this.pictureContainer.getContentBoxSize();
-            
-            this.indicator        = $(this.innerDoc.getElementById("ProgressIndicator"));
-            
-            var paperSize  = this.captureInfo.paperSize;
-            this.paperSize = paperSize;
-            
-            var ratio = paperSize.w / paperSize.h;
-            
-            // Resize the indicator
-            this.indicator.style.width  = pcBox.width + "px";
-            this.indicator.style.height = pcBox.width / ratio + "px";
-            // Set a explicit size to the container
-            this.pictureContainer.style.width  = this.indicator.style.width;
-            this.pictureContainer.style.height = this.indicator.style.height;
-            // Get the styles for the print picture
-            var rules = this.innerDoc.styleSheets[1].cssRules || this.innerDoc.styleSheets[1].rules;
-            this.previewStyle = rules[0];
-            rules     = this.innerDoc.styleSheets[2].cssRules || this.innerDoc.styleSheets[2].rules;
-            this.printStyle   = rules[0];
-            
-            // Reset the background
-            this.indicator.style.background = "url(progress_indicator.gif) no-repeat cneter center";
-            
-            this.loadingErrorMessage = $(this.innerDoc.getElementById("PictureLoadingErrorMessage"));
-            this.loadingErrorMessage.setOpacity(0);
-            
-            // Set the picture url
-            var src = "GeneratePicture.php?session_id=" + this.mapInfo.sessionID +
-                  "&map_name=" + this.mapInfo.name + 
-                  "&print_dpi=" + this.params.printDpi + 
-                  "&paper_size=" + this.captureInfo.paperSize.w + "," + this.captureInfo.paperSize.h + 
-                  "&box=" + this.captureInfo.params1 +
-                  "&normalized_box=" + this.captureInfo.params2 + 
-                  "&scale_denominator=" + this.captureInfo.scaleDenominator + 
-                  "&rotation=" + this.captureInfo.rotation; 
-                
-            this.printPicture       = $(this.innerDoc.getElementById("PrintPicture"));
-            this.printPicture.src   = src;
-            
-            // Listen to print picture onload vent
-            this.printPicture.addEvent("load", this.printPictureLoaded.bind(this));
-            this.printPicture.addEvent("error", this.printPictureLoadError.bind(this));
-            
-            var innerBox  = this.previewContainer.getMarginBoxSize();
-            // Resize the frame according to the inner container's 
-            this.previewFrame.style.width  = innerBox.width + "px";
-            this.previewFrame.style.height = innerBox.height + "px";
-            
-            // Hide the title bar
-            this.jxDialog.title.style.display  = "none";
-            // Hide the chrome
-            this.jxDialog.chrome.style.display = "none";
-            
-            // Disable the print button until the image is ready
-            this.printButton           = this.innerDoc.getElementById("PrintButton");
-            this.cancelButton          = this.innerDoc.getElementById("CancelButton");
-            this.printButton.disabled  = true;
-            this.cancelButton.disabled = true;
-            
-            var delta     = {x: 22, y: 43};
-            var container = $("PreviewContainer");
-            var size      = container.getMarginBoxSize();
-            this.jxDialog.resize(size.width + delta.x, size.height + delta.y, true);
-            
-            this.jxDialog.blanket.fade(0.2);
-            this.jxDialog.domObj.fade(1);
-            this.resizeIsPending = false;
-            
-            this.previewInnerIsLoaded = false;
-        }
-        else
-        {
-            this.jxDialog.blanket.setOpacity(0);
-            this.jxDialog.domObj.setOpacity(0);
-            this.resizeIsPending = true;
-        }
-    },
-    
-    previewInnerLoaded: function()
-    {
-        this.previewInnerIsLoaded = true;
-        if (this.resizeIsPending)
-        {
-            this.jxDialogOpened(false);
-        }
-    },
-    
-    closeJxDialog : function()
-    {
-        if (this.isClosing)
-        {
-            this.jxDialog.close();
-            this.isClosing = false;
-        }
-    },
-    
-    printPictureLoaded : function()
-    {
-        var size = {width: parseInt(this.indicator.style.width), height: parseInt(this.indicator.style.height)};
-        
-        this.indicator.fade(0);
-        this.indicator.style.display = "none";
-        
-        // Set the preview size
-        this.printPicture.setOpacity(0);
-        // Clear the inline style
-        this.printPicture.style.width   = "";
-        this.previewStyle.style.width   = size.width + "px";
-        this.previewStyle.style.height  = size.height + "px";
-        this.printPicture.fade(1);
-        
-        // Set the print size
-        // NOTE: It works only with a 96 dpi device dpi
-        var deviceDpi  = 96;
-        var idealSize  = {width:(this.paperSize.w / 25.4 - 2 * this.printMargin) * deviceDpi, height:(this.paperSize.h / 25.4 - 2 * this.printMargin) * deviceDpi};
-        // Get the size of the print frame
-        var docSize    = $(this.innerDoc.body).getContentBoxSize();
-        var realHeight = idealSize.height - (docSize.height - size.height);
-        var realWidth  = realHeight * this.paperSize.w / this.paperSize.h;
-        if (realWidth > idealSize.width)
-        {
-            realWidth = idealSize.width;
-            realHeight = realWidth / (this.paperSize.w / this.paperSize.h);
-        }
-        
-        this.printStyle.style.width  = realWidth + "px";
-        this.printStyle.style.height = realHeight + "px";
-        
-        // Create the coordinates labels
-        if (!this.topLeftXYLabel)
-        {
-            this.topLeftXYLabel = this.createCoordinateLabel(this.pictureContainer, this.captureInfo.topLeftCs.x, this.captureInfo.topLeftCs.y, "TopLeftXYLabel");
-            this.topLeftXYLabel.setOpacity(0);
-        }
-        
-        if (!this.bottomRightXYLabel)
-        {
-            this.bottomRightXYLabel = this.createCoordinateLabel(this.pictureContainer, this.captureInfo.bottomRightCs.x, this.captureInfo.bottomRightCs.y, "BottomRightXYLabel");
-            this.bottomRightXYLabel.setOpacity(0);
-        }
-        
-        if (!this.printLabel)
-        {
-            this.printLabel = this.createCoordinateLabel(this.pictureContainer, this.captureInfo.bottomRightCs.x, this.captureInfo.bottomRightCs.y, "PrintLabel");
-        }
-        
-        // Set the correct positions for the labels
-        var pos    = this.getContentPosition(this.pictureContainer);
-        var picDim = this.pictureContainer.getContentBoxSize();
-        this.topLeftXYLabel.style.left     = pos.left + this.csLabelOffset + "px";
-        this.topLeftXYLabel.style.top      = pos.top + this.csLabelOffset + "px"; 
-        var labelDim = this.bottomRightXYLabel.getMarginBoxSize();
-        this.bottomRightXYLabel.className  = "ScreenOnly";
-        this.bottomRightXYLabel.style.left = pos.left + picDim.width - this.csLabelOffset - labelDim.width + "px";
-        this.bottomRightXYLabel.style.top  = pos.top + picDim.height - this.csLabelOffset - labelDim.height + "px";
-        labelDim = this.printLabel.getMarginBoxSize();
-        this.printLabel.className          = "PrintOnly";
-        this.printLabel.style.left         = pos.left + realWidth - this.csLabelOffset - labelDim.width + "px";
-        this.printLabel.style.top          = pos.top + realHeight - this.csLabelOffset - labelDim.height + "px";
-        
-        this.topLeftXYLabel.fade(1);
-        this.bottomRightXYLabel.fade(1);
-        // Enable the print button
-        this.printButton.disabled  = false;
-        this.cancelButton.disabled = false;
-    },
-    
-    printPictureLoadError : function()
-    {
-        this.indicator.fade(0);
-        this.indicator.style.display = "none";
-        this.loadingErrorMessage.style.display = "inline";
-        this.loadingErrorMessage.setOpacity(0);
-        this.loadingErrorMessage.fade(1);
-        this.cancelButton.disabled = false;
-    },
-    
-    createCoordinateLabel: function(container, cX, cY, id)
-    {
-        cX = cX + "";
-        cY = cY + "";
-        var digits = 6;
-        
-        var index = cX.indexOf(".");
-        if (index > -1)
-        {
-            cX = cX.substr(0, index + digits + 1);
-        }
-        
-        index = cY.indexOf(".");
-        if (index > -1)
-        {
-            cY = cY.substr(0, index + digits + 1);
-        }
-        
-        var label = this.innerDoc.createElement("div");
-        container.appendChild(label);
-        label.id  = id;
-        label.style.cssText = "border:solid 1px black; padding:1px; background:#F2F2F2; color:black; font-size:8pt; z-index:1000; " +
-                              "position:absolute; white-space:nowrap";
-        label.innerHTML     = "X: " + cX + " Y: " + cY;
-        
-        return $(label);
-    },
-    
-    getContentPosition: function(element)
-    {
-        var offsetLeft = 0;
-        var offsetTop  = 0;
-        var border     = 0;
-        
-        while (element && element.tagName.toLowerCase() != "body" && element.tagName.toLowerCase() != "html")
-        {
-            offsetLeft += element.offsetLeft;
-            offsetTop  += element.offsetTop;
-            
-            border      = parseInt(element.style.borderLeftWidth);
-            if (!isNaN(border))
-            {
-                offsetLeft += border;
-            }
-            
-            border      = parseInt(element.style.borderTopWidth);
-            if (!isNaN(border))
-            {
-                offsetTop += border;
-            }
-            
-            element     = element.offsetParent;
-        }
-        
-        return {left: offsetLeft, top: offsetTop};
-    }
-};
\ No newline at end of file

Copied: branches/fusion-2.2/widgets/QuickPlot/PreviewDialog.js (from rev 2233, trunk/widgets/QuickPlot/PreviewDialog.js)
===================================================================
--- branches/fusion-2.2/widgets/QuickPlot/PreviewDialog.js	                        (rev 0)
+++ branches/fusion-2.2/widgets/QuickPlot/PreviewDialog.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,368 @@
+/**
+ * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
+ */
+
+var PreviewDialog = function(options)
+{
+    this.initialize(options);
+};
+
+PreviewDialog.prototype = 
+{
+    jxDialog : null,
+    previewFrame : null,
+    innerDoc : null,
+    indicator : null,
+    previewPicture : null,
+    printPicture : null,
+    topLeftXYLabel : null,
+    bottomRightXYLabel : null,
+    previewContainer : null,
+    pictureContainer : null,
+    printButton : null,
+    cancelButton : null,
+    loadingErrorMessage : null,
+    printStyle: null,
+    previewStyle: null,
+    // The offset from the border of the paper, in px 
+    csLabelOffset : 5,
+    // The print margin, in inches
+    printMargin: 0,
+    mapInfo : {sessionID: "", name: ""},
+    captureInfo : {topLeftCs : {x : 0, y : 0}, bottomRightCs : {x : 0, y : 0}, paperSize:{w : 0, h : 0}, scaleDenominator : 0, rotation : 0, params1 : "", params2 : ""},
+    params : null,
+    
+    // The callback will be called right after the JxDialog content has been loaded.
+    // The callback accepts 1 parameter: windowName (string)
+    // Here it is used to submit the quick plot form to the preview frame.
+    contentLoadedCallback : null,
+    
+    initialize : function(options)
+    {
+        this.mapInfo      = options.mapInfo;
+        this.captureInfo  = options.captureInfo;
+        this.params       = options.params;
+        
+        this.jxDialog = new Jx.Dialog(
+        {
+            modal: true,
+            width:400,
+            height: 400,
+            content: '<table border="0" cellspacing="0" cellpadding="0" id="PreviewContainer">' + 
+                     '	<tr>' + 
+                     '		<td>' + 
+                     '			<iframe id="PreviewFrame" scrolling="no" frameborder="0" style="border: 0px; width: 400px; height: 300px;" src="about:blank"></iframe>' +
+                     '		</td>' +
+                     '  </tr>' +
+                     '</table>'
+        });
+        
+        this.jxDialog.addEvent("open", this.jxDialogOpened.bind(this, true));
+        this.jxDialog.addEvent("contentLoaded", this.jxDialogContentLoaded.bind(this));
+        // Listen to the fade complete event to close the dialog
+        var o = this.jxDialog.domObj.get("tween").addEvent("complete", this.closeJxDialog.bind(this));
+    },
+    
+    open : function(contentLoadedCallback)
+    {
+        this.contentLoadedCallback = contentLoadedCallback;
+        this.jxDialog.loadContent(this.jxDialog.content);
+        this.jxDialog.open();
+    },
+    
+    print : function()
+    {
+        //
+        this.previewFrame.contentWindow.doPrint();
+    },
+    
+    cancel : function()
+    {
+        this.indicator.style.display     = "inline";
+        this.indicator.style.visibility  = "visible";
+        this.indicator.setOpacity(1);
+        
+        this.loadingErrorMessage.fade(0);
+        this.loadingErrorMessage.style.display = "none";
+        // Hide the picture but don't set the 'display' style property to avoid messing the print layout up
+        this.printPicture.style.height   = "0px";
+        
+        if (this.topLeftXYLabel && this.bottomRightXYLabel)
+        {
+            this.topLeftXYLabel.setOpacity(0);
+            this.bottomRightXYLabel.setOpacity(0);
+            this.printLabel.setOpacity(0);
+            // Remove the labels
+            this.topLeftXYLabel.parentNode.removeChild(this.topLeftXYLabel);
+            this.topLeftXYLabel     = null;
+            this.bottomRightXYLabel.parentNode.removeChild(this.bottomRightXYLabel);
+            this.bottomRightXYLabel = null;
+            this.printLabel.parentNode.removeChild(this.printLabel);
+            this.printLabel         = null;
+        }
+        
+        this.isClosing = true;
+        this.jxDialog.blanket.fade(0);
+        this.jxDialog.domObj.fade(0);
+    },
+    
+    jxDialogContentLoaded : function()
+    {
+        // Set the window name for the preview frame
+        this.previewFrame = $("PreviewFrame");
+        this.previewFrame.contentWindow.name = "QuickPlotPreviewFrame";
+        
+        // Inform the listener that the content is ready, then the Quick Plot panel can submit its data to the preview frame
+        if (this.contentLoadedCallback)
+        {
+            this.contentLoadedCallback(this.previewFrame.contentWindow.name);
+        }
+    },
+    
+    jxDialogOpened : function(setFrameUrl)
+    {
+        if (this.previewInnerIsLoaded)
+        {
+            // Resize the preview frame according to the monitor resolution
+            this.innerDoc         = this.previewFrame.contentWindow.document;
+            var box       = $(document.body).getDimensions();
+            // Width of preview dialog = screen width * factor
+            var factor    = 0.5;
+            this.previewContainer = $(this.innerDoc.getElementById("PreviewContainer"));
+            this.previewContainer.style.width = box.width * factor + "px";
+            this.pictureContainer = $(this.innerDoc.getElementById("PictureContainer"));
+            var pcBox = this.pictureContainer.getContentBoxSize();
+            
+            this.indicator        = $(this.innerDoc.getElementById("ProgressIndicator"));
+            
+            var paperSize  = this.captureInfo.paperSize;
+            this.paperSize = paperSize;
+            
+            var ratio = paperSize.w / paperSize.h;
+            
+            // Resize the indicator
+            this.indicator.style.width  = pcBox.width + "px";
+            this.indicator.style.height = pcBox.width / ratio + "px";
+            // Set a explicit size to the container
+            this.pictureContainer.style.width  = this.indicator.style.width;
+            this.pictureContainer.style.height = this.indicator.style.height;
+            // Get the styles for the print picture
+            var rules = this.innerDoc.styleSheets[1].cssRules || this.innerDoc.styleSheets[1].rules;
+            this.previewStyle = rules[0];
+            rules     = this.innerDoc.styleSheets[2].cssRules || this.innerDoc.styleSheets[2].rules;
+            this.printStyle   = rules[0];
+            
+            // Reset the background
+            this.indicator.style.background = "url(progress_indicator.gif) no-repeat cneter center";
+            
+            this.loadingErrorMessage = $(this.innerDoc.getElementById("PictureLoadingErrorMessage"));
+            this.loadingErrorMessage.setOpacity(0);
+            
+            // Set the picture url
+            var src = "GeneratePicture.php?session_id=" + this.mapInfo.sessionID +
+                  "&map_name=" + this.mapInfo.name + 
+                  "&print_dpi=" + this.params.printDpi + 
+                  "&paper_size=" + this.captureInfo.paperSize.w + "," + this.captureInfo.paperSize.h + 
+                  "&box=" + this.captureInfo.params1 +
+                  "&normalized_box=" + this.captureInfo.params2 + 
+                  "&scale_denominator=" + this.captureInfo.scaleDenominator + 
+                  "&rotation=" + this.captureInfo.rotation; 
+                
+            this.printPicture       = $(this.innerDoc.getElementById("PrintPicture"));
+            this.printPicture.src   = src;
+            
+            // Listen to print picture onload vent
+            this.printPicture.addEvent("load", this.printPictureLoaded.bind(this));
+            this.printPicture.addEvent("error", this.printPictureLoadError.bind(this));
+            
+            var innerBox  = this.previewContainer.getMarginBoxSize();
+            // Resize the frame according to the inner container's 
+            this.previewFrame.style.width  = innerBox.width + "px";
+            this.previewFrame.style.height = innerBox.height + "px";
+            
+            // Hide the title bar
+            this.jxDialog.title.style.display  = "none";
+            // Hide the chrome
+            this.jxDialog.chrome.style.display = "none";
+            
+            // Disable the print button until the image is ready
+            this.printButton           = this.innerDoc.getElementById("PrintButton");
+            this.cancelButton          = this.innerDoc.getElementById("CancelButton");
+            this.printButton.disabled  = true;
+            this.cancelButton.disabled = true;
+            
+            var delta     = {x: 22, y: 43};
+            var container = $("PreviewContainer");
+            var size      = container.getMarginBoxSize();
+            this.jxDialog.resize(size.width + delta.x, size.height + delta.y, true);
+            
+            this.jxDialog.blanket.fade(0.2);
+            this.jxDialog.domObj.fade(1);
+            this.resizeIsPending = false;
+            
+            this.previewInnerIsLoaded = false;
+        }
+        else
+        {
+            this.jxDialog.blanket.setOpacity(0);
+            this.jxDialog.domObj.setOpacity(0);
+            this.resizeIsPending = true;
+        }
+    },
+    
+    previewInnerLoaded: function()
+    {
+        this.previewInnerIsLoaded = true;
+        if (this.resizeIsPending)
+        {
+            this.jxDialogOpened(false);
+        }
+    },
+    
+    closeJxDialog : function()
+    {
+        if (this.isClosing)
+        {
+            this.jxDialog.close();
+            this.isClosing = false;
+        }
+    },
+    
+    printPictureLoaded : function()
+    {
+        var size = {width: parseInt(this.indicator.style.width), height: parseInt(this.indicator.style.height)};
+        
+        this.indicator.fade(0);
+        this.indicator.style.display = "none";
+        
+        // Set the preview size
+        this.printPicture.setOpacity(0);
+        // Clear the inline style
+        this.printPicture.style.width   = "";
+        this.previewStyle.style.width   = size.width + "px";
+        this.previewStyle.style.height  = size.height + "px";
+        this.printPicture.fade(1);
+        
+        // Set the print size
+        // NOTE: It works only with a 96 dpi device dpi
+        var deviceDpi  = 96;
+        var idealSize  = {width:(this.paperSize.w / 25.4 - 2 * this.printMargin) * deviceDpi, height:(this.paperSize.h / 25.4 - 2 * this.printMargin) * deviceDpi};
+        // Get the size of the print frame
+        var docSize    = $(this.innerDoc.body).getContentBoxSize();
+        var realHeight = idealSize.height - (docSize.height - size.height);
+        var realWidth  = realHeight * this.paperSize.w / this.paperSize.h;
+        if (realWidth > idealSize.width)
+        {
+            realWidth = idealSize.width;
+            realHeight = realWidth / (this.paperSize.w / this.paperSize.h);
+        }
+        
+        this.printStyle.style.width  = realWidth + "px";
+        this.printStyle.style.height = realHeight + "px";
+        
+        // Create the coordinates labels
+        if (!this.topLeftXYLabel)
+        {
+            this.topLeftXYLabel = this.createCoordinateLabel(this.pictureContainer, this.captureInfo.topLeftCs.x, this.captureInfo.topLeftCs.y, "TopLeftXYLabel");
+            this.topLeftXYLabel.setOpacity(0);
+        }
+        
+        if (!this.bottomRightXYLabel)
+        {
+            this.bottomRightXYLabel = this.createCoordinateLabel(this.pictureContainer, this.captureInfo.bottomRightCs.x, this.captureInfo.bottomRightCs.y, "BottomRightXYLabel");
+            this.bottomRightXYLabel.setOpacity(0);
+        }
+        
+        if (!this.printLabel)
+        {
+            this.printLabel = this.createCoordinateLabel(this.pictureContainer, this.captureInfo.bottomRightCs.x, this.captureInfo.bottomRightCs.y, "PrintLabel");
+        }
+        
+        // Set the correct positions for the labels
+        var pos    = this.getContentPosition(this.pictureContainer);
+        var picDim = this.pictureContainer.getContentBoxSize();
+        this.topLeftXYLabel.style.left     = pos.left + this.csLabelOffset + "px";
+        this.topLeftXYLabel.style.top      = pos.top + this.csLabelOffset + "px"; 
+        var labelDim = this.bottomRightXYLabel.getMarginBoxSize();
+        this.bottomRightXYLabel.className  = "ScreenOnly";
+        this.bottomRightXYLabel.style.left = pos.left + picDim.width - this.csLabelOffset - labelDim.width + "px";
+        this.bottomRightXYLabel.style.top  = pos.top + picDim.height - this.csLabelOffset - labelDim.height + "px";
+        labelDim = this.printLabel.getMarginBoxSize();
+        this.printLabel.className          = "PrintOnly";
+        this.printLabel.style.left         = pos.left + realWidth - this.csLabelOffset - labelDim.width + "px";
+        this.printLabel.style.top          = pos.top + realHeight - this.csLabelOffset - labelDim.height + "px";
+        
+        this.topLeftXYLabel.fade(1);
+        this.bottomRightXYLabel.fade(1);
+        // Enable the print button
+        this.printButton.disabled  = false;
+        this.cancelButton.disabled = false;
+    },
+    
+    printPictureLoadError : function()
+    {
+        this.indicator.fade(0);
+        this.indicator.style.display = "none";
+        this.loadingErrorMessage.style.display = "inline";
+        this.loadingErrorMessage.setOpacity(0);
+        this.loadingErrorMessage.fade(1);
+        this.cancelButton.disabled = false;
+    },
+    
+    createCoordinateLabel: function(container, cX, cY, id)
+    {
+        cX = cX + "";
+        cY = cY + "";
+        var digits = 6;
+        
+        var index = cX.indexOf(".");
+        if (index > -1)
+        {
+            cX = cX.substr(0, index + digits + 1);
+        }
+        
+        index = cY.indexOf(".");
+        if (index > -1)
+        {
+            cY = cY.substr(0, index + digits + 1);
+        }
+        
+        var label = this.innerDoc.createElement("div");
+        container.appendChild(label);
+        label.id  = id;
+        label.style.cssText = "border:solid 1px black; padding:1px; background:#F2F2F2; color:black; font-size:8pt; z-index:1000; " +
+                              "position:absolute; white-space:nowrap";
+        label.innerHTML     = "X: " + cX + " Y: " + cY;
+        
+        return $(label);
+    },
+    
+    getContentPosition: function(element)
+    {
+        var offsetLeft = 0;
+        var offsetTop  = 0;
+        var border     = 0;
+        
+        while (element && element.tagName.toLowerCase() != "body" && element.tagName.toLowerCase() != "html")
+        {
+            offsetLeft += element.offsetLeft;
+            offsetTop  += element.offsetTop;
+            
+            border      = parseInt(element.style.borderLeftWidth);
+            if (!isNaN(border))
+            {
+                offsetLeft += border;
+            }
+            
+            border      = parseInt(element.style.borderTopWidth);
+            if (!isNaN(border))
+            {
+                offsetTop += border;
+            }
+            
+            element     = element.offsetParent;
+        }
+        
+        return {left: offsetLeft, top: offsetTop};
+    }
+};
\ No newline at end of file

Deleted: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.js
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPanel.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1,155 +0,0 @@
-/**
- * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
- */
-
-function restoreUI()
-{
-    setAdvancedOptionsUI(false);
-    
-    // Read the last used options
-    lastPaperSize = getParent().Cookie.read("QuickPlotLastUsedPaperSize");
-    lastScale     = getParent().Cookie.read("QuickPlotLastUsedScaling");
-    lastDPI       = getParent().Cookie.read("QuickPlotLastUsedDPI");
-    
-    if (lastPaperSize != null)
-    {
-        document.getElementById("PaperList").value   = lastPaperSize;
-    }
-    
-    if (lastScale != null)
-    {
-        document.getElementById("ScalingList").value = lastScale;
-    }
-    
-    if (lastDPI != null)
-    {
-        document.getElementById("DPIList").value     = lastDPI;
-    }
-}
-
-function setAdvancedOptionsUI(enabled)
-{
-    document.getElementById("PaperList").disabled   = !enabled;
-    document.getElementById("ScalingList").disabled = !enabled;
-    document.getElementById("DPIList").disabled     = !enabled;
-    
-    var mapCapturer = getParent().Fusion.getWidgetsByType("QuickPlot")[0].mapCapturer;
-    
-    if (enabled)
-    {
-        mapCapturer.enable();
-        drawCaptureBox();
-    }
-    else
-    {
-        mapCapturer.disable();
-    }
-}
-
-function generatePlot()
-{
-    var widget      = getParent().Fusion.getWidgetsByType("QuickPlot")[0];
-    var mapCapturer = widget.mapCapturer;
-
-    if (!advancedOptionsOn())
-    {
-        // Get paper size. Use the last used paper size by default
-        mapCapturer.setSize(getPaperSize(), getScale());
-        
-    }
-    
-    widget.preview(submitForm, getPrintDpi());
-}
-
-function submitForm(windowName)
-{
-    var form = document.getElementById("Form1");
-    form.target = windowName;
-    // Save the advanced options to a cookie
-    var cookieDuration = 365;
-    getParent().Cookie.write("QuickPlotLastUsedPaperSize", document.getElementById("PaperList").value, {duration:cookieDuration});
-    getParent().Cookie.write("QuickPlotLastUsedScaling", document.getElementById("ScalingList").value, {duration:cookieDuration});
-    getParent().Cookie.write("QuickPlotLastUsedDPI", document.getElementById("DPIList").value, {duration:cookieDuration});
-    form.submit();
-}
-
-
-function advancedOptionsOn()
-{
-    var o = document.getElementById("AdvancedOptionsCheckBox");
-    if (o && o.checked)
-    {
-        return true;
-    }
-    
-    return false;
-}
-
-function getPaperSize()
-{
-    var value = document.getElementById("PaperList").value.split(",");
-    var size = {w: parseFloat(value[0]), h: parseFloat(value[1])};
-
-    if (!advancedOptionsOn())
-    {
-        // Calculate the paper size to make sure it has a same ratio with the viweport
-        var map        = getParent().Fusion.getWidgetById("Map");
-        var paperRatio = size.w / size.h;
-        var viewSize   = map.getSize();
-        var viewRatio  = viewSize.w / viewSize.h;
-
-        if (paperRatio > viewRatio)
-        {
-            size.w     = size.h * viewRatio;
-        }
-        else
-        {
-            size.h     = size.w / viewRatio;
-        }
-    }
-
-    return size;
-}
-
-function getScale()
-{
-    var scale = 0;
-    if (advancedOptionsOn())
-    {
-        scale = document.getElementById("ScalingList").value;
-    }
-    else
-    {
-        var map        = getParent().Fusion.getWidgetById("Map");
-        var paperSize  = getPaperSize();
-        var viewerSize = map.getCurrentExtents().getSize();
-        var factor     = map.getMetersPerUnit();
-        
-        if (paperSize.w / paperSize.h > viewerSize.w / viewerSize.h)
-        {
-            scale = viewerSize.h * factor * 1000 / paperSize.h;
-        } 
-        else
-        {
-            scale = viewerSize.w * factor * 1000 / paperSize.w;
-        }
-    }
-
-    scale = parseInt(scale);
-    // Set the value to a hidden field so that it could be sent by POST method
-    // We cannot rely on the ScalingList.value because we have to handle also the viewport print 
-    document.getElementById("ScaleDenominator").value = scale;
-    
-    return scale;
-}
-
-function getPrintDpi()
-{
-    return document.getElementById("DPIList").value;
-}
-
-function drawCaptureBox()
-{
-    var mapCapturer = getParent().Fusion.getWidgetsByType("QuickPlot")[0].mapCapturer;
-    mapCapturer.setSize(getPaperSize(), getScale());
-}

Copied: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.js (from rev 2233, trunk/widgets/QuickPlot/QuickPlotPanel.js)
===================================================================
--- branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.js	                        (rev 0)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,155 @@
+/**
+ * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
+ */
+
+function restoreUI()
+{
+    setAdvancedOptionsUI(false);
+    
+    // Read the last used options
+    lastPaperSize = getParent().Cookie.read("QuickPlotLastUsedPaperSize");
+    lastScale     = getParent().Cookie.read("QuickPlotLastUsedScaling");
+    lastDPI       = getParent().Cookie.read("QuickPlotLastUsedDPI");
+    
+    if (lastPaperSize != null)
+    {
+        document.getElementById("PaperList").value   = lastPaperSize;
+    }
+    
+    if (lastScale != null)
+    {
+        document.getElementById("ScalingList").value = lastScale;
+    }
+    
+    if (lastDPI != null)
+    {
+        document.getElementById("DPIList").value     = lastDPI;
+    }
+}
+
+function setAdvancedOptionsUI(enabled)
+{
+    document.getElementById("PaperList").disabled   = !enabled;
+    document.getElementById("ScalingList").disabled = !enabled;
+    document.getElementById("DPIList").disabled     = !enabled;
+    
+    var mapCapturer = getParent().Fusion.getWidgetsByType("QuickPlot")[0].mapCapturer;
+    
+    if (enabled)
+    {
+        mapCapturer.enable();
+        drawCaptureBox();
+    }
+    else
+    {
+        mapCapturer.disable();
+    }
+}
+
+function generatePlot()
+{
+    var widget      = getParent().Fusion.getWidgetsByType("QuickPlot")[0];
+    var mapCapturer = widget.mapCapturer;
+
+    if (!advancedOptionsOn())
+    {
+        // Get paper size. Use the last used paper size by default
+        mapCapturer.setSize(getPaperSize(), getScale());
+        
+    }
+    
+    widget.preview(submitForm, getPrintDpi());
+}
+
+function submitForm(windowName)
+{
+    var form = document.getElementById("Form1");
+    form.target = windowName;
+    // Save the advanced options to a cookie
+    var cookieDuration = 365;
+    getParent().Cookie.write("QuickPlotLastUsedPaperSize", document.getElementById("PaperList").value, {duration:cookieDuration});
+    getParent().Cookie.write("QuickPlotLastUsedScaling", document.getElementById("ScalingList").value, {duration:cookieDuration});
+    getParent().Cookie.write("QuickPlotLastUsedDPI", document.getElementById("DPIList").value, {duration:cookieDuration});
+    form.submit();
+}
+
+
+function advancedOptionsOn()
+{
+    var o = document.getElementById("AdvancedOptionsCheckBox");
+    if (o && o.checked)
+    {
+        return true;
+    }
+    
+    return false;
+}
+
+function getPaperSize()
+{
+    var value = document.getElementById("PaperList").value.split(",");
+    var size = {w: parseFloat(value[0]), h: parseFloat(value[1])};
+
+    if (!advancedOptionsOn())
+    {
+        // Calculate the paper size to make sure it has a same ratio with the viweport
+        var map        = getParent().Fusion.getWidgetById("Map");
+        var paperRatio = size.w / size.h;
+        var viewSize   = map.getSize();
+        var viewRatio  = viewSize.w / viewSize.h;
+
+        if (paperRatio > viewRatio)
+        {
+            size.w     = size.h * viewRatio;
+        }
+        else
+        {
+            size.h     = size.w / viewRatio;
+        }
+    }
+
+    return size;
+}
+
+function getScale()
+{
+    var scale = 0;
+    if (advancedOptionsOn())
+    {
+        scale = document.getElementById("ScalingList").value;
+    }
+    else
+    {
+        var map        = getParent().Fusion.getWidgetById("Map");
+        var paperSize  = getPaperSize();
+        var viewerSize = map.getCurrentExtents().getSize();
+        var factor     = map.getMetersPerUnit();
+        
+        if (paperSize.w / paperSize.h > viewerSize.w / viewerSize.h)
+        {
+            scale = viewerSize.h * factor * 1000 / paperSize.h;
+        } 
+        else
+        {
+            scale = viewerSize.w * factor * 1000 / paperSize.w;
+        }
+    }
+
+    scale = parseInt(scale);
+    // Set the value to a hidden field so that it could be sent by POST method
+    // We cannot rely on the ScalingList.value because we have to handle also the viewport print 
+    document.getElementById("ScaleDenominator").value = scale;
+    
+    return scale;
+}
+
+function getPrintDpi()
+{
+    return document.getElementById("DPIList").value;
+}
+
+function drawCaptureBox()
+{
+    var mapCapturer = getParent().Fusion.getWidgetsByType("QuickPlot")[0].mapCapturer;
+    mapCapturer.setSize(getPaperSize(), getScale());
+}

Deleted: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.php
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPanel.php	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.php	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1,43 +0,0 @@
-<?php
-
-    $fusionMGpath = '../../layers/MapGuide/php/';
-    include $fusionMGpath . 'Common.php';
-
-    $locale = GetDefaultLocale();
-    $popup = 0;
-    $mapName = "";
-    $sessionId = "";
-    $us = "";
-    $popup = "false";
-
-    GetRequestParameters();
-
-    $templ = file_get_contents("QuickPlotPanel.templ");
-    SetLocalizedFilesPath(GetLocalizationPath());
-    $templ = Localize($templ, $locale, GetClientOS());
-
-    $vpath = GetSurroundVirtualPath();
-    $jsPath = "";
-    print sprintf($templ, $popup, $jsPath);
-
-function GetParameters($params)
-{
-    global $target, $cmdIndex, $clientWidth, $mapName, $sessionId, $popup, $us, $locale, $popup;
-
-    $locale    = $params['locale'];
-    $mapName   = $params['mapname'];
-    $sessionId = $params['session'];
-    $popup     = $params['popup'];
-    $us        = $params['us'];
-    $popup     = $params['popup'];
-}
-
-function GetRequestParameters()
-{
-    if($_SERVER['REQUEST_METHOD'] == "POST")
-        GetParameters($_POST);
-    else
-        GetParameters($_GET);
-}
-
-?>

Copied: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.php (from rev 2233, trunk/widgets/QuickPlot/QuickPlotPanel.php)
===================================================================
--- branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.php	                        (rev 0)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.php	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,43 @@
+<?php
+
+    $fusionMGpath = '../../layers/MapGuide/php/';
+    include $fusionMGpath . 'Common.php';
+
+    $locale = GetDefaultLocale();
+    $popup = 0;
+    $mapName = "";
+    $sessionId = "";
+    $us = "";
+    $popup = "false";
+
+    GetRequestParameters();
+
+    $templ = file_get_contents("QuickPlotPanel.templ");
+    SetLocalizedFilesPath(GetLocalizationPath());
+    $templ = Localize($templ, $locale, GetClientOS());
+
+    $vpath = GetSurroundVirtualPath();
+    $jsPath = "";
+    print sprintf($templ, $popup, $jsPath);
+
+function GetParameters($params)
+{
+    global $target, $cmdIndex, $clientWidth, $mapName, $sessionId, $popup, $us, $locale, $popup;
+
+    $locale    = $params['locale'];
+    $mapName   = $params['mapname'];
+    $sessionId = $params['session'];
+    $popup     = $params['popup'];
+    $us        = $params['us'];
+    $popup     = $params['popup'];
+}
+
+function GetRequestParameters()
+{
+    if($_SERVER['REQUEST_METHOD'] == "POST")
+        GetParameters($_POST);
+    else
+        GetParameters($_GET);
+}
+
+?>

Deleted: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.templ
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPanel.templ	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1,150 +0,0 @@
-<html>
-<head>
-<title>__#QUICKPLOT_HEADER#__</title>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-<style type="text/css">
-body, table, td, div, select, input 
-{
-    font: 8pt/1em __#@font#__;
-}
-
-div.Label
-{
-    padding:5px 0px;
-}
-
-div.Ctrl
-{
-    padding:5px 0px;
-}
-
-div.Title
-{
-    font-size: 14px;
-    font-weight: bold;
-    padding: 10px 0px;
-}
-
-div.HPlaceholder5px
-{
-    font-size:0px;
-    height:5px;
-}
-
-div.ButtonContainer
-{
-    padding: 5px 0px;
-    text-align: right;
-}
-
-.FixWidth
-{
-    width: 100%%;
-}
-
-input.Button
-{
-    width:75px;
-    height:23px;
-    margin-left:7px;
-}
-</style>
-<script language="javascript" type="text/javascript">
-var popup = %s;
-
-// Get window where the Fusion object is available
-function getParent()
-{
-    if (popup) 
-    {
-        return opener;
-    } 
-    else if (parent.Fusion)
-    {
-        return parent;
-    } 
-    else if (parent.parent.Fusion) 
-    {
-        return parent.parent;
-    }
-    
-    return null;
-}
-
-</script>
-<script language="javascript" type="text/javascript" src="%sQuickPlotPanel.js"></script>
-
-</head>
-<body onload="restoreUI()">
-    <form id="Form1" name="Form1" method="post" action="QuickPlotPreviewInner.php">
-        <div class="Title FixWidth">__#QUICKPLOT_HEADER#__</div>
-        <div class="Label ">__#QUICKPLOT_TITLE#__</div>
-        <div class="Ctrl">
-            <input type="text" class="FixWidth" name="{field:title}" maxLength=100"/>
-        </div>
-        <div class="HPlaceholder5px"></div>
-        <div class="HPlaceholder5px"></div>
-        <div class="Label">__#QUICKPLOT_SUBTITLE#__</div>
-        <div class="Ctrl">
-            <input type="text" class="FixWidth" name="{field:sub_title}" maxLength=100"/>
-        </div>
-        <div class="HPlaceholder5px"></div>
-        <div class="HPlaceholder5px"></div>
-        <div class="HPlaceholder5px"></div>
-        <div class="Label">
-            <table cellspacing="0" cellpadding="0">
-                <tr>
-                    <td><input type="checkbox" id="AdvancedOptionsCheckBox" onclick="setAdvancedOptionsUI(this.checked)" /></td>
-                    <td><label for="AdvancedOptionsCheckBox">__#QUICKPLOT_ADVANCED_OPTIONS#__</label></td>
-                </tr>
-            </table>
-        </div>
-        <div class="HPlaceholder5px"></div>
-        <div class="Label">__#QUICKPLOT_PAPER_SIZE#__</div>
-        <div class="Ctrl">
-            <!--
-                The pre-defined paper size list. The value for each "option" item is in this format: [width,height]. The unit is in millimeter.
-                We can change the html code to add more paper size or remove some ones.
-            -->
-            <select class="FixWidth" id="PaperList" onchange="drawCaptureBox(this)">
-                <option value="297.0,210.0">A4 (210 MM x 297 MM)</option>
-                <option value="420.0,297.0">A3 (297 MM) x 420 MM</option>
-                <option value="279.4,215.9">Letter (8.50 x 11.00 Inches)</option>
-                <option value="355.6,215.9">Legal (8.50 x 14.00 Inches)</option>
-            </select>
-        </div>
-        <div class="HPlaceholder5px"></div>
-        <div class="HPlaceholder5px"></div>
-        <div class="Label">__#QUICKPLOT_SCALING#__</div>
-        <div class="Ctrl">
-            <!--
-                The pre-defined scales. The value for each "option" item is the scale denominator.
-                We can change the html code to extend the pre-defined scales
-            -->
-            <select class="FixWidth" id="ScalingList" onchange="drawCaptureBox(this)">
-                <option value="500">1 : 500</option>
-                <option value="1000">1 : 1000</option>
-                <option value="2500">1 : 2500</option>
-                <option value="5000">1 : 5000</option>
-            </select>
-        </div>
-        <div class="Label">__#QUICKPLOT_DPI#__</div>
-        <div class="Ctrl">
-            <!--
-                The pre-defined print DPI. 
-                We can change the html code to extend the pre-defined values
-            -->
-            <select class="FixWidth" id="DPIList">
-                <option value="96">96</option>
-                <option value="150" selected>150</option>
-                <option value="300">300</option>
-                <option value="600">600</option>
-            </select>
-        </div>
-        <input type="hidden" id="ScaleDenominator" name="scale_denominator" />
-        <div class="ButtonContainer FixWidth">
-            <input type="button" class="Button" value="__#QUICKPLOT_GENERATE#__" onclick="generatePlot()" />
-        </div>
-    </form>
-</body>
-</html>

Copied: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.templ (from rev 2233, trunk/widgets/QuickPlot/QuickPlotPanel.templ)
===================================================================
--- branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.templ	                        (rev 0)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPanel.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,150 @@
+<html>
+<head>
+<title>__#QUICKPLOT_HEADER#__</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<style type="text/css">
+body, table, td, div, select, input 
+{
+    font: 8pt/1em __#@font#__;
+}
+
+div.Label
+{
+    padding:5px 0px;
+}
+
+div.Ctrl
+{
+    padding:5px 0px;
+}
+
+div.Title
+{
+    font-size: 14px;
+    font-weight: bold;
+    padding: 10px 0px;
+}
+
+div.HPlaceholder5px
+{
+    font-size:0px;
+    height:5px;
+}
+
+div.ButtonContainer
+{
+    padding: 5px 0px;
+    text-align: right;
+}
+
+.FixWidth
+{
+    width: 100%%;
+}
+
+input.Button
+{
+    width:75px;
+    height:23px;
+    margin-left:7px;
+}
+</style>
+<script language="javascript" type="text/javascript">
+var popup = %s;
+
+// Get window where the Fusion object is available
+function getParent()
+{
+    if (popup) 
+    {
+        return opener;
+    } 
+    else if (parent.Fusion)
+    {
+        return parent;
+    } 
+    else if (parent.parent.Fusion) 
+    {
+        return parent.parent;
+    }
+    
+    return null;
+}
+
+</script>
+<script language="javascript" type="text/javascript" src="%sQuickPlotPanel.js"></script>
+
+</head>
+<body onload="restoreUI()">
+    <form id="Form1" name="Form1" method="post" action="QuickPlotPreviewInner.php">
+        <div class="Title FixWidth">__#QUICKPLOT_HEADER#__</div>
+        <div class="Label ">__#QUICKPLOT_TITLE#__</div>
+        <div class="Ctrl">
+            <input type="text" class="FixWidth" name="{field:title}" maxLength=100"/>
+        </div>
+        <div class="HPlaceholder5px"></div>
+        <div class="HPlaceholder5px"></div>
+        <div class="Label">__#QUICKPLOT_SUBTITLE#__</div>
+        <div class="Ctrl">
+            <input type="text" class="FixWidth" name="{field:sub_title}" maxLength=100"/>
+        </div>
+        <div class="HPlaceholder5px"></div>
+        <div class="HPlaceholder5px"></div>
+        <div class="HPlaceholder5px"></div>
+        <div class="Label">
+            <table cellspacing="0" cellpadding="0">
+                <tr>
+                    <td><input type="checkbox" id="AdvancedOptionsCheckBox" onclick="setAdvancedOptionsUI(this.checked)" /></td>
+                    <td><label for="AdvancedOptionsCheckBox">__#QUICKPLOT_ADVANCED_OPTIONS#__</label></td>
+                </tr>
+            </table>
+        </div>
+        <div class="HPlaceholder5px"></div>
+        <div class="Label">__#QUICKPLOT_PAPER_SIZE#__</div>
+        <div class="Ctrl">
+            <!--
+                The pre-defined paper size list. The value for each "option" item is in this format: [width,height]. The unit is in millimeter.
+                We can change the html code to add more paper size or remove some ones.
+            -->
+            <select class="FixWidth" id="PaperList" onchange="drawCaptureBox(this)">
+                <option value="297.0,210.0">A4 (210 MM x 297 MM)</option>
+                <option value="420.0,297.0">A3 (297 MM) x 420 MM</option>
+                <option value="279.4,215.9">Letter (8.50 x 11.00 Inches)</option>
+                <option value="355.6,215.9">Legal (8.50 x 14.00 Inches)</option>
+            </select>
+        </div>
+        <div class="HPlaceholder5px"></div>
+        <div class="HPlaceholder5px"></div>
+        <div class="Label">__#QUICKPLOT_SCALING#__</div>
+        <div class="Ctrl">
+            <!--
+                The pre-defined scales. The value for each "option" item is the scale denominator.
+                We can change the html code to extend the pre-defined scales
+            -->
+            <select class="FixWidth" id="ScalingList" onchange="drawCaptureBox(this)">
+                <option value="500">1 : 500</option>
+                <option value="1000">1 : 1000</option>
+                <option value="2500">1 : 2500</option>
+                <option value="5000">1 : 5000</option>
+            </select>
+        </div>
+        <div class="Label">__#QUICKPLOT_DPI#__</div>
+        <div class="Ctrl">
+            <!--
+                The pre-defined print DPI. 
+                We can change the html code to extend the pre-defined values
+            -->
+            <select class="FixWidth" id="DPIList">
+                <option value="96">96</option>
+                <option value="150" selected>150</option>
+                <option value="300">300</option>
+                <option value="600">600</option>
+            </select>
+        </div>
+        <input type="hidden" id="ScaleDenominator" name="scale_denominator" />
+        <div class="ButtonContainer FixWidth">
+            <input type="button" class="Button" value="__#QUICKPLOT_GENERATE#__" onclick="generatePlot()" />
+        </div>
+    </form>
+</body>
+</html>

Deleted: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreview.js
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPreview.js	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreview.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1,27 +0,0 @@
-/**
- * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
- */
-
-function innerLoaded()
-{
-    if (parent.Fusion)
-    {
-        parent.Fusion.getWidgetsByType("QuickPlot")[0].previewInnerLoaded();
-    }
-}
-
-function printIt()
-{
-    parent.Fusion.getWidgetsByType("QuickPlot")[0].printPreview();
-}
-
-function cancelPreview()
-{
-    parent.Fusion.getWidgetsByType("QuickPlot")[0].cancelPreview();
-}
-
-function doPrint()
-{
-    window.focus();
-    window.print();
-}

Copied: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreview.js (from rev 2233, trunk/widgets/QuickPlot/QuickPlotPreview.js)
===================================================================
--- branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreview.js	                        (rev 0)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreview.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
+ */
+
+function innerLoaded()
+{
+    if (parent.Fusion)
+    {
+        parent.Fusion.getWidgetsByType("QuickPlot")[0].previewInnerLoaded();
+    }
+}
+
+function printIt()
+{
+    parent.Fusion.getWidgetsByType("QuickPlot")[0].printPreview();
+}
+
+function cancelPreview()
+{
+    parent.Fusion.getWidgetsByType("QuickPlot")[0].cancelPreview();
+}
+
+function doPrint()
+{
+    window.focus();
+    window.print();
+}

Deleted: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.php
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPreviewInner.php	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.php	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1,69 +0,0 @@
-<?php
-
-    $fusionMGpath = '../../layers/MapGuide/php/';
-    include $fusionMGpath . 'Common.php';
-
-    $locale = GetDefaultLocale();
-    $scaleDenominator;
-    $annotations;
-    
-    $args = GetRequestMethod();
-    GetParameters($args);
-
-    $templ = file_get_contents("QuickPlotPreviewInner.templ");
-    SetLocalizedFilesPath(GetLocalizationPath());
-    
-    // Localize the page
-    $templ = Localize($templ, $locale, GetClientOS());
-    
-    // Set some annotation labels in the page by replacing the placeholders in the html code
-    $templ = str_replace(array_keys($annotations), array_values($annotations), $templ);
-    // Set the date annotation according to its format mask
-    $pattern = "/\{date:(.+?)\}/";
-    $matches = array();
-    if (preg_match($pattern, $templ, $matches))
-    {
-        $mask  = $matches[1];
-        $date  = date($mask);
-        $templ = preg_replace($pattern, $date, $templ);
-    }
-    
-    $jsPath    = "";
-    print sprintf($templ, $jsPath);
-?>
-
-<?php
-function GetParameters($params)
-{
-    global $scaleDenominator, $annotations;
-    
-    $scaleDenominator = intval($params["scale_denominator"]);
-    $annotations = array();
-    
-    // The parameters whose name matches this pattern will be treated as annotation
-    $pattern = "/^\{field:.+\}$/i";
-    foreach ($params as $key => $value)
-    {
-        if (preg_match($pattern, $key) == 1)
-        {
-            $annotations[$key] = htmlspecialchars(urlDecode($value), ENT_QUOTES);
-        }
-    }
-    
-    // The scale annotation
-    $annotations["{scale}"] = "1 : " . $scaleDenominator;
-}
-
-function GetRequestMethod()
-{
-    if($_SERVER['REQUEST_METHOD'] == "POST")
-    {
-        return $_POST;
-    }
-    else
-    {
-        return $_GET;
-    }
-}
-
-?>

Copied: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.php (from rev 2233, trunk/widgets/QuickPlot/QuickPlotPreviewInner.php)
===================================================================
--- branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.php	                        (rev 0)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.php	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,69 @@
+<?php
+
+    $fusionMGpath = '../../layers/MapGuide/php/';
+    include $fusionMGpath . 'Common.php';
+
+    $locale = GetDefaultLocale();
+    $scaleDenominator;
+    $annotations;
+    
+    $args = GetRequestMethod();
+    GetParameters($args);
+
+    $templ = file_get_contents("QuickPlotPreviewInner.templ");
+    SetLocalizedFilesPath(GetLocalizationPath());
+    
+    // Localize the page
+    $templ = Localize($templ, $locale, GetClientOS());
+    
+    // Set some annotation labels in the page by replacing the placeholders in the html code
+    $templ = str_replace(array_keys($annotations), array_values($annotations), $templ);
+    // Set the date annotation according to its format mask
+    $pattern = "/\{date:(.+?)\}/";
+    $matches = array();
+    if (preg_match($pattern, $templ, $matches))
+    {
+        $mask  = $matches[1];
+        $date  = date($mask);
+        $templ = preg_replace($pattern, $date, $templ);
+    }
+    
+    $jsPath    = "";
+    print sprintf($templ, $jsPath);
+?>
+
+<?php
+function GetParameters($params)
+{
+    global $scaleDenominator, $annotations;
+    
+    $scaleDenominator = intval($params["scale_denominator"]);
+    $annotations = array();
+    
+    // The parameters whose name matches this pattern will be treated as annotation
+    $pattern = "/^\{field:.+\}$/i";
+    foreach ($params as $key => $value)
+    {
+        if (preg_match($pattern, $key) == 1)
+        {
+            $annotations[$key] = htmlspecialchars(urlDecode($value), ENT_QUOTES);
+        }
+    }
+    
+    // The scale annotation
+    $annotations["{scale}"] = "1 : " . $scaleDenominator;
+}
+
+function GetRequestMethod()
+{
+    if($_SERVER['REQUEST_METHOD'] == "POST")
+    {
+        return $_POST;
+    }
+    else
+    {
+        return $_GET;
+    }
+}
+
+?>

Deleted: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.templ
===================================================================
--- trunk/widgets/QuickPlot/QuickPlotPreviewInner.templ	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -1,85 +0,0 @@
-<html>
-<head>
-<title>__#QUICKPLOT_HEADER#__</title>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-<style type="text/css">
-body, table, td, div, input
-{
-    font: 9pt/1.5em __#@font#__;
-}
-
-td.LegalNotice
-{
-    font-size: 8pt;
-}
-
-input.Button
-{
-    width:75px;
-    height:23px;
-    margin-left:7px;
-}
-</style>
-
-<style type="text/css" media="screen">
-#PrintPicture { }
-
-.PrintOnly
-{
-    display:none;
-}
-</style>
-
-<style type="text/css" media="print">
-#PrintPicture { }
-input.Button
-{
-    visibility:hidden;
-}
-
-.ScreenOnly
-{
-    display: none;
-}
-</style>
-
-<script language="javascript" type="text/javascript" src="%sQuickPlotPreview.js"></script>
-</head>
-<body style="margin:0px" onLoad="innerLoaded()">
-<table cellspacing="10" cellpadding="0" style="width:100%%; border-width:0px" id="PreviewContainer">
-  <tr>
-    <td><table style="width:100%%" border="0" cellspacing="0" cellpadding="0" id="AnnotationContainer">
-        <tr>
-          <td style="width:100%%">{field:title}</td>
-          <!-- 
-            The date format mask follows the php date() function's instruction
-            see also here for more reference: http://cn.php.net/manual/en/function.date.php
-           -->
-          <td style="white-space:nowrap">{date:m/d/Y}</td>
-        </tr>
-        <tr>
-          <td>{field:sub_title}</td>
-          <td style="white-space:nowrap">__#QUICKPLOT_SCALE_LABEL#__: {scale}</td>
-        </tr>
-      </table></td>
-  </tr>
-  <tr>
-    <td id="PictureContainer" style="border: solid 1px black; text-align:center; vertical-align:center;">
-        <img style="width:1px; background:url(progress_indicator.gif) no-repeat center center" id="ProgressIndicator" src="pixel.gif" />
-        <img style="width:1px" id="PrintPicture" src="pixel.gif" />
-        <span id="PictureLoadingErrorMessage" style="display:none; text-align:center">__#QUICKPLOT_PREVIEW_ERROR#__</span>
-    </td>
-  </tr>
-  <tr>
-    <td><table width="100%%" border="0" cellspacing="0" cellpadding="0">
-        <tr>
-          <!-- Legal notice. Just replace it with the necessary statement -->
-          <td style="width:100%%" class="LegalNotice">The materials available at this web site are for informational purposes only and do not constitute a legal document.</td>
-          <td style="white-space:nowrap"><input type="button" id="PrintButton" class="Button" onClick="printIt()" value="__#QUICKPLOT_PRINT#__" /><input type="button" id="CancelButton" class="Button" onClick="cancelPreview()" value="__#QUICKPLOT_CANCEL#__" />
-          </td>
-        </tr>
-      </table></td>
-  </tr>
-</table>
-</body>
-</html>

Copied: branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.templ (from rev 2233, trunk/widgets/QuickPlot/QuickPlotPreviewInner.templ)
===================================================================
--- branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.templ	                        (rev 0)
+++ branches/fusion-2.2/widgets/QuickPlot/QuickPlotPreviewInner.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,85 @@
+<html>
+<head>
+<title>__#QUICKPLOT_HEADER#__</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<style type="text/css">
+body, table, td, div, input
+{
+    font: 9pt/1.5em __#@font#__;
+}
+
+td.LegalNotice
+{
+    font-size: 8pt;
+}
+
+input.Button
+{
+    width:75px;
+    height:23px;
+    margin-left:7px;
+}
+</style>
+
+<style type="text/css" media="screen">
+#PrintPicture { }
+
+.PrintOnly
+{
+    display:none;
+}
+</style>
+
+<style type="text/css" media="print">
+#PrintPicture { }
+input.Button
+{
+    visibility:hidden;
+}
+
+.ScreenOnly
+{
+    display: none;
+}
+</style>
+
+<script language="javascript" type="text/javascript" src="%sQuickPlotPreview.js"></script>
+</head>
+<body style="margin:0px" onLoad="innerLoaded()">
+<table cellspacing="10" cellpadding="0" style="width:100%%; border-width:0px" id="PreviewContainer">
+  <tr>
+    <td><table style="width:100%%" border="0" cellspacing="0" cellpadding="0" id="AnnotationContainer">
+        <tr>
+          <td style="width:100%%">{field:title}</td>
+          <!-- 
+            The date format mask follows the php date() function's instruction
+            see also here for more reference: http://cn.php.net/manual/en/function.date.php
+           -->
+          <td style="white-space:nowrap">{date:m/d/Y}</td>
+        </tr>
+        <tr>
+          <td>{field:sub_title}</td>
+          <td style="white-space:nowrap">__#QUICKPLOT_SCALE_LABEL#__: {scale}</td>
+        </tr>
+      </table></td>
+  </tr>
+  <tr>
+    <td id="PictureContainer" style="border: solid 1px black; text-align:center; vertical-align:center;">
+        <img style="width:1px; background:url(progress_indicator.gif) no-repeat center center" id="ProgressIndicator" src="pixel.gif" />
+        <img style="width:1px" id="PrintPicture" src="pixel.gif" />
+        <span id="PictureLoadingErrorMessage" style="display:none; text-align:center">__#QUICKPLOT_PREVIEW_ERROR#__</span>
+    </td>
+  </tr>
+  <tr>
+    <td><table width="100%%" border="0" cellspacing="0" cellpadding="0">
+        <tr>
+          <!-- Legal notice. Just replace it with the necessary statement -->
+          <td style="width:100%%" class="LegalNotice">The materials available at this web site are for informational purposes only and do not constitute a legal document.</td>
+          <td style="white-space:nowrap"><input type="button" id="PrintButton" class="Button" onClick="printIt()" value="__#QUICKPLOT_PRINT#__" /><input type="button" id="CancelButton" class="Button" onClick="cancelPreview()" value="__#QUICKPLOT_CANCEL#__" />
+          </td>
+        </tr>
+      </table></td>
+  </tr>
+</table>
+</body>
+</html>

Deleted: branches/fusion-2.2/widgets/QuickPlot/north_arrow.png
===================================================================
(Binary files differ)

Copied: branches/fusion-2.2/widgets/QuickPlot/north_arrow.png (from rev 2233, trunk/widgets/QuickPlot/north_arrow.png)
===================================================================
(Binary files differ)

Deleted: branches/fusion-2.2/widgets/QuickPlot/pixel.gif
===================================================================
(Binary files differ)

Copied: branches/fusion-2.2/widgets/QuickPlot/pixel.gif (from rev 2233, trunk/widgets/QuickPlot/pixel.gif)
===================================================================
(Binary files differ)

Deleted: branches/fusion-2.2/widgets/QuickPlot/progress_indicator.gif
===================================================================
(Binary files differ)

Copied: branches/fusion-2.2/widgets/QuickPlot/progress_indicator.gif (from rev 2233, trunk/widgets/QuickPlot/progress_indicator.gif)
===================================================================
(Binary files differ)

Deleted: branches/fusion-2.2/widgets/QuickPlot/rotate.cur
===================================================================
(Binary files differ)

Copied: branches/fusion-2.2/widgets/QuickPlot/rotate.cur (from rev 2233, trunk/widgets/QuickPlot/rotate.cur)
===================================================================
(Binary files differ)

Copied: branches/fusion-2.2/widgets/QuickPlot.js (from rev 2233, trunk/widgets/QuickPlot.js)
===================================================================
--- branches/fusion-2.2/widgets/QuickPlot.js	                        (rev 0)
+++ branches/fusion-2.2/widgets/QuickPlot.js	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,160 @@
+/**
+ * Fusion.Widget.QuickPlot
+ * Copyright (C) 2010 Autodesk, Inc. All rights reserved.
+ */
+
+ /*****************************************************************************
+ * Class: Fusion.Widget.QuickPlot
+ * This widget provides a quick way to print a certain region of map in a good quality
+ * **********************************************************************/
+
+Fusion.require("widgets/QuickPlot/MapCapturer.js");
+Fusion.require("widgets/QuickPlot/PreviewDialog.js");
+
+Fusion.Widget.QuickPlot = OpenLayers.Class(Fusion.Widget, 
+{
+    isExclusive: true,
+    uiClass: Jx.Button,
+    sFeatures : 'menubar=no,location=no,resizable=no,status=no',
+    options : {},
+    
+    initializeWidget: function(widgetTag) 
+    {
+        this.mapCapturer = new OpenLayers.Control.MapCapturer(this.getMap());
+        this.getMap().oMapOL.addControl(this.mapCapturer);
+        
+        var json                     = widgetTag.extension;
+        
+        this.sTarget  = json.Target ? json.Target[0] : "PrintPanelWindow";
+        this.sBaseUrl = Fusion.getFusionURL() + 'widgets/QuickPlot/QuickPlotPanel.php';
+        
+        this.additionalParameters = [];
+        if (json.AdditionalParameter) 
+        {
+            for (var i=0; i<json.AdditionalParameter.length; i++) 
+            {
+                var p = json.AdditionalParameter[i];
+                var k = p.Key[0];
+                var v = p.Value[0];
+                this.additionalParameters.push(k+'='+encodeURIComponent(v));
+            }
+        }
+    },
+
+    activate: function() 
+    {
+        var url = this.sBaseUrl;
+        var map = this.getMap();
+        var mapLayers      = map.getAllMaps();
+        var taskPaneTarget = Fusion.getWidgetById(this.sTarget);
+        var pageElement    = $(this.sTarget);
+
+        var params = [];
+        params.push('locale='+Fusion.locale);
+        params.push('session='+mapLayers[0].getSessionID());
+        params.push('mapname='+mapLayers[0].getMapName());
+        
+        if (taskPaneTarget || pageElement) 
+        {
+          params.push('popup=false');
+        } 
+        else 
+        {
+          params.push('popup=true');
+        }
+
+        params = params.concat(this.additionalParameters);
+
+        if (url.indexOf('?') < 0) 
+        {
+            url += '?';
+        } 
+        else if (url.slice(-1) != '&') 
+        {
+            url += '&';
+        }
+        
+        url += params.join('&');
+        
+        if (taskPaneTarget) 
+        {
+            taskPaneTarget.setContent(url);
+        } 
+        else 
+        {
+            if (pageElement) 
+            {
+                pageElement.src = url;
+            } 
+            else 
+            {
+                window.open(url, this.sTarget, this.sWinFeatures);
+            }
+        }
+        
+        // Expand taskpane automatically if it is the target window
+        if (panelman)
+        {
+            var panel = null;
+            for (var i = 0; i < panelman.panels.length; ++i)
+            {
+                panel = panelman.panels[i];
+                if (panel.options.contentId == this.sTarget)
+                {
+                    panelman.maximizePanel(panel);
+                    return;
+                }
+            }
+        }
+    },
+    
+    /***************************************************************************************
+     * The dialogContentLoadedCallback is used to submit the Quick Plot panel's parameters to the preview iframe
+     ***************************************************************************************/
+    preview: function(dialogConentLoadedCallback, printDpi)
+    {
+        var map = this.getMap();
+        var capture  = this.mapCapturer.getCaptureBox();
+        var normalizedCapture = this.mapCapturer.getNormalizedCapture();
+        var vertices = capture.geometry.getVertices();
+        this.options.printDpi = printDpi;
+        var options = {mapInfo : {sessionID : map.getSessionID(), name : map.getMapName()}, 
+                       captureInfo : {topLeftCs : {x : vertices[3].x, y : vertices[3].y},
+                                     bottomRightCs : {x : vertices[1].x, y : vertices[1].y}, 
+                                     paperSize : {w : this.mapCapturer.paperSize.w, h : this.mapCapturer.paperSize.h},
+                                     scaleDenominator : this.mapCapturer.scaleDenominator,
+                                     rotation : this.mapCapturer.rotation,
+                                     center : capture.geometry.getCentroid(),
+                                     params1 : capture.params,
+                                     params2 : normalizedCapture.params},
+                       params : this.options};
+        
+        if (!this.previewDialog)
+        {
+            this.previewDialog = new PreviewDialog(options);
+        }
+        else
+        {
+            this.previewDialog.mapInfo     = options.mapInfo;
+            this.previewDialog.captureInfo = options.captureInfo;
+            this.previewDialog.params      = options.params;
+        }
+        
+        this.previewDialog.open(dialogConentLoadedCallback);
+    },
+    
+    cancelPreview: function()
+    {
+        this.previewDialog.cancel();
+    },
+    
+    printPreview: function()
+    {
+        this.previewDialog.print();
+    },
+    
+    previewInnerLoaded: function()
+    {
+        this.previewDialog.previewInnerLoaded();
+    }
+});
\ No newline at end of file

Modified: branches/fusion-2.2/widgets/Search/ErrorPage.templ
===================================================================
--- branches/fusion-2.2/widgets/Search/ErrorPage.templ	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/Search/ErrorPage.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -51,10 +51,15 @@
 
 function GetParent()
 {
-    if(popup)
-        return opener;
-    else
-        return parent.parent;
+	if(popup)
+		return opener;
+	else
+	{
+		var node = parent;
+		while (!node.fusion && node.parent)
+			node = node.parent;
+		return node;
+	}
 }
 
 </script>

Modified: branches/fusion-2.2/widgets/Search/Search.templ
===================================================================
--- branches/fusion-2.2/widgets/Search/Search.templ	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/Search/Search.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -106,10 +106,15 @@
 
 function GetParent()
 {
-    if(popup)
-        return opener;
-    else
-        return parent.parent;
+	if(popup)
+		return opener;
+	else
+	{
+		var node = parent;
+		while (!node.Fusion && node.parent)
+			node = node.parent;
+		return node;
+	}
 }
 
 </script>

Modified: branches/fusion-2.2/widgets/Search/SearchPrompt.templ
===================================================================
--- branches/fusion-2.2/widgets/Search/SearchPrompt.templ	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/Search/SearchPrompt.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -80,10 +80,15 @@
 
 function GetParent()
 {
-    if(popup)
-        return opener;
-    else
-        return parent.parent;
+	if(popup)
+		return opener;
+	else
+	{
+		var node = parent;
+		while (!node.fusion && node.parent)
+			node = node.parent;
+		return node;
+	}
 }
 
 function SetMatchLabel()

Modified: branches/fusion-2.2/widgets/SelectWithin/SelectWithinPanel.templ
===================================================================
--- branches/fusion-2.2/widgets/SelectWithin/SelectWithinPanel.templ	2010-09-22 19:14:57 UTC (rev 2233)
+++ branches/fusion-2.2/widgets/SelectWithin/SelectWithinPanel.templ	2010-09-24 18:32:16 UTC (rev 2234)
@@ -146,12 +146,16 @@
 }
 
 function GetParent()
-{
-    if(popup) {
-        return opener;
-    } else {
-        return parent.parent;
-    }
+{debugger;
+	if(popup)
+		return opener;
+	else
+	{
+		var node = parent;
+		while (!node.Fusion && node.parent)
+			node = node.parent;
+		return node;
+	}
 }
 
 </script>

Copied: branches/fusion-2.2/widgets/widgetinfo/quickplot.xml (from rev 2233, trunk/widgets/widgetinfo/quickplot.xml)
===================================================================
--- branches/fusion-2.2/widgets/widgetinfo/quickplot.xml	                        (rev 0)
+++ branches/fusion-2.2/widgets/widgetinfo/quickplot.xml	2010-09-24 18:32:16 UTC (rev 2234)
@@ -0,0 +1,19 @@
+<WidgetInfo>
+    <Type>QuickPlot</Type>
+    <LocalizedType>QuickPlot</LocalizedType>
+    <Description>This widget offers a quick way to print map</Description>
+    <Label>Quick Plot</Label>
+    <Tooltip>Click to create a plot quickly</Tooltip>
+    <ImageUrl>images/icons/print.png</ImageUrl>
+    <ImageClass></ImageClass>
+    <StandardUi>true</StandardUi>
+    <ContainableBy>Any</ContainableBy>
+    <Parameter>
+        <Name>Target</Name>
+        <Description>The frame, window, or TaskPane in which to display any UI for the widget. If empty, a new window is used</Description>
+        <Type>target</Type>
+        <Label>Target</Label>
+        <DefaultValue>TaskPane</DefaultValue>
+        <IsMandatory>true</IsMandatory>
+    </Parameter>
+</WidgetInfo>



More information about the fusion-commits mailing list