[fusion-commits] r2322 - in trunk: . lib/OpenLayers

svn_fusion at osgeo.org svn_fusion at osgeo.org
Thu Jan 20 14:46:19 EST 2011


Author: madair
Date: 2011-01-20 11:46:05 -0800 (Thu, 20 Jan 2011)
New Revision: 2322

Modified:
   trunk/fusion.cfg
   trunk/lib/OpenLayers/OpenLayers.js
Log:
closes #430: update OpenLayers to latest trunk version; also changes to the way dependancies are calculated prompts a change in the .cfg file

Modified: trunk/fusion.cfg
===================================================================
--- trunk/fusion.cfg	2011-01-18 19:57:52 UTC (rev 2321)
+++ trunk/fusion.cfg	2011-01-20 19:46:05 UTC (rev 2322)
@@ -2,17 +2,6 @@
 # for Fusion
 
 [first]
-OpenLayers/SingleFile.js
-OpenLayers.js
-OpenLayers/Util.js
-OpenLayers/Console.js
-OpenLayers/BaseTypes.js
-OpenLayers/BaseTypes/Class.js
-OpenLayers/BaseTypes/Size.js
-OpenLayers/BaseTypes/Bounds.js
-OpenLayers/BaseTypes/Element.js
-OpenLayers/BaseTypes/LonLat.js
-OpenLayers/BaseTypes/Pixel.js
 
 [last]
 

Modified: trunk/lib/OpenLayers/OpenLayers.js
===================================================================
--- trunk/lib/OpenLayers/OpenLayers.js	2011-01-18 19:57:52 UTC (rev 2321)
+++ trunk/lib/OpenLayers/OpenLayers.js	2011-01-20 19:46:05 UTC (rev 2322)
@@ -1,100 +1,132 @@
-/*
-
-  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.js -- OpenLayers Map Viewer Library
+
+  Copyright 2005-2011 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.Util.pagePosition is based on Yahoo's getXY method, which is
+ * Copyright (c) 2006, Yahoo! Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use of this software in source and binary forms, with or
+ * without modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * 
+ * * 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.
+ * 
+ * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
+ *   used to endorse or promote products derived from this software without
+ *   specific prior written permission of Yahoo! Inc.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+ *//* ======================================================================
     OpenLayers/SingleFile.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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. */
@@ -138,411 +170,121 @@
     })()
 };
 /* ======================================================================
-    OpenLayers.js
+    OpenLayers/BaseTypes/Class.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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
+/**
+ * @requires OpenLayers/SingleFile.js
  */
- 
-/*
- * TODO: In 3.0, we will stop supporting build profiles that include
- * OpenLayers.js. This means we will not need the singleFile and scriptFile
- * variables, because we don't have to handle the singleFile case any more.
+
+/**
+ * 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 
+ *     will be removed.
+ * 
+ * To create a new OpenLayers-style class, use the following syntax:
+ * > var MyClass = OpenLayers.Class(prototype);
+ *
+ * To create a new OpenLayers-style class with multiple inheritance, use the
+ *     following syntax:
+ * > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
+ * Note that instanceof reflection will only reveil Class1 as superclass.
+ * Class2 ff are mixins.
+ *
  */
+OpenLayers.Class = function() {
+    var len = arguments.length;
+    var P = arguments[0];
+    var F = arguments[len-1];
 
-(function() {
-    /**
-     * Before creating the OpenLayers namespace, check to see if
-     * OpenLayers.singleFile is true.  This occurs if the
-     * OpenLayers/SingleFile.js script is included before this one - as is the
-     * case with old single file build profiles that included both
-     * OpenLayers.js and OpenLayers/SingleFile.js.
-     */
-    var singleFile = (typeof OpenLayers == "object" && OpenLayers.singleFile);
-    
-    /**
-     * Relative path of this script.
-     */
-    var scriptName = (!singleFile) ? "lib/OpenLayers.js" : "OpenLayers.js";
-    
-    /**
-     * Namespace: OpenLayers
-     * The OpenLayers object provides a namespace for all things OpenLayers
-     */
-    window.OpenLayers = {
-        /**
-         * Method: _getScriptLocation
-         * Return the path to this script. This is also implemented in
-         * OpenLayers/SingleFile.js
-         *
-         * Returns:
-         * {String} Path to this script
-         */
-        _getScriptLocation: (function() {
-            var r = new RegExp("(^|(.*?\\/))(" + scriptName + ")(\\?|$)"),
-                s = document.getElementsByTagName('script'),
-                src, m, l = "";
-            for(var i=0, len=s.length; i<len; i++) {
-                src = s[i].getAttribute('src');
-                if(src) {
-                    var m = src.match(r);
-                    if(m) {
-                        l = m[1];
-                        break;
-                    }
-                }
-            }
-            return (function() { return l; });
-        })()
-    };
-    /**
-     * 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 
-     * OpenLayers library code as it will be appended at the end of this file.
-     */
-    if(!singleFile) {
-        var jsfiles = new Array(
-            "OpenLayers/Util.js",
-            "OpenLayers/BaseTypes.js",
-            "OpenLayers/BaseTypes/Class.js",
-            "OpenLayers/BaseTypes/Bounds.js",
-            "OpenLayers/BaseTypes/Element.js",
-            "OpenLayers/BaseTypes/LonLat.js",
-            "OpenLayers/BaseTypes/Pixel.js",
-            "OpenLayers/BaseTypes/Size.js",
-            "OpenLayers/Console.js",
-            "OpenLayers/Tween.js",
-            "Rico/Corner.js",
-            "Rico/Color.js",
-            "OpenLayers/Ajax.js",
-            "OpenLayers/Events.js",
-            "OpenLayers/Request.js",
-            "OpenLayers/Request/XMLHttpRequest.js",
-            "OpenLayers/Projection.js",
-            "OpenLayers/Map.js",
-            "OpenLayers/Layer.js",
-            "OpenLayers/Icon.js",
-            "OpenLayers/Marker.js",
-            "OpenLayers/Marker/Box.js",
-            "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",
-            "OpenLayers/Layer/Grid.js",
-            "OpenLayers/Layer/MapGuide.js",
-            "OpenLayers/Layer/MapServer.js",
-            "OpenLayers/Layer/MapServer/Untiled.js",
-            "OpenLayers/Layer/KaMap.js",
-            "OpenLayers/Layer/KaMapCache.js",
-            "OpenLayers/Layer/MultiMap.js",
-            "OpenLayers/Layer/Markers.js",
-            "OpenLayers/Layer/Text.js",
-            "OpenLayers/Layer/WorldWind.js",
-            "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",
-            "OpenLayers/Popup/FramedCloud.js",
-            "OpenLayers/Feature.js",
-            "OpenLayers/Feature/Vector.js",
-            "OpenLayers/Feature/WFS.js",
-            "OpenLayers/Handler.js",
-            "OpenLayers/Handler/Click.js",
-            "OpenLayers/Handler/Hover.js",
-            "OpenLayers/Handler/Point.js",
-            "OpenLayers/Handler/Path.js",
-            "OpenLayers/Handler/Polygon.js",
-            "OpenLayers/Handler/Feature.js",
-            "OpenLayers/Handler/Drag.js",
-            "OpenLayers/Handler/RegularPolygon.js",
-            "OpenLayers/Handler/Box.js",
-            "OpenLayers/Handler/MouseWheel.js",
-            "OpenLayers/Handler/Keyboard.js",
-            "OpenLayers/Control.js",
-            "OpenLayers/Control/Attribution.js",
-            "OpenLayers/Control/Button.js",
-            "OpenLayers/Control/ZoomBox.js",
-            "OpenLayers/Control/ZoomToMaxExtent.js",
-            "OpenLayers/Control/DragPan.js",
-            "OpenLayers/Control/Navigation.js",
-            "OpenLayers/Control/MouseDefaults.js",
-            "OpenLayers/Control/MousePosition.js",
-            "OpenLayers/Control/OverviewMap.js",
-            "OpenLayers/Control/KeyboardDefaults.js",
-            "OpenLayers/Control/PanZoom.js",
-            "OpenLayers/Control/PanZoomBar.js",
-            "OpenLayers/Control/ArgParser.js",
-            "OpenLayers/Control/Permalink.js",
-            "OpenLayers/Control/Scale.js",
-            "OpenLayers/Control/ScaleLine.js",
-            "OpenLayers/Control/Snapping.js",
-            "OpenLayers/Control/Split.js",
-            "OpenLayers/Control/LayerSwitcher.js",
-            "OpenLayers/Control/DrawFeature.js",
-            "OpenLayers/Control/DragFeature.js",
-            "OpenLayers/Control/ModifyFeature.js",
-            "OpenLayers/Control/Panel.js",
-            "OpenLayers/Control/SelectFeature.js",
-            "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",
-            "OpenLayers/Geometry/Point.js",
-            "OpenLayers/Geometry/MultiPoint.js",
-            "OpenLayers/Geometry/Curve.js",
-            "OpenLayers/Geometry/LineString.js",
-            "OpenLayers/Geometry/LinearRing.js",        
-            "OpenLayers/Geometry/Polygon.js",
-            "OpenLayers/Geometry/MultiLineString.js",
-            "OpenLayers/Geometry/MultiPolygon.js",
-            "OpenLayers/Geometry/Surface.js",
-            "OpenLayers/Renderer.js",
-            "OpenLayers/Renderer/Elements.js",
-            "OpenLayers/Renderer/SVG.js",
-            "OpenLayers/Renderer/Canvas.js",
-            "OpenLayers/Renderer/VML.js",
-            "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",
-            "OpenLayers/Protocol/SQL/Gears.js",
-            "OpenLayers/Protocol/WFS.js",
-            "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/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",
-            "OpenLayers/Format/WFSCapabilities.js",
-            "OpenLayers/Format/WFSCapabilities/v1.js",
-            "OpenLayers/Format/WFSCapabilities/v1_0_0.js",
-            "OpenLayers/Format/WFSCapabilities/v1_1_0.js",
-            "OpenLayers/Format/WFSDescribeFeatureType.js",
-            "OpenLayers/Format/WMSDescribeLayer.js",
-            "OpenLayers/Format/WMSDescribeLayer/v1_1.js",
-            "OpenLayers/Format/WKT.js",
-            "OpenLayers/Format/OSM.js",
-            "OpenLayers/Format/GPX.js",
-            "OpenLayers/Format/Filter.js",
-            "OpenLayers/Format/Filter/v1.js",
-            "OpenLayers/Format/Filter/v1_0_0.js",
-            "OpenLayers/Format/Filter/v1_1_0.js",
-            "OpenLayers/Format/SLD.js",
-            "OpenLayers/Format/SLD/v1.js",
-            "OpenLayers/Format/SLD/v1_0_0.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",
-            "OpenLayers/Format/WFST/v1_1_0.js",
-            "OpenLayers/Format/Text.js",
-            "OpenLayers/Format/JSON.js",
-            "OpenLayers/Format/GeoJSON.js",
-            "OpenLayers/Format/WMC.js",
-            "OpenLayers/Format/WMC/v1.js",
-            "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",
-            "OpenLayers/Control/NavToolbar.js",
-            "OpenLayers/Control/PanPanel.js",
-            "OpenLayers/Control/Pan.js",
-            "OpenLayers/Control/ZoomIn.js",
-            "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.
+    var C = typeof F.initialize == "function" ?
+        F.initialize :
+        function(){ P.apply(this, arguments); };
 
-        var agent = navigator.userAgent;
-        var docWrite = (agent.match("MSIE") || agent.match("Safari"));
-        if(docWrite) {
-            var allScriptTags = new Array(jsfiles.length);
-        }
-        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>"; 
-            } else {
-                var s = document.createElement("script");
-                s.src = host + jsfiles[i];
-                var h = document.getElementsByTagName("head").length ? 
-                           document.getElementsByTagName("head")[0] : 
-                           document.body;
-                h.appendChild(s);
-            }
-        }
-        if (docWrite) {
-            document.write(allScriptTags.join(""));
-        }
+    if (len > 1) {
+        var newArgs = [C, P].concat(
+                Array.prototype.slice.call(arguments).slice(1, len-1), F);
+        OpenLayers.inherit.apply(null, newArgs);
+    } else {
+        C.prototype = F;
     }
-})();
+    return C;
+};
 
 /**
- * Constant: VERSION_NUMBER
+ * Property: isPrototype
+ * *Deprecated*.  This is no longer needed and will be removed at 3.0.
  */
-OpenLayers.VERSION_NUMBER="$Revision$";
-/* ======================================================================
-    OpenLayers/Util.js
-   ====================================================================== */
+OpenLayers.Class.isPrototype = function () {};
 
-/* 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/Console.js
+ * APIFunction: OpenLayers.create
+ * *Deprecated*.  Old method to create an OpenLayers style class.  Use the
+ *     <OpenLayers.Class> constructor instead.
+ *
+ * Returns:
+ * An OpenLayers class
  */
-
-/**
- * Namespace: Util
- */
-OpenLayers.Util = {};
-
-/** 
- * Function: getElement
- * This is the old $() from prototype
- */
-OpenLayers.Util.getElement = function() {
-    var elements = [];
-
-    for (var i=0, len=arguments.length; i<len; i++) {
-        var element = arguments[i];
-        if (typeof element == 'string') {
-            element = document.getElementById(element);
+OpenLayers.Class.create = function() {
+    return function() {
+        if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
+            this.initialize.apply(this, arguments);
         }
-        if (arguments.length == 1) {
-            return element;
-        }
-        elements.push(element);
-    }
-    return elements;
+    };
 };
 
 /**
- * Function: isElement
- * A cross-browser implementation of "e instanceof Element".
+ * APIFunction: inherit
+ * *Deprecated*.  Old method to inherit from one or more OpenLayers style
+ *     classes.  Use the <OpenLayers.Class> constructor instead.
  *
  * Parameters:
- * o - {Object} The object to test.
+ * class - One or more classes can be provided as arguments
  *
  * Returns:
- * {Boolean}
+ * An object prototype
  */
-OpenLayers.Util.isElement = function(o) {
-    return !!(o && o.nodeType === 1);
+OpenLayers.Class.inherit = function (P) {
+    var C = function() {
+       P.call(this);
+    };
+    var newArgs = [C].concat(Array.prototype.slice.call(arguments));
+    OpenLayers.inherit.apply(null, newArgs);
+    return C.prototype;
 };
 
-/** 
- * Maintain existing definition of $.
+/**
+ * Function: OpenLayers.inherit
+ *
+ * Parameters:
+ * C - {Object} the class that inherits
+ * P - {Object} the superclass to inherit from
+ *
+ * In addition to the mandatory C and P parameters, an arbitrary number of
+ * objects can be passed, which will extend C.
  */
-if(typeof window.$  === "undefined") {
-    window.$ = OpenLayers.Util.getElement;
-}
+OpenLayers.inherit = function(C, P) {
+   var F = function() {};
+   F.prototype = P.prototype;
+   C.prototype = new F;
+   var i, l, o;
+   for(i=2, l=arguments.length; i<l; i++) {
+       o = arguments[i];
+       if(typeof o === "function") {
+           o = o.prototype;
+       }
+       OpenLayers.Util.extend(C.prototype, o);
+   }
+};
 
 /**
  * APIFunction: extend
@@ -557,12 +299,13 @@
  * Returns:
  * {Object} The destination object.
  */
+OpenLayers.Util = OpenLayers.Util || {};
 OpenLayers.Util.extend = function(destination, source) {
     destination = destination || {};
-    if(source) {
-        for(var property in source) {
+    if (source) {
+        for (var property in source) {
             var value = source[property];
-            if(value !== undefined) {
+            if (value !== undefined) {
                 destination[property] = value;
             }
         }
@@ -582,1734 +325,27 @@
         var sourceIsEvt = typeof window.Event == "function"
                           && source instanceof window.Event;
 
-        if(!sourceIsEvt
-           && source.hasOwnProperty && source.hasOwnProperty('toString')) {
+        if (!sourceIsEvt
+           && source.hasOwnProperty && source.hasOwnProperty("toString")) {
             destination.toString = source.toString;
         }
     }
     return destination;
 };
-
-
-/** 
- * Function: removeItem
- * Remove an object from an array. Iterates through the array
- *     to find the item, then removes it.
- *
- * Parameters:
- * array - {Array}
- * item - {Object}
- * 
- * Return
- * {Array} A reference to the array
- */
-OpenLayers.Util.removeItem = function(array, item) {
-    for(var i = array.length - 1; i >= 0; i--) {
-        if(array[i] == item) {
-            array.splice(i,1);
-            //break;more than once??
-        }
-    }
-    return array;
-};
-
-/**
- * Function: clearArray
- * *Deprecated*. This function will disappear in 3.0.
- * Please use "array.length = 0" instead.
- * 
- * Parameters:
- * array - {Array}
- */
-OpenLayers.Util.clearArray = function(array) {
-    OpenLayers.Console.warn(
-        OpenLayers.i18n(
-            "methodDeprecated", {'newMethod': 'array = []'}
-        )
-    );
-    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 first object was found in the array.
- *           If not found, returns -1.
- */
-OpenLayers.Util.indexOf = function(array, obj) {
-    // 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;   
-    }
-};
-
-
-
-/**
- * Function: modifyDOMElement
- * 
- * 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, 
- *                           relative, etc.
- * border - {String}         The style.border attribute.  eg:
- *                           solid black 2px
- * overflow - {String}       The style.overview attribute.  
- * opacity - {Float}         Fractional value (0.0 - 1.0)
- */
-OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, 
-                                            border, overflow, opacity) {
-
-    if (id) {
-        element.id = id;
-    }
-    if (px) {
-        element.style.left = px.x + "px";
-        element.style.top = px.y + "px";
-    }
-    if (sz) {
-        element.style.width = sz.w + "px";
-        element.style.height = sz.h + "px";
-    }
-    if (position) {
-        element.style.position = position;
-    }
-    if (border) {
-        element.style.border = border;
-    }
-    if (overflow) {
-        element.style.overflow = overflow;
-    }
-    if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) {
-        element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
-        element.style.opacity = opacity;
-    } else if (parseFloat(opacity) == 1.0) {
-        element.style.filter = '';
-        element.style.opacity = '';
-    }
-};
-
-/** 
- * 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 
- *               automatically.
- * 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 
- *                   background image.
- * position - {String} The style.position value. eg: absolute,
- *                     relative etc.
- * 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: 
- * {DOMElement} A DOM Div created with the specified attributes.
- */
-OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, 
-                                     border, overflow, opacity) {
-
-    var dom = document.createElement('div');
-
-    if (imgURL) {
-        dom.style.backgroundImage = 'url(' + imgURL + ')';
-    }
-
-    //set generic properties
-    if (!id) {
-        id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
-    }
-    if (!position) {
-        position = "absolute";
-    }
-    OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, 
-                                     border, overflow, opacity);
-
-    return dom;
-};
-
-/**
- * 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.
- * px - {<OpenLayers.Pixel>} The left and top positions.
- * sz - {<OpenLayers.Size>} The style.width and style.height values.
- * imgURL - {String} The url to use as the image source.
- * position - {String} The style.position value.
- * border - {String} The border to place around the image.
- * 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.
- */
-OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
-                                       opacity, delayDisplay) {
-
-    var image = document.createElement("img");
-
-    //set generic properties
-    if (!id) {
-        id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
-    }
-    if (!position) {
-        position = "relative";
-    }
-    OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, 
-                                     border, null, opacity);
-
-    if(delayDisplay) {
-        image.style.display = "none";
-        OpenLayers.Event.observe(image, "load", 
-            OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
-        OpenLayers.Event.observe(image, "error", 
-            OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
-        
-    }
-    
-    //set special properties
-    image.style.alt = id;
-    image.galleryImg = "no";
-    if (imgURL) {
-        image.src = imgURL;
-    }
-
-
-        
-    return image;
-};
-
-/**
- * Function: setOpacity
- * *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:
- *     http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
- *
- * Parameters:
- * element - {DOMElement} Set the opacity on this DOM element
- * opacity - {Float} Opacity value (0.0 - 1.0)
- */
-OpenLayers.Util.setOpacity = function(element, opacity) {
-    OpenLayers.Util.modifyDOMElement(element, null, null, null,
-                                     null, null, null, opacity);
-};
-
-/**
- * Function: onImageLoad
- * Bound to image load events.  For all images created with <createImage> or
- *     <createAlphaImageDiv>, this function will be bound to the load event.
- */
-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' 
-    // 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 
-    // 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.display = "";  
-    }
-    OpenLayers.Element.removeClass(this, "olImageLoadError");
-};
-
-/**
- * Property: IMAGE_RELOAD_ATTEMPTS
- * {Integer} How many times should we try to reload an image before giving up?
- *           Default is 0
- */
-OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
-
-/**
- * Function: onImageLoadError 
- */
-OpenLayers.Util.onImageLoadError = function() {
-    this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
-    if (this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
-        var urls = this.urls;
-        if (urls && urls instanceof Array && urls.length > 1){
-            var src = this.src.toString();
-            var current_url, k;
-            for (k = 0; current_url = urls[k]; k++){
-                if(src.indexOf(current_url) != -1){
-                    break;
-                }
-            }
-            var guess = Math.floor(urls.length * Math.random());
-            var new_url = urls[guess];
-            k = 0;
-            while(new_url == current_url && k++ < 4){
-                guess = Math.floor(urls.length * Math.random());
-                new_url = urls[guess];
-            }
-            this.src = src.replace(current_url, new_url);
-        } else {
-            this.src = this.src;
-        }
-    } else {
-        OpenLayers.Element.addClass(this, "olImageLoadError");
-    }
-    this.style.display = "";
-};
-
-/**
- * Property: alphaHackNeeded
- * {Boolean} true if the png alpha hack is necessary and possible, false otherwise.
- */
-OpenLayers.Util.alphaHackNeeded = null;
-
-/**
- * Function: alphaHack
- * 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.
- */
-OpenLayers.Util.alphaHack = function() {
-    if (OpenLayers.Util.alphaHackNeeded == null) {
-        var arVersion = navigator.appVersion.split("MSIE");
-        var version = parseFloat(arVersion[1]);
-        var filter = false;
-    
-        // 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 { 
-            filter = !!(document.body.filters);
-        } 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>}
- * sz - {<OpenLayers.Size>}
- * imgURL - {String}
- * position - {String}
- * 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, 
-                                               opacity) {
-
-    OpenLayers.Util.modifyDOMElement(div, id, px, sz, position,
-                                     null, null, opacity);
-
-    var img = div.childNodes[0];
-
-    if (imgURL) {
-        img.src = imgURL;
-    }
-    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";
-        }
-        if (sizing == null) {
-            sizing = "scale";
-        }
-        
-        div.style.filter = "progid:DXImageTransform.Microsoft" +
-                           ".AlphaImageLoader(src='" + img.src + "', " +
-                           "sizingMethod='" + sizing + "')";
-        if (parseFloat(div.style.opacity) >= 0.0 && 
-            parseFloat(div.style.opacity) < 1.0) {
-            div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
-        }
-
-        img.style.filter = "alpha(opacity=0)";
-    }
-};
-
-/** 
- * Function: createAlphaImageDiv
- * 
- * id - {String}
- * px - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- * imgURL - {String}
- * position - {String}
- * border - {String}
- * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale"
- * 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 
- *              needed for transparency in IE, it is added.
- */ 
-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, 
-                                          null, false);
-    div.appendChild(img);
-
-    if (delayDisplay) {
-        img.style.display = "none";
-        OpenLayers.Event.observe(img, "load",
-            OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
-        OpenLayers.Event.observe(img, "error",
-            OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
-    }
-
-    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 
- *     passed-in object, but storing them under an uppercased
- *     version of the key at which they were stored.
- * 
- * Parameters: 
- * object - {Object}
- * 
- * Returns: 
- * {Object} A new Object with all the same keys but uppercased
- */
-OpenLayers.Util.upperCaseObject = function (object) {
-    var uObject = {};
-    for (var key in object) {
-        uObject[key.toUpperCase()] = object[key];
-    }
-    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
- *     are undefined in the to object will be set on the to object.
- *
- * Returns:
- * {Object} A reference to the to object.  Note that the to argument is modified
- *     in place and returned by this function.
- */
-OpenLayers.Util.applyDefaults = function (to, from) {
-    to = to || {};
-    /*
-     * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
-     * prototype object" when calling hawOwnProperty if the source object is an
-     * instance of window.Event.
-     */
-    var fromIsEvt = typeof window.Event == "function"
-                    && from instanceof window.Event;
-
-    for (var key in from) {
-        if (to[key] === undefined ||
-            (!fromIsEvt && from.hasOwnProperty
-             && from.hasOwnProperty(key) && !to.hasOwnProperty(key))) {
-            to[key] = from[key];
-        }
-    }
-    /**
-     * IE doesn't include the toString property when iterating over an object's
-     * properties with the for(property in object) syntax.  Explicitly check if
-     * the source has its own toString property.
-     */
-    if(!fromIsEvt && from && from.hasOwnProperty
-       && 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. 
- *          (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). 
- */
-OpenLayers.Util.getParameterString = function(params) {
-    var paramsArray = [];
-    
-    for (var key in params) {
-      var value = params[key];
-      if ((value != null) && (typeof value != 'function')) {
-        var encodedValue;
-        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++) {
-            item = value[itemIndex];
-            encodedItemArray.push(encodeURIComponent(
-                (item === null || item === undefined) ? "" : item)
-            );
-          }
-          encodedValue = encodedItemArray.join(",");
-        }
-        else {
-          /* value is a string; simply encode */
-          encodedValue = encodeURIComponent(value);
-        }
-        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
- */
-OpenLayers.Util.getImagesLocation = function() {
-    return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
-};
-
-
-/** 
- * Function: Try
- * 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. 
- *    If none executes successfully, returns null.
- * 
- * Returns:
- * {*} The value returned by the first successfully executed function.
- */
-OpenLayers.Util.Try = function() {
-    var returnValue = null;
-
-    for (var i=0, len=arguments.length; i<len; i++) {
-      var lambda = arguments[i];
-      try {
-        returnValue = lambda();
-        break;
-      } catch (e) {}
-    }
-
-    return returnValue;
-};
-
-
-/** 
- * Function: getNodes
- * 
- * These could/should be made namespace aware?
- * 
- * Parameters:
- * p - {}
- * tagName - {String}
- * 
- * Returns:
- * {Array}
- */
-OpenLayers.Util.getNodes=function(p, tagName) {
-    var nodes = OpenLayers.Util.Try(
-        function () {
-            return OpenLayers.Util._getNodes(p.documentElement.childNodes,
-                                            tagName);
-        },
-        function () {
-            return OpenLayers.Util._getNodes(p.childNodes, tagName);
-        }
-    );
-    return nodes;
-};
-
-/**
- * Function: _getNodes
- * 
- * Parameters:
- * nodes - {Array}
- * tagName - {String}
- * 
- * Returns:
- * {Array}
- */
-OpenLayers.Util._getNodes=function(nodes, tagName) {
-    var retArray = [];
-    for (var i=0, len=nodes.length; i<len; i++) {
-        if (nodes[i].nodeName==tagName) {
-            retArray.push(nodes[i]);
-        }
-    }
-
-    return retArray;
-};
-
-
-
-/**
- * Function: getTagText
- * 
- * Parameters:
- * parent - {}
- * item - {String}
- * index - {Integer}
- * 
- * Returns:
- * {String}
- */
-OpenLayers.Util.getTagText = function (parent, item, index) {
-    var result = OpenLayers.Util.getNodes(parent, item);
-    if (result && (result.length > 0))
-    {
-        if (!index) {
-            index=0;
-        }
-        if (result[index].childNodes.length > 1) {
-            return result.childNodes[1].nodeValue; 
-        }
-        else if (result[index].childNodes.length == 1) {
-            return result[index].firstChild.nodeValue; 
-        }
-    } 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( 
-        function() {
-            val = node.text;
-            if (!val) {
-                val = node.textContent;
-            }
-            if (!val) {
-                val = node.firstChild.nodeValue;
-            }
-        }, 
-        function() {
-            val = node.textContent;
-        }); 
-    return val;
-};
-
-/** 
- * Function: mouseLeft
- * 
- * Parameters:
- * evt - {Event}
- * div - {HTMLDivElement}
- * 
- * Returns:
- * {Boolean}
- */
-OpenLayers.Util.mouseLeft = function (evt, div) {
-    // start with the element to which the mouse has moved
-    var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
-    // walk up the DOM tree.
-    while (target != div && target != null) {
-        target = target.parentNode;
-    }
-    // if the target we stop at isn't the div, then we've left the div.
-    return (target != div);
-};
-
-/**
- * Property: precision
- * {Number} The number of significant digits to retain to avoid
- * floating point precision errors.
- *
- * We use 14 as a "safe" default because, although IEEE 754 double floats
- * (standard on most modern operating systems) support up to about 16
- * significant digits, 14 significant digits are sufficient to represent
- * sub-millimeter accuracy in any coordinate system that anyone is likely to
- * use with OpenLayers.
- *
- * If DEFAULT_PRECISION is set to 0, the original non-truncating behavior
- * of OpenLayers <2.8 is preserved. Be aware that this will cause problems
- * with certain projections, e.g. spherical Mercator.
- *
- */
-OpenLayers.Util.DEFAULT_PRECISION = 14;
-
-/**
- * Function: toFloat
- * Convenience method to cast an object to a Number, rounded to the
- * desired floating point precision.
- *
- * Parameters:
- * number    - {Number} The number to cast and round.
- * precision - {Number} An integer suitable for use with
- *      Number.toPrecision(). Defaults to OpenLayers.Util.DEFAULT_PRECISION.
- *      If set to 0, no rounding is performed.
- *
- * Returns:
- * {Number} The cast, rounded number.
- */
-OpenLayers.Util.toFloat = function (number, precision) {
-    if (precision == null) {
-        precision = OpenLayers.Util.DEFAULT_PRECISION;
-    }
-    var number;
-    if (precision == 0) {
-        number = parseFloat(number);
-    } else {
-        number = parseFloat(parseFloat(number).toPrecision(precision));
-    }
-    return number;
-};
-
-/**
- * Function: rad
- * 
- * Parameters:
- * x - {Float}
- * 
- * Returns:
- * {Float}
- */
-OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
-
-/**
- * Function: deg
- *
- * Parameters:
- * x - {Float}
- *
- * Returns:
- * {Float}
- */
-OpenLayers.Util.deg = function(x) {return x*180/Math.PI;};
-
-/**
- * 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.
- *
- * Parameters:
- * p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
- * p2 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
- *
- * Returns:
- * {Float} The distance (in km) between the two input points as measured on an
- *     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 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)));
-    var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
-    var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
-    var lambda = L, lambdaP = 2*Math.PI;
-    var iterLimit = 20;
-    while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
-        var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
-        var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
-        (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
-        if (sinSigma==0) {
-            return 0;  // co-incident points
-        }
-        var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
-        var sigma = Math.atan2(sinSigma, cosSigma);
-        var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma);
-        var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha);
-        var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
-        var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
-        lambdaP = lambda;
-        lambda = L + (1-C) * f * Math.sin(alpha) *
-        (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
-    }
-    if (iterLimit==0) {
-        return NaN;  // formula failed to converge
-    }
-    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 deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
-        B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
-    var s = b*A*(sigma-deltaSigma);
-    var d = s.toFixed(3)/1000; // round to 1mm precision
-    return d;
-};
-
-/**
- * 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 
- *     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.
- */
-OpenLayers.Util.getParameters = function(url) {
-    // if no url specified, take it from the location bar
-    url = url || window.location.href;
-
-    //parse out parameters portion of url string
-    var paramsString = "";
-    if (OpenLayers.String.contains(url, '?')) {
-        var start = url.indexOf('?') + 1;
-        var end = OpenLayers.String.contains(url, "#") ?
-                    url.indexOf('#') : url.length;
-        paramsString = url.substring(start, end);
-    }
-
-    var parameters = {};
-    var pairs = paramsString.split(/[&;]/);
-    for(var i=0, len=pairs.length; i<len; ++i) {
-        var keyValue = pairs[i].split('=');
-        if (keyValue[0]) {
-
-            var key = keyValue[0];
-            try {
-                key = decodeURIComponent(key);
-            } catch (err) {
-                key = unescape(key);
-            }
-            
-            // being liberal by replacing "+" with " "
-            var value = (keyValue[1] || '').replace(/\+/g, " ");
-
-            try {
-                value = decodeURIComponent(value);
-            } catch (err) {
-                value = unescape(value);
-            }
-            
-            // follow OGC convention of comma delimited values
-            value = value.split(",")
-
-            //if there's only one value, do not return as array                    
-            if (value.length == 1) {
-                value = value[0];
-            }                
-            
-            parameters[key] = value;
-         }
-     }
-    return parameters;
-};
-
-/**
- * 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.
- */
-OpenLayers.Util.getArgs = function(url) {
-    OpenLayers.Console.warn(
-        OpenLayers.i18n(
-            "methodDeprecated", {'newMethod': 'OpenLayers.Util.getParameters'}
-        )
-    );
-    return OpenLayers.Util.getParameters(url);
-};
-
-/**
- * Property: lastSeqID
- * {Integer} The ever-incrementing count variable.
- *           Used for generating unique ids.
- */
-OpenLayers.Util.lastSeqID = 0;
-
-/**
- * Function: createUniqueID
- * 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.
- */
-OpenLayers.Util.createUniqueID = function(prefix) {
-    if (prefix == null) {
-        prefix = "id_";
-    }
-    OpenLayers.Util.lastSeqID += 1; 
-    return prefix + OpenLayers.Util.lastSeqID;        
-};
-
-/**
- * Constant: INCHES_PER_UNIT
- * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
- * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
- * Includes the full set of units supported by CS-MAP (http://trac.osgeo.org/csmap/)
- * and PROJ.4 (http://trac.osgeo.org/proj/)
- * 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 = { 
-    'inches': 1.0,
-    'ft': 12.0,
-    'mi': 63360.0,
-    'm': 39.3701,
-    'km': 39370.1,
-    'dd': 4374754,
-    'yd': 36
-};
-OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
-OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
-OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
-
-// Units from CS-Map
-OpenLayers.METERS_PER_INCH = 0.02540005080010160020;
-OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
-    "Inch": OpenLayers.INCHES_PER_UNIT.inches,
-    "Meter": 1.0 / OpenLayers.METERS_PER_INCH,   //EPSG:9001
-    "Foot": 0.30480060960121920243 / OpenLayers.METERS_PER_INCH,   //EPSG:9003
-    "IFoot": 0.30480000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9002
-    "ClarkeFoot": 0.3047972651151 / OpenLayers.METERS_PER_INCH,   //EPSG:9005
-    "SearsFoot": 0.30479947153867624624 / OpenLayers.METERS_PER_INCH,   //EPSG:9041
-    "GoldCoastFoot": 0.30479971018150881758 / OpenLayers.METERS_PER_INCH,   //EPSG:9094
-    "IInch": 0.02540000000000000000 / OpenLayers.METERS_PER_INCH,
-    "MicroInch": 0.00002540000000000000 / OpenLayers.METERS_PER_INCH,
-    "Mil": 0.00000002540000000000 / OpenLayers.METERS_PER_INCH,
-    "Centimeter": 0.01000000000000000000 / OpenLayers.METERS_PER_INCH,
-    "Kilometer": 1000.00000000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9036
-    "Yard": 0.91440182880365760731 / OpenLayers.METERS_PER_INCH,
-    "SearsYard": 0.914398414616029 / OpenLayers.METERS_PER_INCH,   //EPSG:9040
-    "IndianYard": 0.91439853074444079983 / OpenLayers.METERS_PER_INCH,   //EPSG:9084
-    "IndianYd37": 0.91439523 / OpenLayers.METERS_PER_INCH,   //EPSG:9085
-    "IndianYd62": 0.9143988 / OpenLayers.METERS_PER_INCH,   //EPSG:9086
-    "IndianYd75": 0.9143985 / OpenLayers.METERS_PER_INCH,   //EPSG:9087
-    "IndianFoot": 0.30479951 / OpenLayers.METERS_PER_INCH,   //EPSG:9080
-    "IndianFt37": 0.30479841 / OpenLayers.METERS_PER_INCH,   //EPSG:9081
-    "IndianFt62": 0.3047996 / OpenLayers.METERS_PER_INCH,   //EPSG:9082
-    "IndianFt75": 0.3047995 / OpenLayers.METERS_PER_INCH,   //EPSG:9083
-    "Mile": 1609.34721869443738887477 / OpenLayers.METERS_PER_INCH,
-    "IYard": 0.91440000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9096
-    "IMile": 1609.34400000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9093
-    "NautM": 1852.00000000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9030
-    "Lat-66": 110943.316488932731 / OpenLayers.METERS_PER_INCH,
-    "Lat-83": 110946.25736872234125 / OpenLayers.METERS_PER_INCH,
-    "Decimeter": 0.10000000000000000000 / OpenLayers.METERS_PER_INCH,
-    "Millimeter": 0.00100000000000000000 / OpenLayers.METERS_PER_INCH,
-    "Dekameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
-    "Decameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
-    "Hectometer": 100.00000000000000000000 / OpenLayers.METERS_PER_INCH,
-    "GermanMeter": 1.0000135965 / OpenLayers.METERS_PER_INCH,   //EPSG:9031
-    "CaGrid": 0.999738 / OpenLayers.METERS_PER_INCH,
-    "ClarkeChain": 20.1166194976 / OpenLayers.METERS_PER_INCH,   //EPSG:9038
-    "GunterChain": 20.11684023368047 / OpenLayers.METERS_PER_INCH,   //EPSG:9033
-    "BenoitChain": 20.116782494375872 / OpenLayers.METERS_PER_INCH,   //EPSG:9062
-    "SearsChain": 20.11676512155 / OpenLayers.METERS_PER_INCH,   //EPSG:9042
-    "ClarkeLink": 0.201166194976 / OpenLayers.METERS_PER_INCH,   //EPSG:9039
-    "GunterLink": 0.2011684023368047 / OpenLayers.METERS_PER_INCH,   //EPSG:9034
-    "BenoitLink": 0.20116782494375872 / OpenLayers.METERS_PER_INCH,   //EPSG:9063
-    "SearsLink": 0.2011676512155 / OpenLayers.METERS_PER_INCH,   //EPSG:9043
-    "Rod": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
-    "IntnlChain": 20.1168 / OpenLayers.METERS_PER_INCH,   //EPSG:9097
-    "IntnlLink": 0.201168 / OpenLayers.METERS_PER_INCH,   //EPSG:9098
-    "Perch": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
-    "Pole": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
-    "Furlong": 201.1684023368046 / OpenLayers.METERS_PER_INCH,
-    "Rood": 3.778266898 / OpenLayers.METERS_PER_INCH,
-    "CapeFoot": 0.3047972615 / OpenLayers.METERS_PER_INCH,
-    "Brealey": 375.00000000000000000000 / OpenLayers.METERS_PER_INCH,
-    "ModAmFt": 0.304812252984505969011938 / OpenLayers.METERS_PER_INCH,
-    "Fathom": 1.8288 / OpenLayers.METERS_PER_INCH,
-    "NautM-UK": 1853.184 / OpenLayers.METERS_PER_INCH,
-    "50kilometers": 50000.0 / OpenLayers.METERS_PER_INCH,
-    "150kilometers": 150000.0 / OpenLayers.METERS_PER_INCH
-});
-
-//unit abbreviations supported by PROJ.4
-OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
-    "mm": OpenLayers.INCHES_PER_UNIT["Meter"] / 1000.0,
-    "cm": OpenLayers.INCHES_PER_UNIT["Meter"] / 100.0,
-    "dm": OpenLayers.INCHES_PER_UNIT["Meter"] * 100.0,
-    "km": OpenLayers.INCHES_PER_UNIT["Meter"] * 1000.0,
-    "kmi": OpenLayers.INCHES_PER_UNIT["nmi"],    //International Nautical Mile
-    "fath": OpenLayers.INCHES_PER_UNIT["Fathom"], //International Fathom
-    "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-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
-    "ind-ft": OpenLayers.INCHES_PER_UNIT["IndianFt37"],  //Indian Foot
-    "ind-ch": 20.11669506 / OpenLayers.METERS_PER_INCH  //Indian Chain
-});
-
-/** 
- * Constant: DOTS_PER_INCH
- * {Integer} 72 (A sensible default)
- */
-OpenLayers.DOTS_PER_INCH = 72;
-
-/**
- * Function: normalizeScale
- * 
- * Parameters:
- * scale - {float}
- * 
- * Returns:
- * {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 
- *         1 / scale
- */
-OpenLayers.Util.normalizeScale = function (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.  If the given scale is falsey, the returned resolution will
- *     be undefined.
- */
-OpenLayers.Util.getResolutionFromScale = function (scale, units) {
-    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);        
-    }
-    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 
- *         parameters.
- */
-OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
-
-    if (units == null) {
-        units = "degrees";
-    }
-
-    var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
-                    OpenLayers.DOTS_PER_INCH;
-    return scale;
-};
-
-/**
- * Function: safeStopPropagation
- * *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}
- */
-OpenLayers.Util.safeStopPropagation = function(evt) {
-    OpenLayers.Event.stop(evt, true);
-};
-
-/**
- * Function: pagePositon
- * Calculates the position of an element on the page. 
- *
- * Parameters:
- * forElement - {DOMElement}
- * 
- * Returns:
- * {Array} two item array, L value then T value.
- */
-OpenLayers.Util.pagePosition = function(forElement) {
-    var valueT = 0, valueL = 0;
-
-    var element = forElement;
-    var child = forElement;
-    while(element) {
-
-        if(element == document.body) {
-            if(OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
-                break;
-            }
-        }
-        
-        valueT += element.offsetTop  || 0;
-        valueL += element.offsetLeft || 0;
-
-        child = element;
-        try {
-            // wrapping this in a try/catch because IE chokes on the offsetParent
-            element = element.offsetParent;
-        } catch(e) {
-            OpenLayers.Console.error(OpenLayers.i18n(
-                                  "pagePositionFailed",{'elemId':element.id}));
-            break;
-        }
-    }
-
-    element = forElement;
-    while(element) {
-        valueT -= element.scrollTop  || 0;
-        valueL -= element.scrollLeft || 0;
-        element = element.parentNode;
-    }
-    
-    return [valueL, valueT];
-};
-
-
-/** 
- * Function: isEquivalentUrl
- * Test two URLs for equivalence. 
- * 
- * Setting 'ignoreCase' allows for case-independent comparison.
- * 
- * 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) 
- *  - Arguments (so they can be out of order)
- *  
- * Parameters:
- * url1 - {String}
- * url2 - {String}
- * options - {Object} Allows for customization of comparison:
- *                    'ignoreCase' - Default is True
- *                    'ignorePort80' - Default is True
- *                    'ignoreHash' - Default is True
- *
- * Returns:
- * {Boolean} Whether or not the two URLs are equivalent
- */
-OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
-    options = options || {};
-
-    OpenLayers.Util.applyDefaults(options, {
-        ignoreCase: true,
-        ignorePort80: true,
-        ignoreHash: true
-    });
-
-    var urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
-    var urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
-
-    //compare all keys except for "args" (treated below)
-    for(var key in urlObj1) {
-        if(key !== "args") {
-            if(urlObj1[key] != urlObj2[key]) {
-                return false;
-            }
-        }
-    }
-
-    // compare search args - irrespective of order
-    for(var key in urlObj1.args) {
-        if(urlObj1.args[key] != urlObj2.args[key]) {
-            return false;
-        }
-        delete urlObj2.args[key];
-    }
-    // urlObj2 shouldn't have any args left
-    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 
- *          and ready for comparison
- */
-OpenLayers.Util.createUrlObject = function(url, options) {
-    options = options || {};
-
-    // deal with relative urls first
-    if(!(/^\w+:\/\//).test(url)) {
-        var loc = window.location;
-        var port = loc.port ? ":" + loc.port : "";
-        var fullUrl = loc.protocol + "//" + loc.host.split(":").shift() + port;
-        if(url.indexOf("/") === 0) {
-            // full pathname
-            url = fullUrl + url;
-        } else {
-            // relative to current path
-            var parts = loc.pathname.split("/");
-            parts.pop();
-            url = fullUrl + parts.join("/") + "/" + url;
-        }
-    }
-  
-    if (options.ignoreCase) {
-        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;  
-
-    //port (get uniform browser behavior with port 80 here)
-    if(options.ignorePort80) {
-        urlObject.port = (a.port == "80" || a.port == "0") ? "" : a.port;
-    } else {
-        urlObject.port = (a.port == "" || a.port == "0") ? "80" : a.port;
-    }
-
-    //hash
-    urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash;  
-    
-    //args
-    var queryString = a.search;
-    if (!queryString) {
-        var qMark = url.indexOf("?");
-        queryString = (qMark != -1) ? url.substr(qMark) : "";
-    }
-    urlObject.args = OpenLayers.Util.getParameters(queryString);
-
-    //pathname (uniform browser behavior with leading "/")
-    urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname;
-    
-    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)) 
-                                  : url.substr(0, qMark);
-    }
-    return head;
-};
-
-
-/**
- * Function: getBrowserName
- * 
- * Returns:
- * {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 
- *           return an empty string.
- */
-OpenLayers.Util.getBrowserName = function() {
-    var browserName = "";
-    
-    var ua = navigator.userAgent.toLowerCase();
-    if ( ua.indexOf( "opera" ) != -1 ) {
-        browserName = "opera";
-    } else if ( ua.indexOf( "msie" ) != -1 ) {
-        browserName = "msie";
-    } else if ( ua.indexOf( "safari" ) != -1 ) {
-        browserName = "safari";
-    } else if ( ua.indexOf( "mozilla" ) != -1 ) {
-        if ( ua.indexOf( "firefox" ) != -1 ) {
-            browserName = "firefox";
-        } else {
-            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 
- *     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 
- *     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. 
- * 
- * 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;
-
-    //fix a dimension, if specified.
-    if (size) {
-        if (size.w) {
-            w = size.w;
-            container.style.width = w + "px";
-        } else if (size.h) {
-            h = size.h;
-            container.style.height = h + "px";
-        }
-    }
-
-    //add css classes, if specified
-    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) {
-        for (var i=0, l=content.childNodes.length; i<l; i++) {
-            if (!content.childNodes[i].style) continue;
-            content.childNodes[i].style.overflow = "visible";
-        }
-    }
-    
-    // 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;
-    var parent = container.parentNode;
-    while (parent && parent.tagName.toLowerCase()!="body") {
-        var parentPosition = OpenLayers.Element.getStyle(parent, "position");
-        if(parentPosition == "absolute") {
-            parentHasPositionAbsolute = true;
-            break;
-        } else if (parentPosition && parentPosition != "static") {
-            break;
-        }
-        parent = parent.parentNode;
-    }
-
-    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);
-    }
-
-    // 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 
- *     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. 
- * 
- * 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';
-        scr.style.top = '-1000px';
-        scr.style.left = '-1000px';
-        scr.style.width = '100px';
-        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;
-    }
-
-    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-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/Class.js
+ */
+
+/**
  * Namespace: OpenLayers.Console
  * The OpenLayers.Console namespace is used for debugging and error logging.
  * If the Firebug Lite (../Firebug/firebug.js) is included before this script,
@@ -2551,22 +587,154 @@
     }
 })();
 /* ======================================================================
+    OpenLayers/Lang.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2011 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/Console.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang
+ * Internationalization namespace.  Contains dictionaries in various languages
+ *     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
+     *     retrieve it.
+     */
+    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.
+     *
+     * Returns:
+     * The current language code.
+     */
+    getCode: function() {
+        if(!OpenLayers.Lang.code) {
+            OpenLayers.Lang.setCode();
+        }
+        return OpenLayers.Lang.code;
+    },
+    
+    /**
+     * APIFunction: setCode
+     * Set the language code for string translation.  This code is used by
+     *     the <OpenLayers.Lang.translate> method.
+     *
+     * Parameters-
+     * code - {String} These codes follow the IETF recommendations at
+     *     http://www.ietf.org/rfc/rfc3066.txt.  If no value is set, the
+     *     browser's language setting will be tested.  If no <OpenLayers.Lang>
+     *     dictionary exists for the code, the <OpenLayers.String.defaultLang>
+     *     will be used.
+     */
+    setCode: function(code) {
+        var lang;
+        if(!code) {
+            code = (OpenLayers.BROWSER_NAME == "msie") ?
+                navigator.userLanguage : navigator.language;
+        }
+        var parts = code.split('-');
+        parts[0] = parts[0].toLowerCase();
+        if(typeof OpenLayers.Lang[parts[0]] == "object") {
+            lang = parts[0];
+        }
+
+        // check for regional extensions
+        if(parts[1]) {
+            var testLang = parts[0] + '-' + parts[1].toUpperCase();
+            if(typeof OpenLayers.Lang[testLang] == "object") {
+                lang = testLang;
+            }
+        }
+        if(!lang) {
+            OpenLayers.Console.warn(
+                'Failed to find OpenLayers.Lang.' + parts.join("-") +
+                ' dictionary, falling back to default language'
+            );
+            lang = OpenLayers.Lang.defaultCode;
+        }
+        
+        OpenLayers.Lang.code = lang;
+    },
+
+    /**
+     * APIMethod: translate
+     * Looks up a key from a dictionary based on the current language string.
+     *     The value of <getCode> will be used to determine the appropriate
+     *     dictionary.  Dictionaries are stored in <OpenLayers.Lang>.
+     *
+     * Parameters:
+     * 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.
+     */
+    translate: function(key, context) {
+        var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
+        var message = dictionary && dictionary[key];
+        if(!message) {
+            // Message not found, fall back to message key
+            message = key;
+        }
+        if(context) {
+            message = OpenLayers.String.format(message, context);
+        }
+        return message;
+    }
+    
+};
+
+
+/**
+ * APIMethod: OpenLayers.i18n
+ * Alias for <OpenLayers.Lang.translate>.  Looks up a key from a dictionary
+ *     based on the current language string. The value of
+ *     <OpenLayers.Lang.getCode> will be used to determine the appropriate
+ *     dictionary.  Dictionaries are stored in <OpenLayers.Lang>.
+ *
+ * Parameters:
+ * 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.
+ */
+OpenLayers.i18n = OpenLayers.Lang.translate;
+/* ======================================================================
     OpenLayers/BaseTypes.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/Class.js
- * @requires OpenLayers/BaseTypes/LonLat.js
- * @requires OpenLayers/BaseTypes/Size.js
- * @requires OpenLayers/BaseTypes/Pixel.js
- * @requires OpenLayers/BaseTypes/Bounds.js
- * @requires OpenLayers/BaseTypes/Element.js
- * @requires OpenLayers/Lang/en.js
+ * @requires OpenLayers/Lang.js
  * @requires OpenLayers/Console.js
  */
  
@@ -3222,7 +1390,7 @@
                     // check offset
                     if (type !== "Z") {
                         var hoursOffset = parseInt(type, 10);
-                        var minutesOffset = parseInt(match[8]) || 0;
+                        var minutesOffset = parseInt(match[8], 10) || 0;
                         var offset = -1000 * (60 * (hoursOffset * 60) + minutesOffset * 60);
                         date = new Date(date.getTime() + offset);
                     }
@@ -3236,217 +1404,18 @@
 
 };
 /* ======================================================================
-    OpenLayers/BaseTypes/Class.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. */
-
-/**
- * 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 
- *     will be removed.
- * 
- * To create a new OpenLayers-style class, use the following syntax:
- * > var MyClass = OpenLayers.Class(prototype);
- *
- * To create a new OpenLayers-style class with multiple inheritance, use the
- *     following syntax:
- * > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
- * Note that instanceof reflection will only reveil Class1 as superclass.
- * Class2 ff are mixins.
- *
- */
-OpenLayers.Class = function() {
-    var len = arguments.length;
-    var P = arguments[0];
-    var F = arguments[len-1];
-
-    var C = typeof F.initialize == "function" ?
-        F.initialize :
-        function(){ P.apply(this, arguments); };
-
-    if (len > 1) {
-        var newArgs = [C, P].concat(
-                Array.prototype.slice.call(arguments).slice(1, len-1), F);
-        OpenLayers.inherit.apply(null, newArgs);
-    } else {
-        C.prototype = F;
-    }
-    return C;
-};
-
-/**
- * Property: isPrototype
- * *Deprecated*.  This is no longer needed and will be removed at 3.0.
- */
-OpenLayers.Class.isPrototype = function () {};
-
-/**
- * APIFunction: OpenLayers.create
- * *Deprecated*.  Old method to create an OpenLayers style class.  Use the
- *     <OpenLayers.Class> constructor instead.
- *
- * Returns:
- * An OpenLayers class
- */
-OpenLayers.Class.create = function() {
-    return function() {
-        if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
-            this.initialize.apply(this, arguments);
-        }
-    };
-};
-
-/**
- * APIFunction: inherit
- * *Deprecated*.  Old method to inherit from one or more OpenLayers style
- *     classes.  Use the <OpenLayers.Class> constructor instead.
- *
- * Parameters:
- * class - One or more classes can be provided as arguments
- *
- * Returns:
- * An object prototype
- */
-OpenLayers.Class.inherit = function (P) {
-    var C = function() {
-       P.call(this);
-    };
-    var newArgs = [C].concat(Array.prototype.slice.call(arguments));
-    OpenLayers.inherit.apply(null, newArgs);
-    return C.prototype;
-};
-
-/**
- * Function: OpenLayers.inherit
- *
- * Parameters:
- * C - {Object} the class that inherits
- * P - {Object} the superclass to inherit from
- *
- * In addition to the mandatory C and P parameters, an arbitrary number of
- * objects can be passed, which will extend C.
- */
-OpenLayers.inherit = function(C, P) {
-   var F = function() {};
-   F.prototype = P.prototype;
-   C.prototype = new F;
-   var i, l, o;
-   for(i=2, l=arguments.length; i<l; i++) {
-       o = arguments[i];
-       if(typeof o === "function") {
-           o = o.prototype;
-       }
-       OpenLayers.Util.extend(C.prototype, o);
-   }
-};
-/* ======================================================================
-    OpenLayers/BaseTypes/Size.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. */
-
-/**
- * Class: OpenLayers.Size
- * Instances of this class represent a width/height pair
- */
-OpenLayers.Size = OpenLayers.Class({
-
-    /**
-     * APIProperty: w
-     * {Number} width
-     */
-    w: 0.0,
-    
-    /**
-     * APIProperty: h
-     * {Number} height
-     */
-    h: 0.0,
-
-
-    /**
-     * Constructor: OpenLayers.Size
-     * Create an instance of OpenLayers.Size
-     *
-     * Parameters:
-     * w - {Number} width
-     * h - {Number} height
-     */
-    initialize: function(w, h) {
-        this.w = parseFloat(w);
-        this.h = parseFloat(h);
-    },
-
-    /**
-     * Method: toString
-     * Return the string representation of a size object
-     *
-     * Returns:
-     * {String} The string representation of OpenLayers.Size object. 
-     * (ex. <i>"w=55,h=66"</i>)
-     */
-    toString:function() {
-        return ("w=" + this.w + ",h=" + this.h);
-    },
-
-    /**
-     * APIMethod: clone
-     * Create a clone of this size object
-     *
-     * Returns:
-     * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
-     * values
-     */
-    clone:function() {
-        return new OpenLayers.Size(this.w, this.h);
-    },
-
-    /**
-     *
-     * APIMethod: equals
-     * Determine where this size is equal to another
-     *
-     * Parameters:
-     * sz - {<OpenLayers.Size>}
-     *
-     * 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.
-     *
-     */
-    equals:function(sz) {
-        var equals = false;
-        if (sz != null) {
-            equals = ((this.w == sz.w && this.h == sz.h) ||
-                      (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
-        }
-        return equals;
-    },
-
-    CLASS_NAME: "OpenLayers.Size"
-});
-/* ======================================================================
     OpenLayers/BaseTypes/Bounds.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/Class.js
  * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
  */
 
 /**
@@ -4055,14 +2024,15 @@
  * 
  * Parameters: 
  * str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
+ * reverseAxisOrder - {Boolean} Does the string use reverse axis order?
  * 
  * Returns:
  * {<OpenLayers.Bounds>} New bounds object built from the 
  *                       passed-in String.
  */
-OpenLayers.Bounds.fromString = function(str) {
+OpenLayers.Bounds.fromString = function(str, reverseAxisOrder) {
     var bounds = str.split(",");
-    return OpenLayers.Bounds.fromArray(bounds);
+    return OpenLayers.Bounds.fromArray(bounds, reverseAxisOrder);
 };
 
 /** 
@@ -4072,12 +2042,18 @@
  * 
  * Parameters:
  * bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
+ * reverseAxisOrder - {Boolean} Does the array use reverse axis order?
  *
  * Returns:
  * {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
  */
-OpenLayers.Bounds.fromArray = function(bbox) {
-    return new OpenLayers.Bounds(parseFloat(bbox[0]),
+OpenLayers.Bounds.fromArray = function(bbox, reverseAxisOrder) {
+    return reverseAxisOrder === true ?
+           new OpenLayers.Bounds(parseFloat(bbox[1]),
+                                 parseFloat(bbox[0]),
+                                 parseFloat(bbox[3]),
+                                 parseFloat(bbox[2])) :
+           new OpenLayers.Bounds(parseFloat(bbox[0]),
                                  parseFloat(bbox[1]),
                                  parseFloat(bbox[2]),
                                  parseFloat(bbox[3]));
@@ -4125,12 +2101,17 @@
     OpenLayers/BaseTypes/Element.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/BaseTypes.js
+ */
+
+/**
  * Namespace: OpenLayers.Element
  */
 OpenLayers.Element = {
@@ -4380,13 +2361,15 @@
     OpenLayers/BaseTypes/LonLat.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/Class.js
  * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
  */
 
 /**
@@ -4574,13 +2557,15 @@
     OpenLayers/BaseTypes/Pixel.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/Class.js
  * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
  */
 
 /**
@@ -4700,7082 +2685,1985 @@
     CLASS_NAME: "OpenLayers.Pixel"
 });
 /* ======================================================================
-    OpenLayers/Icon.js
+    OpenLayers/BaseTypes/Size.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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 
- * 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. 
- * 
+ * @requires OpenLayers/BaseTypes/Class.js
  */
-OpenLayers.Icon = OpenLayers.Class({
-    
-    /** 
-     * Property: url 
-     * {String}  image url
-     */
-    url: null,
-    
-    /** 
-     * Property: size 
-     * {<OpenLayers.Size>} 
-     */
-    size: null,
 
-    /** 
-     * 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) 
-     */
-    calculateOffset: null,    
-    
-    /** 
-     * Property: imageDiv 
-     * {DOMElement} 
-     */
-    imageDiv: null,
-
-    /** 
-     * Property: px 
-     * {<OpenLayers.Pixel>} 
-     */
-    px: null,
-    
-    /** 
-     * Constructor: OpenLayers.Icon
-     * Creates an icon, which is an image tag in a div.  
-     *
-     * url - {String} 
-     * size - {<OpenLayers.Size>} 
-     * offset - {<OpenLayers.Pixel>}
-     * calculateOffset - {Function} 
-     */
-    initialize: function(url, size, offset, calculateOffset) {
-        this.url = url;
-        this.size = (size) ? size : new OpenLayers.Size(20,20);
-        this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2));
-        this.calculateOffset = calculateOffset;
-
-        var id = OpenLayers.Util.createUniqueID("OL_Icon_");
-        this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
-    },
-    
-    /** 
-     * Method: destroy
-     * 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); 
-        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, 
-                                   this.calculateOffset);
-    },
-    
-    /**
-     * Method: setSize
-     * 
-     * Parameters:
-     * size - {<OpenLayers.Size>} 
-     */
-    setSize: function(size) {
-        if (size != null) {
-            this.size = size;
-        }
-        this.draw();
-    },
-    
-    /**
-     * Method: setUrl
-     * 
-     * Parameters:
-     * url - {String} 
-     */
-    setUrl: function(url) {
-        if (url != null) {
-            this.url = url;
-        }
-        this.draw();
-    },
-
-    /** 
-     * Method: draw
-     * Move the div to the given pixel.
-     * 
-     * Parameters:
-     * 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, 
-                                            "absolute");
-        this.moveTo(px);
-        return this.imageDiv;
-    }, 
-
-    /** 
-     * Method: erase
-     * Erase the underlying image element.
-     *
-     */
-    erase: function() {
-        if (this.imageDiv != null && this.imageDiv.parentNode != null) {
-            OpenLayers.Element.remove(this.imageDiv);
-        }
-    }, 
-    
-    /** 
-     * Method: setOpacity
-     * Change the icon's opacity
-     *
-     * Parameters:
-     * opacity - {float} 
-     */
-    setOpacity: function(opacity) {
-        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>} 
-     */
-    moveTo: function (px) {
-        //if no px passed in, use stored location
-        if (px != null) {
-            this.px = px;
-        }
-
-        if (this.imageDiv != null) {
-            if (this.px == null) {
-                this.display(false);
-            } else {
-                if (this.calculateOffset) {
-                    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: function(display) {
-        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));    
-
-        return isDrawn;   
-    },
-
-    CLASS_NAME: "OpenLayers.Icon"
-});
-/* ======================================================================
-    OpenLayers/Popup.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. */
-
-
 /**
- * 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.  
- * 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", 
- *                    new OpenLayers.LonLat(5,40),
- *                    new OpenLayers.Size(200,200),
- *                    "example popup",
- *                    true);
- *       
- * map.addPopup(popup);
- * (end)
+ * Class: OpenLayers.Size
+ * Instances of this class represent a width/height pair
  */
-OpenLayers.Popup = OpenLayers.Class({
+OpenLayers.Size = OpenLayers.Class({
 
-    /** 
-     * Property: events  
-     * {<OpenLayers.Events>} custom event manager 
-     */
-    events: null,
-    
-    /** Property: id
-     * {String} the unique identifier assigned to this popup.
-     */
-    id: "",
-
-    /** 
-     * Property: lonlat 
-     * {<OpenLayers.LonLat>} the position of this popup on the map
-     */
-    lonlat: null,
-
-    /** 
-     * Property: div 
-     * {DOMElement} the div that contains this popup.
-     */
-    div: null,
-
-    /** 
-     * Property: contentSize 
-     * {<OpenLayers.Size>} the width and height of the content.
-     */
-    contentSize: null,    
-
-    /** 
-     * Property: size 
-     * {<OpenLayers.Size>} the width and height of the popup.
-     */
-    size: null,    
-
-    /** 
-     * Property: contentHTML 
-     * {String} An HTML string for this popup to display.
-     */
-    contentHTML: null,
-    
-    /** 
-     * Property: backgroundColor 
-     * {String} the background color used by the popup.
-     */
-    backgroundColor: "",
-    
-    /** 
-     * Property: opacity 
-     * {float} the opacity of this popup (between 0.0 and 1.0)
-     */
-    opacity: "",
-
-    /** 
-     * Property: border 
-     * {String} the border size of the popup.  (eg 2px)
-     */
-    border: "",
-    
-    /** 
-     * Property: contentDiv 
-     * {DOMElement} a reference to the element that holds the content of
-     *              the div.
-     */
-    contentDiv: null,
-    
-    /** 
-     * 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.
-     */
-    autoSize: false,
-
     /**
-     * APIProperty: minSize
-     * {<OpenLayers.Size>} Minimum size allowed for the popup's contents.
+     * APIProperty: w
+     * {Number} width
      */
-    minSize: null,
-
-    /**
-     * APIProperty: maxSize
-     * {<OpenLayers.Size>} Maximum size allowed for the popup's contents.
-     */
-    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 
-     *     padding of the content div inside the popup. This was originally
-     *     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 
-     *     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 
-     *     re-initialized, which is troublesome.
-     *     With this property the hack can be disabled.
-     */
-    disableFirefoxOverflowHack: false,
-
-    /**
-     * 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, 
-     *     instead of an <OpenLayers.Bounds> object.
-     */
-    fixPadding: function() {
-        if (typeof this.padding == "number") {
-            this.padding = new OpenLayers.Bounds(
-                this.padding, this.padding, this.padding, this.padding
-            );
-        }
-    },
-
-    /**
-     * APIProperty: panMapIfOutOfView
-     * {Boolean} When drawn, pan map such that the entire popup is visible in
-     *     the current viewport (if necessary).
-     *     Default is false.
-     */
-    panMapIfOutOfView: false,
+    w: 0.0,
     
     /**
-     * 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.
+     * APIProperty: h
+     * {Number} height
      */
-    keepInMap: false,
+    h: 0.0,
 
-    /**
-     * APIProperty: closeOnMove
-     * {Boolean} When map pans, close the popup.
-     *     Default is false.
-     */
-    closeOnMove: false,
-    
-    /** 
-     * 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: 
-    * id - {String} a unqiue identifier for this popup.  If null is passed
-    *               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   
-    *                                 popup.
-    * closeBox - {Boolean}            Whether to display a close box inside
-    *                                 the popup.
-    * closeBoxCallback - {Function}   Function to be called on closeBox click.
-    */
-    initialize:function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) {
-        if (id == null) {
-            id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
-        }
-
-        this.id = id;
-        this.lonlat = lonlat;
-
-        this.contentSize = (contentSize != null) ? contentSize 
-                                  : new OpenLayers.Size(
-                                                   OpenLayers.Popup.WIDTH,
-                                                   OpenLayers.Popup.HEIGHT);
-        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, 
-                                             null, null, null, "hidden");
-        this.div.className = this.displayClass;
-        
-        var groupDivId = this.id + "_GroupDiv";
-        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(), 
-                                                    null, "relative");
-        this.contentDiv.className = this.contentDisplayClass;
-        this.groupDiv.appendChild(this.contentDiv);
-        this.div.appendChild(this.groupDiv);
-
-        if (closeBox) {
-            this.addCloseBox(closeBoxCallback);
-        } 
-
-        this.registerEvents();
-    },
-
-    /** 
-     * Method: destroy
-     * nullify references to prevent circular references and memory leaks
-     */
-    destroy: function() {
-
-        this.id = null;
-        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); 
-            this.groupDiv.removeChild(this.closeDiv);
-        }
-        this.closeDiv = null;
-        
-        this.div.removeChild(this.groupDiv);
-        this.groupDiv = null;
-
-        if (this.map != null) {
-            this.map.removePopup(this);
-        }
-        this.map = null;
-        this.div = null;
-        
-        this.autoSize = null;
-        this.minSize = null;
-        this.maxSize = null;
-        this.padding = null;
-        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
-    */
-    draw: function(px) {
-        if (px == null) {
-            if ((this.lonlat != null) && (this.map != null)) {
-                px = this.map.getLayerPxFromLonLat(this.lonlat);
-            }
-        }
-
-        // 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() {
-                var style = document.defaultView.getComputedStyle(
-                    this.contentDiv, null
-                );
-                var currentOverflow = style.getPropertyValue("overflow");
-                if (currentOverflow != "hidden") {
-                    this.contentDiv._oldOverflow = currentOverflow;
-                    this.contentDiv.style.overflow = "hidden";
-                }
-            });
-            this.map.events.register("moveend", this, function() {
-                var oldOverflow = this.contentDiv._oldOverflow;
-                if (oldOverflow) {
-                    this.contentDiv.style.overflow = oldOverflow;
-                    this.contentDiv._oldOverflow = null;
-                }
-            });
-        }
-
-        this.moveTo(px);
-        if (!this.autoSize && !this.size) {
-            this.setSize(this.contentSize);
-        }
-        this.setBackgroundColor();
-        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, 
-     * 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);           
-            }    
-        }
-    },
-
     /**
-     * Method: moveTo
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>} the top and left position of the popup div. 
-     */
-    moveTo: function(px) {
-        if ((px != null) && (this.div != null)) {
-            this.div.style.left = px.x + "px";
-            this.div.style.top = px.y + "px";
-        }
-    },
-
-    /**
-     * Method: visible
+     * Constructor: OpenLayers.Size
+     * Create an instance of OpenLayers.Size
      *
-     * Returns:      
-     * {Boolean} Boolean indicating whether or not the popup is visible
-     */
-    visible: function() {
-        return OpenLayers.Element.visible(this.div);
-    },
-
-    /**
-     * Method: toggle
-     * Toggles visibility of the popup.
-     */
-    toggle: function() {
-        if (this.visible()) {
-            this.hide();
-        } else {
-            this.show();
-        }
-    },
-
-    /**
-     * Method: show
-     * Makes the popup visible.
-     */
-    show: function() {
-        OpenLayers.Element.show(this.div);
-
-        if (this.panMapIfOutOfView) {
-            this.panIntoView();
-        }    
-    },
-
-    /**
-     * Method: hide
-     * Makes the popup invisible.
-     */
-    hide: function() {
-        OpenLayers.Element.hide(this.div);
-    },
-
-    /**
-     * Method: setSize
-     * Used to adjust the size of the popup. 
-     *
      * Parameters:
-     * contentSize - {<OpenLayers.Size>} the new size for the popup's 
-     *     contents div (in pixels).
+     * w - {Number} width
+     * h - {Number} height
      */
-    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;
-
-        // take into account the popup's 'padding' property
-        this.fixPadding();
-        wPadding += this.padding.left + this.padding.right;
-        hPadding += this.padding.top + this.padding.bottom;
-
-        // make extra space for the close div
-        if (this.closeDiv) {
-            var closeDivWidth = parseInt(this.closeDiv.style.width);
-            wPadding += closeDivWidth + contentDivPadding.right;
-        }
-
-        //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 
-        // me want to shoot someone, but so it goes.
-        if (OpenLayers.Util.getBrowserName() == "msie") {
-            this.contentSize.w += 
-                contentDivPadding.left + contentDivPadding.right;
-            this.contentSize.h += 
-                contentDivPadding.bottom + contentDivPadding.top;
-        }
-
-        if (this.div != null) {
-            this.div.style.width = this.size.w + "px";
-            this.div.style.height = this.size.h + "px";
-        }
-        if (this.contentDiv != null){
-            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 
-     *     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 + 
-            "</div>";
- 
-        var containerElement = (this.map) ? this.map.layerContainerDiv
-        								  : document.body;
-        var realSize = OpenLayers.Util.getRenderedDimensions(
-            preparedHTML, null,	{
-                displayClass: this.displayClass,
-                containerElement: containerElement
-            }
-        );
-
-        // is the "real" size of the div is safe to display in our map?
-        var safeSize = this.getSafeContentSize(realSize);
-
-        var newSize = null;
-        if (safeSize.equals(realSize)) {
-            //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 
-            // 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.                
-                newSize = safeSize;
-            } else {
-                //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, {
-                        displayClass: this.contentDisplayClass,
-                        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 
-                // adjust for that.
-                //
-                var currentOverflow = OpenLayers.Element.getStyle(
-                    this.contentDiv, "overflow"
-                );
-                if ( (currentOverflow != "hidden") && 
-                     (clippedSize.equals(safeSize)) ) {
-                    var scrollBar = OpenLayers.Util.getScrollbarWidth();
-                    if (fixedSize.w) {
-                        clippedSize.h += scrollBar;
-                    } else {
-                        clippedSize.w += scrollBar;
-                    }
-                }
-                
-                newSize = this.getSafeContentSize(clippedSize);
-            }
-        }                        
-        this.setSize(newSize);     
-    },    
-
-    /**
-     * Method: setBackgroundColor
-     * Sets the background color of the popup.
-     *
-     * Parameters:
-     * color - {String} the background color.  eg "#FFBBBB"
-     */
-    setBackgroundColor:function(color) { 
-        if (color != undefined) {
-            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).   
-     */
-    setOpacity:function(opacity) { 
-        if (opacity != undefined) {
-            this.opacity = opacity; 
-        }
-        
-        if (this.div != null) {
-            // for Mozilla and Safari
-            this.div.style.opacity = this.opacity;
-
-            // 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 
-     */
-    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.
-     *
-     * Parameters:
-     * contentHTML - {String} HTML for the div.
-     */
-    setContentHTML:function(contentHTML) {
-
-        if (contentHTML != null) {
-            this.contentHTML = contentHTML;
-        }
-       
-        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();
-
-                //auto size the popup to its current contents
-                this.updateSize();
-            }
-        }    
-
+    initialize: function(w, h) {
+        this.w = parseFloat(w);
+        this.h = parseFloat(h);
     },
-    
-    /**
-     * 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() { 
 
-        // 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 
-        // 'img' properties in the context.
-        //
-        var onImgLoad = function() {
-            
-            this.popup.updateSize();
-     
-            if ( this.popup.visible() && this.popup.panMapIfOutOfView ) {
-                this.popup.panIntoView();
-            }
-
-            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 
-        // popup accordingly to its new size.
-        var images = this.contentDiv.getElementsByTagName("img");
-        for (var i = 0, len = images.length; i < len; i++) {
-            var img = images[i];
-            if (img.width == 0 || img.height == 0) {
-
-                var context = {
-                    'popup': this,
-                    'img': img
-                };
-
-                //expando this function to the image itself before registering
-                // it. This way we can easily and properly unregister it.
-                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 
-     *     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". 
-        var contentDivPadding = this.getContentDivPadding();
-        var wPadding = contentDivPadding.left + contentDivPadding.right;
-        var hPadding = contentDivPadding.top + contentDivPadding.bottom;
-
-        // take into account the popup's 'padding' property
-        this.fixPadding();
-        wPadding += this.padding.left + this.padding.right;
-        hPadding += this.padding.top + this.padding.bottom;
-
-        if (this.closeDiv) {
-            var closeDivWidth = parseInt(this.closeDiv.style.width);
-            wPadding += closeDivWidth + contentDivPadding.right;
-        }
-
-        // prevent the popup from being smaller than a specified minimal size
-        if (this.minSize) {
-            safeContentSize.w = Math.max(safeContentSize.w, 
-                (this.minSize.w - wPadding));
-            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, 
-                (this.maxSize.w - wPadding));
-            safeContentSize.h = Math.min(safeContentSize.h, 
-                (this.maxSize.h - hPadding));
-        }
-        
-        //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);
-                switch (this.relativePosition) {
-                    case "tr":
-                        extraX = px.x;
-                        extraY = this.map.size.h - px.y;
-                        break;
-                    case "tl":
-                        extraX = this.map.size.w - px.x;
-                        extraY = this.map.size.h - px.y;
-                        break;
-                    case "bl":
-                        extraX = this.map.size.w - px.x;
-                        extraY = px.y;
-                        break;
-                    case "br":
-                        extraX = px.x;
-                        extraY = px.y;
-                        break;
-                    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 - 
-                hPadding - extraY;
-            
-            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. 
+     * Method: toString
+     * Return the string representation of a size object
      *
-     *     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:
-     * {<OpenLayers.Bounds>}
+     * {String} The string representation of OpenLayers.Size object. 
+     * (ex. <i>"w=55,h=66"</i>)
      */
-    getContentDivPadding: function() {
-
-        //use cached value if we have it
-        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        
-            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 = "";
-            }
-        }
-        return contentDivPadding;
+    toString:function() {
+        return ("w=" + this.w + ",h=" + this.h);
     },
 
     /**
-     * Method: addCloseBox
-     * 
-     * Parameters:
-     * callback - {Function} The callback to be called when the close button
-     *     is clicked.
-     */
-    addCloseBox: function(callback) {
-
-        this.closeDiv = OpenLayers.Util.createDiv(
-            this.id + "_close", null, new OpenLayers.Size(17, 17)
-        );
-        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);
-
-        var closePopup = callback || function(e) {
-            this.hide();
-            OpenLayers.Event.stop(e);
-        };
-        OpenLayers.Event.observe(this.closeDiv, "click", 
-                OpenLayers.Function.bindAsEventListener(closePopup, this));
-    },
-
-    /**
-     * Method: panIntoView
-     * 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, 
-        // 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 
-        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 
-        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.
+     * APIMethod: clone
+     * Create a clone of this size object
      *
-     * 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. 
-     *   
-     *   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 
-     *    hyperlinks or drag-selecting text.
-     */
-     registerEvents:function() {
-        this.events = new OpenLayers.Events(this, this.div, null, true);
-
-        this.events.on({
-            "mousedown": this.onmousedown,
-            "mousemove": this.onmousemove,
-            "mouseup": this.onmouseup,
-            "click": this.onclick,
-            "mouseout": this.onmouseout,
-            "dblclick": this.ondblclick,
-            scope: this
-        });
-        
-     },
-
-    /** 
-     * Method: onmousedown 
-     * When mouse goes down within the popup, make a note of
-     *   it locally, and then do not propagate the mousedown 
-     *   (but do so safely so that user can select text inside)
-     * 
-     * Parameters:
-     * evt - {Event} 
-     */
-    onmousedown: function (evt) {
-        this.mousedown = true;
-        OpenLayers.Event.stop(evt, true);
-    },
-
-    /** 
-     * Method: onmousemove
-     * 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} 
-     */
-    onmousemove: function (evt) {
-        if (this.mousedown) {
-            OpenLayers.Event.stop(evt, true);
-        }
-    },
-
-    /** 
-     * 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 
-     *   select text inside
-     * 
-     * Parameters:
-     * evt - {Event} 
-     */
-    onmouseup: function (evt) {
-        if (this.mousedown) {
-            this.mousedown = false;
-            OpenLayers.Event.stop(evt, true);
-        }
-    },
-
-    /**
-     * Method: onclick
-     * Ignore clicks, but allowing default browser handling
-     * 
-     * Parameters:
-     * 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} 
-     */
-    onmouseout: function (evt) {
-        this.mousedown = false;
-    },
-    
-    /** 
-     * Method: ondblclick
-     * Ignore double-clicks, but allowing default browser handling
-     * 
-     * Parameters:
-     * evt - {Event} 
-     */
-    ondblclick: function (evt) {
-        OpenLayers.Event.stop(evt, true);
-    },
-
-    CLASS_NAME: "OpenLayers.Popup"
-});
-
-OpenLayers.Popup.WIDTH = 200;
-OpenLayers.Popup.HEIGHT = 200;
-OpenLayers.Popup.COLOR = "white";
-OpenLayers.Popup.OPACITY = 1;
-OpenLayers.Popup.BORDER = "0px";
-/* ======================================================================
-    OpenLayers/Protocol.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. */
-
-/**
- * Class: OpenLayers.Protocol
- * Abstract vector layer protocol class.  Not to be instantiated directly.  Use
- *     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.
-     */
-    options: null,
-
-    /**
-     * Property: autoDestroy
-     * {Boolean} The creator of the protocol can set autoDestroy to false
-     *      to fully control when the protocol is destroyed. Defaults to
-     *      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.
-     *
-     * Parameters:
-     * options - {Object} Optional object whose properties will be set on the
-     *     instance.
-     */
-    initialize: function(options) {
-        options = options || {};
-        OpenLayers.Util.extend(this, options);
-        this.options = options;
-    },
-
-    /**
-     * 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.
-     */
-    destroy: function() {
-        this.options = null;
-        this.format = null;
-    },
-    
-    /**
-     * APIMethod: read
-     * Construct a request for reading new features.
-     *
-     * Parameters:
-     * options - {Object} Optional object for configuring the request.
-     *
      * Returns:
-     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
-     * object, the same object will be passed to the callback function passed
-     * if one exists in the options object.
+     * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
+     * values
      */
-    read: function(options) {
-        options = options || {};
-        options.filter = this.mergeWithDefaultFilter(options.filter);
+    clone:function() {
+        return new OpenLayers.Size(this.w, this.h);
     },
-    
-    
-    /**
-     * 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.
-     *
-     * Returns:
-     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
-     * object, the same object will be passed to the callback function passed
-     * if one exists in the options object.
-     */
-    create: function() {
-    },
-    
-    /**
-     * APIMethod: update
-     * Construct a request updating modified features.
-     *
-     * Parameters:
-     * features - {Array({<OpenLayers.Feature.Vector>})} or
-     *            {<OpenLayers.Feature.Vector>}
-     * options - {Object} Optional object for configuring the request.
-     *
-     * Returns:
-     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
-     * object, the same object will be passed to the callback function passed
-     * if one exists in the options object.
-     */
-    update: function() {
-    },
-    
-    /**
-     * APIMethod: delete
-     * Construct a request deleting a removed feature.
-     *
-     * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>}
-     * options - {Object} Optional object for configuring the request.
-     *
-     * Returns:
-     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
-     * object, the same object will be passed to the callback function passed
-     * if one exists in the options object.
-     */
-    "delete": function() {
-    },
 
     /**
-     * APIMethod: commit
-     * Go over the features and for each take action
-     * based on the feature state. Possible actions are create,
-     * update and delete.
      *
-     * Parameters:
-     * features - {Array({<OpenLayers.Feature.Vector>})}
-     * options - {Object} Object whose possible keys are "create", "update",
-     *      "delete", "callback" and "scope", the values referenced by the
-     *      first three are objects as passed to the "create", "update", and
-     *      "delete" methods, the value referenced by the "callback" key is
-     *      a function which is called when the commit operation is complete
-     *      using the scope referenced by the "scope" key.
+     * APIMethod: equals
+     * Determine where this size is equal to another
      *
-     * Returns:
-     * {Array({<OpenLayers.Protocol.Response>})} An array of
-     * <OpenLayers.Protocol.Response> objects.
-     */
-    commit: function() {
-    },
-
-    /**
-     * Method: abort
-     * Abort an ongoing request.
-     *
      * Parameters:
-     * response - {<OpenLayers.Protocol.Response>}
-     */
-    abort: function(response) {
-    },
-   
-    /**
-     * Method: createCallback
-     * Returns a function that applies the given public method with resp and
-     *     options arguments.
+     * sz - {<OpenLayers.Size>}
      *
-     * 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" 
-});
-
-/**
- * Class: OpenLayers.Protocol.Response
- * Protocols return Response objects to their users.
- */
-OpenLayers.Protocol.Response = OpenLayers.Class({
-    /**
-     * Property: code
-     * {Number} - OpenLayers.Protocol.Response.SUCCESS or
-     *            OpenLayers.Protocol.Response.FAILURE
-     */
-    code: null,
-
-    /**
-     * Property: requestType
-     * {String} The type of request this response corresponds to. Either
-     *      "create", "read", "update" or "delete".
-     */
-    requestType: null,
-
-    /**
-     * Property: last
-     * {Boolean} - true if this is the last response expected in a commit,
-     * false otherwise, defaults to true.
-     */
-    last: true,
-
-    /**
-     * Property: features
-     * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>}
-     * The features returned in the response by the server.
-     */
-    features: null,
-
-    /**
-     * Property: reqFeatures
-     * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>}
-     * The features provided by the user and placed in the request by the
-     *      protocol.
-     */
-    reqFeatures: null,
-
-    /**
-     * Property: priv
-     */
-    priv: null,
-
-    /**
-     * Constructor: OpenLayers.Protocol.Response
+     * 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.
      *
-     * Parameters:
-     * options - {Object} Optional object whose properties will be set on the
-     *     instance.
      */
-    initialize: function(options) {
-        OpenLayers.Util.extend(this, options);
+    equals:function(sz) {
+        var equals = false;
+        if (sz != null) {
+            equals = ((this.w == sz.w && this.h == sz.h) ||
+                      (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
+        }
+        return equals;
     },
 
-    /**
-     * Method: success
-     *
-     * Returns:
-     * {Boolean} - true on success, false otherwise
-     */
-    success: function() {
-        return this.code > 0;
-    },
-
-    CLASS_NAME: "OpenLayers.Protocol.Response"
+    CLASS_NAME: "OpenLayers.Size"
 });
-
-OpenLayers.Protocol.Response.SUCCESS = 1;
-OpenLayers.Protocol.Response.FAILURE = 0;
 /* ======================================================================
-    OpenLayers/Renderer.js
+    OpenLayers/Util.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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 
- * 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. 
- * 
- * A note to the user that all subclasses should use getResolution() instead
- *  of directly accessing this.resolution in order to correctly use the 
- *  cacheing system.
- *
+ * @requires OpenLayers/BaseTypes.js
+ * @requires OpenLayers/BaseTypes/Bounds.js
+ * @requires OpenLayers/BaseTypes/Element.js
+ * @requires OpenLayers/BaseTypes/LonLat.js
+ * @requires OpenLayers/BaseTypes/Pixel.js
+ * @requires OpenLayers/BaseTypes/Size.js
+ * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
  */
-OpenLayers.Renderer = OpenLayers.Class({
 
-    /** 
-     * Property: container
-     * {DOMElement} 
-     */
-    container: null,
-    
-    /**
-     * Property: root
-     * {DOMElement}
-     */
-    root: null,
-
-    /** 
-     * Property: extent
-     * {<OpenLayers.Bounds>}
-     */
-    extent: null,
-
-    /**
-     * 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 
-     *     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. 
-     */  
-    locked: false,
-    
-    /** 
-     * Property: size
-     * {<OpenLayers.Size>} 
-     */
-    size: null,
-    
-    /**
-     * Property: resolution
-     * {Float} cache of current map resolution
-     */
-    resolution: null,
-    
-    /**
-     * Property: map  
-     * {<OpenLayers.Map>} Reference to the map -- this is set in Vector's setMap()
-     */
-    map: null,
-    
-    /**
-     * Constructor: OpenLayers.Renderer 
-     *
-     * Parameters:
-     * 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
-     */
-    destroy: function() {
-        this.container = null;
-        this.extent = null;
-        this.size =  null;
-        this.resolution = null;
-        this.map = null;
-    },
-
-    /**
-     * 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 
-     * 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
-     * getResolution() request.
-     *
-     * Parameters:
-     * extent - {<OpenLayers.Bounds>}
-     * resolutionChanged - {Boolean}
-     */
-    setExtent: function(extent, resolutionChanged) {
-        this.extent = extent.clone();
-        if (resolutionChanged) {
-            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 
-     * next it is needed.
-     *
-     * Parameters:
-     * 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
-     */
-    getResolution: function() {
-        this.resolution = this.resolution || this.map.getResolution();
-        return this.resolution;
-    },
-    
-    /**
-     * Method: drawFeature
-     * Draw the feature.  The optional style argument can be used
-     * to override the feature's own style.  This method should only
-     * be called from layer.drawFeature().
-     *
-     * Parameters:
-     * 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
-     */
-    drawFeature: function(feature, style) {
-        if(style == null) {
-            style = feature.style;
-        }
-        if (feature.geometry) {
-            var bounds = feature.geometry.getBounds();
-            if(bounds) {
-                if (!bounds.intersectsBounds(this.extent)) {
-                    style = {display: "none"};
-                }
-                var rendered = this.drawGeometry(feature.geometry, style, feature.id);
-                if(style.display != "none" && style.label && rendered !== false) {
-                    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);
-                }
-                return rendered;
-            }
-        }
-    },
-
-
-    /** 
-     * 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>} 
-     */
-    drawGeometry: function(geometry, style, featureId) {},
-        
-    /**
-     * Method: drawText
-     * Function for drawing text labels.
-     * This method is only called by the renderer itself.
-     * 
-     * Parameters: 
-     * featureId - {String}
-     * style -
-     * location - {<OpenLayers.Geometry.Point>}
-     */
-    drawText: function(featureId, style, location) {},
-
-    /**
-     * Method: removeText
-     * Function for removing text labels.
-     * This method is only called by the renderer itself.
-     * 
-     * 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.  
-     * How this happens is specific to the renderer.  This should be
-     * called from layer.getFeatureFromEvent().
-     * Virtual function.
-     * 
-     * Parameters:
-     * evt - {<OpenLayers.Event>} 
-     *
-     * Returns:
-     * {String} A feature id or null.
-     */
-    getFeatureIdFromEvent: function(evt) {},
-    
-    /**
-     * Method: eraseFeatures 
-     * This is called by the layer to erase features
-     * 
-     * Parameters:
-     * features - {Array(<OpenLayers.Feature.Vector>)} 
-     */
-    eraseFeatures: function(features) {
-        if(!(features instanceof Array)) {
-            features = [features];
-        }
-        for(var i=0, len=features.length; i<len; ++i) {
-            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>} 
-     * featureId - {String}
-     */
-    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
-     */
-    moveRoot: function(renderer) {},
-
-    /**
-     * 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.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)
+ * Namespace: Util
  */
-OpenLayers.Renderer.defaultSymbolizer = {
-    fillColor: "#000000",
-    strokeColor: "#000000",
-    strokeWidth: 2,
-    fillOpacity: 1,
-    strokeOpacity: 1,
-    pointRadius: 0
-};
-    
-/* ======================================================================
-    OpenLayers/Strategy.js
-   ====================================================================== */
+OpenLayers.Util = OpenLayers.Util || {};
 
-/* 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.Strategy
- * Abstract vector layer strategy class.  Not to be instantiated directly.  Use
- *     one of the strategy subclasses instead.
+/** 
+ * Function: getElement
+ * This is the old $() from prototype
  */
-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,
+OpenLayers.Util.getElement = function() {
+    var elements = [];
 
-    /** 
-     * Property: active 
-     * {Boolean} The control is active.
-     */
-    active: null,
-
-    /**
-     * Property: autoActivate
-     * {Boolean} The creator of the strategy can set autoActivate to false
-     *      to fully control when the protocol is activated and deactivated.
-     *      Defaults to true.
-     */
-    autoActivate: true,
-
-    /**
-     * Property: autoDestroy
-     * {Boolean} The creator of the strategy can set autoDestroy to false
-     *      to fully control when the strategy is destroyed. Defaults to
-     *      true.
-     */
-    autoDestroy: true,
-
-    /**
-     * Constructor: OpenLayers.Strategy
-     * Abstract class for vector strategies.  Create instances of a subclass.
-     *
-     * Parameters:
-     * options - {Object} Optional object whose properties will be set on the
-     *     instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Util.extend(this, options);
-        this.options = options;
-        // set the active property here, so that user cannot override it
-        this.active = false;
-    },
-    
-    /**
-     * APIMethod: destroy
-     * Clean up the strategy.
-     */
-    destroy: function() {
-        this.deactivate();
-        this.layer = null;
-        this.options = null;
-    },
-
-    /**
-     * Method: setLayer
-     * Called to set the <layer> property.
-     *
-     * Parameters:
-     * {<OpenLayers.Layer.Vector>}
-     */
-    setLayer: function(layer) {
-        this.layer = layer;
-    },
-    
-    /**
-     * Method: activate
-     * Activate the strategy.  Register any listeners, do appropriate setup.
-     *
-     * Returns:
-     * {Boolean} True if the strategy was successfully activated or false if
-     *      the strategy was already active.
-     */
-    activate: function() {
-        if (!this.active) {
-            this.active = true;
-            return true;
+    for (var i=0, len=arguments.length; i<len; i++) {
+        var element = arguments[i];
+        if (typeof element == 'string') {
+            element = document.getElementById(element);
         }
-        return false;
-    },
-    
-    /**
-     * Method: deactivate
-     * Deactivate the strategy.  Unregister any listeners, do appropriate
-     *     tear-down.
-     *
-     * Returns:
-     * {Boolean} True if the strategy was successfully deactivated or false if
-     *      the strategy was already inactive.
-     */
-    deactivate: function() {
-        if (this.active) {
-            this.active = false;
-            return true;
+        if (arguments.length == 1) {
+            return element;
         }
-        return false;
-    },
-   
-    CLASS_NAME: "OpenLayers.Strategy" 
-});
-/* ======================================================================
-    OpenLayers/Symbolizer.js
-   ====================================================================== */
+        elements.push(element);
+    }
+    return elements;
+};
 
-/* 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.
+ * Function: isElement
+ * A cross-browser implementation of "e instanceof Element".
+ *
+ * Parameters:
+ * o - {Object} The object to test.
+ *
+ * Returns:
+ * {Boolean}
  */
-OpenLayers.Symbolizer = OpenLayers.Class({
-    
+OpenLayers.Util.isElement = function(o) {
+    return !!(o && o.nodeType === 1);
+};
 
-    /**
-     * 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-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/Console.js
+/** 
+ * Maintain existing definition of $.
  */
+if(typeof window.$  === "undefined") {
+    window.$ = OpenLayers.Util.getElement;
+}
 
-/**
- * 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 
- * 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());
- * > map.addControl(new OpenLayers.Control.MouseToolbar());
- * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
- * > map.addControl(new OpenLayers.Control.Permalink());
- * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
- * > map.addControl(new OpenLayers.Control.MousePosition());
- * > map.addControl(new OpenLayers.Control.OverviewMap());
- * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
+/** 
+ * Function: removeItem
+ * Remove an object from an array. Iterates through the array
+ *     to find the item, then removes it.
  *
- * 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 
- * example:
- *
- * > var control = new OpenLayers.Control();
- * > OpenLayers.Util.extend(control, {
- * >     draw: function () {
- * >         // this Handler.Box will intercept the shift-mousedown
- * >         // before Control.MouseDefault gets to see it
- * >         this.box = new OpenLayers.Handler.Box( control, 
- * >             {"done": this.notice},
- * >             {keyMask: OpenLayers.Handler.MOD_SHIFT});
- * >         this.box.activate();
- * >     },
- * >
- * >     notice: function (bounds) {
- * >         OpenLayers.Console.userError(bounds);
- * >     }
- * > }); 
- * > map.addControl(control);
+ * Parameters:
+ * array - {Array}
+ * item - {Object}
  * 
+ * Return
+ * {Array} A reference to the array
  */
-OpenLayers.Control = OpenLayers.Class({
-
-    /** 
-     * Property: id 
-     * {String} 
-     */
-    id: null,
-    
-    /** 
-     * Property: map 
-     * {<OpenLayers.Map>} this gets set in the addControl() function in
-     * OpenLayers.Map 
-     */
-    map: null,
-
-    /** 
-     * Property: div 
-     * {DOMElement} 
-     */
-    div: null,
-
-    /** 
-     * 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, 
-
-    /** 
-     * 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,  
-
-    /** 
-     * Property: displayClass 
-     * {string}  This property is used for CSS related to the drawing of the
-     * Control. 
-     */
-    displayClass: "",
-    
-    /**
-    * Property: title  
-    * {string}  This property is used for showing a tooltip over the  
-    * Control.  
-    */ 
-    title: "",
-
-    /**
-     * 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 
-     * {<OpenLayers.Handler>} null
-     */
-    handler: null,
-
-    /**
-     * APIProperty: eventListeners
-     * {Object} If set as an option at construction, the eventListeners
-     *     object will be registered with <OpenLayers.Events.on>.  Object
-     *     structure must be a listeners object as shown in the example for
-     *     the events.on method.
-     */
-    eventListeners: null,
-
-    /** 
-     * Property: events
-     * {<OpenLayers.Events>} Events instance for triggering control specific
-     *     events.
-     */
-    events: null,
-
-    /**
-     * Constant: EVENT_TYPES
-     * {Array(String)} Supported application event types.  Register a listener
-     *     for a particular event with the following syntax:
-     * (code)
-     * control.events.register(type, obj, listener);
-     * (end)
-     *
-     * Listeners will be called with a reference to an event object.  The
-     *     properties of this event depends on exactly what happened.
-     *
-     * All event objects have at least the following properties:
-     * object - {Object} A reference to control.events.object (a reference
-     *      to the control).
-     * element - {DOMElement} A reference to control.events.element (which
-     *      will be null unless documented otherwise).
-     *
-     * Supported map event types:
-     * activate - Triggered when activated.
-     * deactivate - Triggered when deactivated.
-     */
-    EVENT_TYPES: ["activate", "deactivate"],
-
-    /**
-     * 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} 
-     */
-    initialize: function (options) {
-        // We do this before the extend so that instances can override
-        // className in options.
-        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);
+OpenLayers.Util.removeItem = function(array, item) {
+    for(var i = array.length - 1; i >= 0; i--) {
+        if(array[i] == item) {
+            array.splice(i,1);
+            //break;more than once??
         }
-        if (this.id == null) {
-            this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
-        }
-    },
+    }
+    return array;
+};
 
-    /**
-     * Method: destroy
-     * The destroy method is used to perform any clean up before the control
-     * is dereferenced.  Typically this is where event listeners are removed
-     * to prevent memory leaks.
-     */
-    destroy: function () {
-        if(this.events) {
-            if(this.eventListeners) {
-                this.events.un(this.eventListeners);
-            }
-            this.events.destroy();
-            this.events = null;
-        }
-        this.eventListeners = null;
-
-        // eliminate circular references
-        if (this.handler) {
-            this.handler.destroy();
-            this.handler = null;
-        }
-        if(this.handlers) {
-            for(var key in this.handlers) {
-                if(this.handlers.hasOwnProperty(key) &&
-                   typeof this.handlers[key].destroy == "function") {
-                    this.handlers[key].destroy();
-                }
-            }
-            this.handlers = null;
-        }
-        if (this.map) {
-            this.map.removeControl(this);
-            this.map = null;
-        }
-    },
-
-    /** 
-     * 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. 
-     *
-     * Parameters:
-     * map - {<OpenLayers.Map>} 
-     */
-    setMap: function(map) {
-        this.map = map;
-        if (this.handler) {
-            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. 
-     *
-     * Parameters:
-     * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
-     *      or null.
-     *
-     * Returns:
-     * {DOMElement} A reference to the DIV DOMElement containing the control
-     */
-    draw: function (px) {
-        if (this.div == null) {
-            this.div = OpenLayers.Util.createDiv(this.id);
-            this.div.className = this.displayClass;
-            if (!this.allowSelection) {
-                this.div.className += " olControlNoSelect";
-                this.div.setAttribute("unselectable", "on", 0);
-                this.div.onselectstart = OpenLayers.Function.False; 
-            }    
-            if (this.title != "") {
-                this.div.title = this.title;
-            }
-        }
-        if (px != null) {
-            this.position = px.clone();
-        }
-        this.moveTo(this.position);
-        return this.div;
-    },
-
-    /**
-     * Method: moveTo
-     * Sets the left and top style attributes to the passed in pixel 
-     * coordinates.
-     *
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     */
-    moveTo: function (px) {
-        if ((px != null) && (this.div != null)) {
-            this.div.style.left = px.x + "px";
-            this.div.style.top = px.y + "px";
-        }
-    },
-
-    /**
-     * Method: activate
-     * 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.
-     */
-    activate: function () {
-        if (this.active) {
-            return false;
-        }
-        if (this.handler) {
-            this.handler.activate();
-        }
-        this.active = true;
-        if(this.map) {
-            OpenLayers.Element.addClass(
-                this.map.viewPortDiv,
-                this.displayClass.replace(/ /g, "") + "Active"
-            );
-        }
-        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.
-     */
-    deactivate: function () {
-        if (this.active) {
-            if (this.handler) {
-                this.handler.deactivate();
-            }
-            this.active = false;
-            if(this.map) {
-                OpenLayers.Element.removeClass(
-                    this.map.viewPortDiv,
-                    this.displayClass.replace(/ /g, "") + "Active"
-                );
-            }
-            this.events.triggerEvent("deactivate");
-            return true;
-        }
-        return false;
-    },
-
-    CLASS_NAME: "OpenLayers.Control"
-});
-
 /**
- * Constant: OpenLayers.Control.TYPE_BUTTON
+ * Function: clearArray
+ * *Deprecated*. This function will disappear in 3.0.
+ * Please use "array.length = 0" instead.
+ * 
+ * Parameters:
+ * array - {Array}
  */
-OpenLayers.Control.TYPE_BUTTON = 1;
+OpenLayers.Util.clearArray = function(array) {
+    OpenLayers.Console.warn(
+        OpenLayers.i18n(
+            "methodDeprecated", {'newMethod': 'array = []'}
+        )
+    );
+    array.length = 0;
+};
 
-/**
- * Constant: OpenLayers.Control.TYPE_TOGGLE
+/** 
+ * Function: indexOf
+ * Seems to exist already in FF, but not in MOZ.
+ * 
+ * Parameters:
+ * array - {Array}
+ * obj - {Object}
+ * 
+ * Returns:
+ * {Integer} The index at, which the first object was found in the array.
+ *           If not found, returns -1.
  */
-OpenLayers.Control.TYPE_TOGGLE = 2;
+OpenLayers.Util.indexOf = function(array, obj) {
+    // 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;   
+    }
+};
 
-/**
- * Constant: OpenLayers.Control.TYPE_TOOL
- */
-OpenLayers.Control.TYPE_TOOL   = 3;
-/* ======================================================================
-    OpenLayers/Lang.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/Console.js
+ * Function: modifyDOMElement
+ * 
+ * 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, 
+ *                           relative, etc.
+ * border - {String}         The style.border attribute.  eg:
+ *                           solid black 2px
+ * overflow - {String}       The style.overview attribute.  
+ * opacity - {Float}         Fractional value (0.0 - 1.0)
  */
+OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, 
+                                            border, overflow, opacity) {
 
-/**
- * Namespace: OpenLayers.Lang
- * Internationalization namespace.  Contains dictionaries in various languages
- *     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
-     *     retrieve it.
-     */
-    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.
-     *
-     * Returns:
-     * The current language code.
-     */
-    getCode: function() {
-        if(!OpenLayers.Lang.code) {
-            OpenLayers.Lang.setCode();
-        }
-        return OpenLayers.Lang.code;
-    },
-    
-    /**
-     * APIFunction: setCode
-     * Set the language code for string translation.  This code is used by
-     *     the <OpenLayers.Lang.translate> method.
-     *
-     * Parameters-
-     * code - {String} These codes follow the IETF recommendations at
-     *     http://www.ietf.org/rfc/rfc3066.txt.  If no value is set, the
-     *     browser's language setting will be tested.  If no <OpenLayers.Lang>
-     *     dictionary exists for the code, the <OpenLayers.String.defaultLang>
-     *     will be used.
-     */
-    setCode: function(code) {
-        var lang;
-        if(!code) {
-            code = (OpenLayers.Util.getBrowserName() == "msie") ?
-                navigator.userLanguage : navigator.language;
-        }
-        var parts = code.split('-');
-        parts[0] = parts[0].toLowerCase();
-        if(typeof OpenLayers.Lang[parts[0]] == "object") {
-            lang = parts[0];
-        }
-
-        // check for regional extensions
-        if(parts[1]) {
-            var testLang = parts[0] + '-' + parts[1].toUpperCase();
-            if(typeof OpenLayers.Lang[testLang] == "object") {
-                lang = testLang;
-            }
-        }
-        if(!lang) {
-            OpenLayers.Console.warn(
-                'Failed to find OpenLayers.Lang.' + parts.join("-") +
-                ' dictionary, falling back to default language'
-            );
-            lang = OpenLayers.Lang.defaultCode;
-        }
-        
-        OpenLayers.Lang.code = lang;
-    },
-
-    /**
-     * APIMethod: translate
-     * Looks up a key from a dictionary based on the current language string.
-     *     The value of <getCode> will be used to determine the appropriate
-     *     dictionary.  Dictionaries are stored in <OpenLayers.Lang>.
-     *
-     * Parameters:
-     * 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.
-     */
-    translate: function(key, context) {
-        var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
-        var message = dictionary[key];
-        if(!message) {
-            // Message not found, fall back to message key
-            message = key;
-        }
-        if(context) {
-            message = OpenLayers.String.format(message, context);
-        }
-        return message;
+    if (id) {
+        element.id = id;
     }
-    
+    if (px) {
+        element.style.left = px.x + "px";
+        element.style.top = px.y + "px";
+    }
+    if (sz) {
+        element.style.width = sz.w + "px";
+        element.style.height = sz.h + "px";
+    }
+    if (position) {
+        element.style.position = position;
+    }
+    if (border) {
+        element.style.border = border;
+    }
+    if (overflow) {
+        element.style.overflow = overflow;
+    }
+    if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) {
+        element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
+        element.style.opacity = opacity;
+    } else if (parseFloat(opacity) == 1.0) {
+        element.style.filter = '';
+        element.style.opacity = '';
+    }
 };
 
-
-/**
- * APIMethod: OpenLayers.i18n
- * Alias for <OpenLayers.Lang.translate>.  Looks up a key from a dictionary
- *     based on the current language string. The value of
- *     <OpenLayers.Lang.getCode> will be used to determine the appropriate
- *     dictionary.  Dictionaries are stored in <OpenLayers.Lang>.
- *
+/** 
+ * 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:
- * key - {String} The key for an i18n string value in the dictionary.
- * context - {Object} Optional context to be used with
- *     <OpenLayers.String.format>.
+ * id - {String} An identifier for this element.  If no id is
+ *               passed an identifier will be created 
+ *               automatically.
+ * 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 
+ *                   background image.
+ * position - {String} The style.position value. eg: absolute,
+ *                     relative etc.
+ * 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:
- * {String} A internationalized string.
+ * Returns: 
+ * {DOMElement} A DOM Div created with the specified attributes.
  */
-OpenLayers.i18n = OpenLayers.Lang.translate;
-/* ======================================================================
-    OpenLayers/Popup/Anchored.js
-   ====================================================================== */
+OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, 
+                                     border, overflow, opacity) {
 
-/* 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 dom = document.createElement('div');
 
+    if (imgURL) {
+        dom.style.backgroundImage = 'url(' + imgURL + ')';
+    }
 
-/**
- * @requires OpenLayers/Popup.js
- */
+    //set generic properties
+    if (!id) {
+        id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
+    }
+    if (!position) {
+        position = "absolute";
+    }
+    OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, 
+                                     border, overflow, opacity);
 
+    return dom;
+};
+
 /**
- * Class: OpenLayers.Popup.Anchored
+ * 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.
+ * px - {<OpenLayers.Pixel>} The left and top positions.
+ * sz - {<OpenLayers.Size>} The style.width and style.height values.
+ * imgURL - {String} The url to use as the image source.
+ * position - {String} The style.position value.
+ * border - {String} The border to place around the image.
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ * delayDisplay - {Boolean} If true waits until the image has been
+ *                          loaded.
  * 
- * Inherits from:
- *  - <OpenLayers.Popup>
+ * Returns:
+ * {DOMElement} A DOM Image created with the specified attributes.
  */
-OpenLayers.Popup.Anchored = 
-  OpenLayers.Class(OpenLayers.Popup, {
+OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
+                                       opacity, delayDisplay) {
 
-    /** 
-     * 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, 
-     *     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.
-     */
-    keepInMap: true,
+    var image = document.createElement("img");
 
-    /**
-     * Parameter: anchor
-     * {Object} Object to which we'll anchor the popup. Must expose a 
-     *     'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>).
-     */
-    anchor: null,
+    //set generic properties
+    if (!id) {
+        id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
+    }
+    if (!position) {
+        position = "relative";
+    }
+    OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, 
+                                     border, null, opacity);
 
-    /** 
-    * 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> 
-    *     and 'offset' <OpenLayers.Pixel> (generally an <OpenLayers.Icon>).
-    * closeBox - {Boolean}
-    * closeBoxCallback - {Function} Function to be called on closeBox click.
-    */
-    initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox,
-                        closeBoxCallback) {
-        var newArguments = [
-            id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback
-        ];
-        OpenLayers.Popup.prototype.initialize.apply(this, newArguments);
-
-        this.anchor = (anchor != null) ? anchor 
-                                       : { size: new OpenLayers.Size(0,0),
-                                           offset: new OpenLayers.Pixel(0,0)};
-    },
-
-    /**
-     * APIMethod: destroy
-     */
-    destroy: function() {
-        this.anchor = null;
-        this.relativePosition = null;
+    if(delayDisplay) {
+        image.style.display = "none";
+        OpenLayers.Event.observe(image, "load", 
+            OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
+        OpenLayers.Event.observe(image, "error", 
+            OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
         
-        OpenLayers.Popup.prototype.destroy.apply(this, arguments);        
-    },
-
-    /**
-     * APIMethod: show
-     * 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)
-     */
-    show: function() {
-        this.updatePosition();
-        OpenLayers.Popup.prototype.show.apply(this, arguments);
-    },
-
-    /**
-     * 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 
-     *     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);        
-        OpenLayers.Popup.prototype.moveTo.apply(this, newArguments);
-        
-        //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();
-        }
-    },
-
-    /**
-     * APIMethod: setSize
-     * 
-     * Parameters:
-     * contentSize - {<OpenLayers.Size>} the new size for the popup's 
-     *     contents div (in pixels).
-     */
-    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 extent = this.map.getExtent();
-        var quadrant = extent.determineQuadrant(lonlat);
-        
-        return OpenLayers.Bounds.oppositeQuadrant(quadrant);
-    }, 
+    //set special properties
+    image.style.alt = id;
+    image.galleryImg = "no";
+    if (imgURL) {
+        image.src = imgURL;
+    }
 
-    /**
-     * 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 
-     *     here, since the popup looks exactly the same in all four positions.
-     *     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) : this.anchor.size.h;
-        
-        var left = (this.relativePosition.charAt(1) == 'l');
-        newPx.x += (left) ? -(size.w + this.anchor.size.w) : this.anchor.size.w;
-
-        return newPx;   
-    },
-
-    CLASS_NAME: "OpenLayers.Popup.Anchored"
-});
-/* ======================================================================
-    OpenLayers/Protocol/WFS.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
- */
-
-/**
- * Function: OpenLayers.Protocol.WFS
- * Used to create a versioned WFS protocol.  Default version is 1.0.0.
- *
- * Returns:
- * {<OpenLayers.Protocol>} A WFS protocol of the given version.
- */
-OpenLayers.Protocol.WFS = function(options) {
-    options = OpenLayers.Util.applyDefaults(
-        options, OpenLayers.Protocol.WFS.DEFAULTS
-    );
-    var cls = OpenLayers.Protocol.WFS["v"+options.version.replace(/\./g, "_")];
-    if(!cls) {
-        throw "Unsupported WFS version: " + options.version;
-    }
-    return new cls(options);
+    return image;
 };
 
 /**
- * Function: OpenLayers.Protocol.WFS.fromWMSLayer
- * Convenience function to create a WFS protocol from a WMS layer.  This makes
- *     the assumption that a WFS requests can be issued at the same URL as
- *     WMS requests and that a WFS featureType exists with the same name as the
- *     WMS layer.
- *     
- * This function is designed to auto-configure <url>, <featureType>,
- *     <featurePrefix> and <srsName> for WFS <version> 1.1.0. Note that
- *     srsName matching with the WMS layer will not work with WFS 1.0.0..
+ * Function: setOpacity
+ * *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:
+ *     http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
+ *
  * Parameters:
- * layer - {<OpenLayers.Layer.WMS>} WMS layer that has a matching WFS
- *     FeatureType at the same server url with the same typename.
- * options - {Object} Default properties to be set on the protocol.
- *
+ * element - {DOMElement} Set the opacity on this DOM element
+ * opacity - {Float} Opacity value (0.0 - 1.0)
  */
-OpenLayers.Protocol.WFS.fromWMSLayer = function(layer, options) {
-    var typeName, featurePrefix;
-    var param = layer.params["LAYERS"];
-    var parts = (param instanceof Array ? param[0] : param).split(":");
-    if(parts.length > 1) {
-        featurePrefix = parts[0];
-    }
-    typeName = parts.pop();
-    var protocolOptions = {
-        url: layer.url,
-        featureType: typeName,
-        featurePrefix: featurePrefix,
-        srsName: layer.projection && layer.projection.getCode() ||
-                 layer.map && layer.map.getProjectionObject().getCode(),
-        version: "1.1.0"
-    };
-    return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(
-        options, protocolOptions
-    ));
+OpenLayers.Util.setOpacity = function(element, opacity) {
+    OpenLayers.Util.modifyDOMElement(element, null, null, null,
+                                     null, null, null, opacity);
 };
 
 /**
- * Constant: OpenLayers.Protocol.WFS.DEFAULTS
+ * Function: onImageLoad
+ * Bound to image load events.  For all images created with <createImage> or
+ *     <createAlphaImageDiv>, this function will be bound to the load event.
  */
-OpenLayers.Protocol.WFS.DEFAULTS = {
-    "version": "1.0.0"
+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' 
+    // 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 
+    // 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.display = "";  
+    }
+    OpenLayers.Element.removeClass(this, "olImageLoadError");
 };
-/* ======================================================================
-    OpenLayers/Renderer/Canvas.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/Renderer.js
+ * Property: IMAGE_RELOAD_ATTEMPTS
+ * {Integer} How many times should we try to reload an image before giving up?
+ *           Default is 0
  */
+OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
 
 /**
- * Class: OpenLayers.Renderer.Canvas 
- * A renderer based on the 2D 'canvas' drawing element.element
- * 
- * Inherits:
- *  - <OpenLayers.Renderer>
+ * Function: onImageLoadError 
  */
-OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
-
-    /**
-     * Property: canvas
-     * {Canvas} The canvas context object.
-     */
-    canvas: null, 
-    
-    /**
-     * Property: features
-     * {Object} Internal object of feature/style pairs for use in redrawing the layer.
-     */
-    features: null, 
-   
-    /**
-     * Constructor: OpenLayers.Renderer.Canvas
-     *
-     * Parameters:
-     * containerID - {<String>} 
-     */
-    initialize: function(containerID) {
-        OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
-        this.root = document.createElement("canvas");
-        this.container.appendChild(this.root);
-        this.canvas = this.root.getContext("2d");
-        this.features = {};
-    },
-    
-    /** 
-     * 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.   
-     * 
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * featureId - {String}
-     */
-    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: setSize
-     * Sets the size of the drawing surface.
-     *
-     * Once the size is updated, redraw the canvas.
-     *
-     * Parameters:
-     * size - {<OpenLayers.Size>} 
-     */
-    setSize: function(size) {
-        this.size = size.clone();
-        this.root.style.width = size.w + "px";
-        this.root.style.height = size.h + "px";
-        this.root.width = size.w;
-        this.root.height = size.h;
-        this.resolution = null;
-    },
-    
-    /**
-     * Method: drawFeature
-     * Draw the feature. Stores the feature in the features list,
-     * then redraws the layer. 
-     *
-     * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>} 
-     * style - {<Object>} 
-     */
-    drawFeature: function(feature, style) {
-        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. 
-     *
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>} 
-     * style - {Object} 
-     */
-    drawGeometry: function(geometry, style) {
-        var className = geometry.CLASS_NAME;
-        if ((className == "OpenLayers.Geometry.Collection") ||
-            (className == "OpenLayers.Geometry.MultiPoint") ||
-            (className == "OpenLayers.Geometry.MultiLineString") ||
-            (className == "OpenLayers.Geometry.MultiPolygon")) {
-            for (var i = 0; i < geometry.components.length; i++) {
-                this.drawGeometry(geometry.components[i], style);
-            }
-            return;
-        }
-        switch (geometry.CLASS_NAME) {
-            case "OpenLayers.Geometry.Point":
-                this.drawPoint(geometry, style);
-                break;
-            case "OpenLayers.Geometry.LineString":
-                this.drawLineString(geometry, style);
-                break;
-            case "OpenLayers.Geometry.LinearRing":
-                this.drawLinearRing(geometry, style);
-                break;
-            case "OpenLayers.Geometry.Polygon":
-                this.drawPolygon(geometry, style);
-                break;
-            default:
-                break;
-        }
-    },
-
-    /**
-     * Method: drawExternalGraphic
-     * Called to draw External graphics. 
-     * 
-     * Parameters: 
-     * geometry - {<OpenLayers.Geometry>}
-     * style    - {Object}
-     */ 
-    drawExternalGraphic: function(pt, style) {
-       var img = new Image();
-       
-       if(style.graphicTitle) {
-           img.title=style.graphicTitle;           
-       }
-
-       var width = style.graphicWidth || style.graphicHeight;
-       var height = style.graphicHeight || style.graphicWidth;
-       width = width ? width : style.pointRadius*2;
-       height = height ? height : style.pointRadius*2;
-       var xOffset = (style.graphicXOffset != undefined) ?
-           style.graphicXOffset : -(0.5 * width);
-       var yOffset = (style.graphicYOffset != undefined) ?
-           style.graphicYOffset : -(0.5 * 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.globalAlpha = this.opacity;
-           this.canvas.drawImage(this.img, this.x, 
-                                 this.y, this.width, this.height);
-       }, context);
-       img.src = style.externalGraphic;
-    },
-
-    /**
-     * Method: setCanvasStyle
-     * Prepare the canvas for drawing by setting various global settings.
-     *
-     * Parameters:
-     * type - {String} one of 'stroke', 'fill', or 'reset'
-     * style - {Object} Symbolizer hash
-     */
-    setCanvasStyle: function(type, style) {
-        if (type == "fill") {     
-            this.canvas.globalAlpha = style['fillOpacity'];
-            this.canvas.fillStyle = style['fillColor'];
-        } else if (type == "stroke") {  
-            this.canvas.globalAlpha = style['strokeOpacity'];
-            this.canvas.strokeStyle = style['strokeColor'];
-            this.canvas.lineWidth = style['strokeWidth'];
-        } else {
-            this.canvas.globalAlpha = 0;
-            this.canvas.lineWidth = 1;
-        }
-    },
-
-    /**
-     * Method: drawPoint
-     * This method is only called by the renderer itself.
-     * 
-     * 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], style.pointRadius, 0, Math.PI*2, true);
-                    this.canvas.fill();
+OpenLayers.Util.onImageLoadError = function() {
+    this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
+    if (this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
+        var urls = this.urls;
+        if (urls && urls instanceof Array && urls.length > 1){
+            var src = this.src.toString();
+            var current_url, k;
+            for (k = 0; current_url = urls[k]; k++){
+                if(src.indexOf(current_url) != -1){
+                    break;
                 }
-                
-                if(style.stroke !== false) {
-                    this.setCanvasStyle("stroke", style);
-                    this.canvas.beginPath();
-                    this.canvas.arc(pt[0], pt[1], style.pointRadius, 0, Math.PI*2, true);
-                    this.canvas.stroke();
-                    this.setCanvasStyle("reset");
-                }
             }
-        }
-    },
-
-    /**
-     * Method: drawLineString
-     * This method is only called by the renderer itself.
-     * 
-     * Parameters: 
-     * geometry - {<OpenLayers.Geometry>}
-     * style    - {Object}
-     */ 
-    drawLineString: function(geometry, style) {
-        if(style.stroke !== false) {
-            this.setCanvasStyle("stroke", style);
-            this.canvas.beginPath();
-            var start = this.getLocalXY(geometry.components[0]);
-            this.canvas.moveTo(start[0], start[1]);
-            for(var i = 1; i < geometry.components.length; i++) {
-                var pt = this.getLocalXY(geometry.components[i]);
-                this.canvas.lineTo(pt[0], pt[1]);
+            var guess = Math.floor(urls.length * Math.random());
+            var new_url = urls[guess];
+            k = 0;
+            while(new_url == current_url && k++ < 4){
+                guess = Math.floor(urls.length * Math.random());
+                new_url = urls[guess];
             }
-            this.canvas.stroke();
+            this.src = src.replace(current_url, new_url);
+        } else {
+            this.src = this.src;
         }
-        this.setCanvasStyle("reset");
-    },    
-    
-    /**
-     * Method: drawLinearRing
-     * This method is only called by the renderer itself.
-     * 
-     * Parameters: 
-     * geometry - {<OpenLayers.Geometry>}
-     * style    - {Object}
-     */ 
-    drawLinearRing: function(geometry, style) {
-        if(style.fill !== false) {
-            this.setCanvasStyle("fill", style);
-            this.canvas.beginPath();
-            var start = this.getLocalXY(geometry.components[0]);
-            this.canvas.moveTo(start[0], start[1]);
-            for(var i = 1; i < geometry.components.length - 1 ; i++) {
-                var pt = this.getLocalXY(geometry.components[i]);
-                this.canvas.lineTo(pt[0], pt[1]);
-            }
-            this.canvas.fill();
-        }
-        
-        if(style.stroke !== false) {
-            this.setCanvasStyle("stroke", style);
-            this.canvas.beginPath();
-            var start = this.getLocalXY(geometry.components[0]);
-            this.canvas.moveTo(start[0], start[1]);
-            for(var i = 1; i < geometry.components.length; i++) {
-                var pt = this.getLocalXY(geometry.components[i]);
-                this.canvas.lineTo(pt[0], pt[1]);
-            }
-            this.canvas.stroke();
-        }
-        this.setCanvasStyle("reset");
-    },    
-    
-    /**
-     * Method: drawPolygon
-     * This method is only called by the renderer itself.
-     * 
-     * 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', 
-                fillColor: '#000000'}
-            ); // inner rings are 'empty'  
-        }
-    },
-    
-    /**
-     * Method: drawText
-     * This method is only called by the renderer itself.
-     *
-     * Parameters:
-     * location - {<OpenLayers.Point>}
-     * style    - {Object}
-     */
-    drawText: function(location, style) {
-        style = OpenLayers.Util.extend({
-            fontColor: "#000000",
-            labelAlign: "cm"
-        }, style);
-        var pt = this.getLocalXY(location);
-        
-        this.setCanvasStyle("reset");
-        this.canvas.fillStyle = style.fontColor;
-        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]] ||
-                "center";
-            this.canvas.font = fontStyle;
-            this.canvas.textAlign = labelAlign;
-            this.canvas.fillText(style.label, pt[0], pt[1]);
-        } else if (this.canvas.mozDrawText) {
-            // Mozilla pre-Gecko1.9.1 (<FF3.1)
-            this.canvas.mozTextStyle = fontStyle;
-            // No built-in text alignment, so we measure and adjust the position
-            var len = this.canvas.mozMeasureText(style.label);
-            switch(style.labelAlign[0]) {
-                case "l":
-                    break;
-                case "r":
-                    pt[0] -= len;
-                    break;
-                case "c":
-                default:
-                    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]);
-        }
-        this.setCanvasStyle("reset");
-    },
-
-    /**
-     * Method: getLocalXY
-     * transform geographic xy into pixel xy
-     *
-     * Parameters: 
-     * point - {<OpenLayers.Geometry.Point>}
-     */
-    getLocalXY: function(point) {
-        var resolution = this.getResolution();
-        var extent = this.extent;
-        var x = (point.x / resolution + (-extent.left / resolution));
-        var y = ((extent.top / resolution) - point.y / resolution);
-        return [x, y];
-    },
-
-    /**
-     * Method: clear
-     * Clear all vectors from the renderer.
-     */    
-    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.  
-     * 
-     * Parameters:
-     * evt - {<OpenLayers.Event>} 
-     *
-     * Returns:
-     * {String} A feature id or null.
-     */
-    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, 
-                                           loc.lat + resolution * 5);
-        var geom = bounds.toGeometry();
-        for (var feat in this.features) {
-            if (!this.features.hasOwnProperty(feat)) { continue; }
-            if (this.features[feat][0].geometry.intersects(geom)) {
-                return feat;
-            }
-        }   
-        return null;
-    },
-    
-    /**
-     * 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>)} 
-     */
-    eraseFeatures: function(features) {
-        if(!(features instanceof Array)) {
-            features = [features];
-        }
-        for(var i=0; i<features.length; ++i) {
-            delete this.features[features[i].id];
-        }
-        this.redraw();
-    },
-
-    /**
-     * Method: redraw
-     * The real 'meat' of the function: any time things have changed,
-     *     redraw() can be called to loop over all the data and (you guessed
-     *     it) redraw it.  Unlike Elements-based Renderers, we can't interact
-     *     with things once they're drawn, to remove them, for example, so
-     *     instead we have to just clear everything and draw from scratch.
-     */
-    redraw: function() {
-        if (!this.locked) {
-            this.canvas.clearRect(0, 0, this.root.width, this.root.height);
-            var labelMap = [];
-            var feature, style;
-            for (var id in this.features) {
-                if (!this.features.hasOwnProperty(id)) { continue; }
-                feature = this.features[id][0];
-                style = this.features[id][1];
-                if (!feature.geometry) { continue; }
-                this.drawGeometry(feature.geometry, style);
-                if(style.label) {
-                    labelMap.push([feature, style]);
-                }
-            }
-            var item;
-            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"
-});
-
-/**
- * Constant: OpenLayers.Renderer.Canvas.LABEL_ALIGN
- * {Object}
- */
-OpenLayers.Renderer.Canvas.LABEL_ALIGN = {
-    "l": "left",
-    "r": "right"
+    } else {
+        OpenLayers.Element.addClass(this, "olImageLoadError");
+    }
+    this.style.display = "";
 };
-/* ======================================================================
-    OpenLayers/Renderer/Elements.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/Renderer.js
+ * Property: alphaHackNeeded
+ * {Boolean} true if the png alpha hack is necessary and possible, false otherwise.
  */
+OpenLayers.Util.alphaHackNeeded = null;
 
 /**
- * Class: OpenLayers.ElementsIndexer
- * This class takes care of figuring out which order elements should be
- *     placed in the DOM based on given indexing methods. 
+ * Function: alphaHack
+ * 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.
  */
-OpenLayers.ElementsIndexer = OpenLayers.Class({
-   
-    /**
-     * Property: maxZIndex
-     * {Integer} This is the largest-most z-index value for a node
-     *     contained within the indexer.
-     */
-    maxZIndex: null,
+OpenLayers.Util.alphaHack = function() {
+    if (OpenLayers.Util.alphaHackNeeded == null) {
+        var arVersion = navigator.appVersion.split("MSIE");
+        var version = parseFloat(arVersion[1]);
+        var filter = false;
     
-    /**
-     * 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, 
+        // 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.
     
-    /**
-     * 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 
-     *     value O(1).
-     */
-    indices: null,
+        try { 
+            filter = !!(document.body.filters);
+        } catch (e) {}    
     
-    /**
-     * Property: compare
-     * {Function} This is the function used to determine placement of
-     *     of a new node within the indexer. If null, this defaults to to
-     *     the Z_ORDER_DRAWING_ORDER comparison method.
-     */
-    compare: null,
-    
-    /**
-     * APIMethod: initialize
-     * Create a new indexer with 
-     * 
-     * Parameters:
-     * yOrdering - {Boolean} Whether to use y-ordering.
-     */
-    initialize: function(yOrdering) {
+        OpenLayers.Util.alphaHackNeeded = (filter && 
+                                           (version >= 5.5) && (version < 7));
+    }
+    return OpenLayers.Util.alphaHackNeeded;
+};
 
-        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)). 
-     * 
-     * 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.
-     */
-    insert: function(newNode) {
-        // If the node is known to the indexer, remove it so we can
-        // recalculate where it should go.
-        if (this.exists(newNode)) {
-            this.remove(newNode);
-        }
-        
-        var nodeId = newNode.id;
-        
-        this.determineZIndex(newNode);       
+/** 
+ * Function: modifyAlphaImageDiv
+ * 
+ * div - {DOMElement} Div containing Alpha-adjusted Image
+ * id - {String}
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ * imgURL - {String}
+ * position - {String}
+ * 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, 
+                                               opacity) {
 
-        var leftIndex = -1;
-        var rightIndex = this.order.length;
-        var middle;
+    OpenLayers.Util.modifyDOMElement(div, id, px, sz, position,
+                                     null, null, opacity);
 
-        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);
-    },
-    
-    /**
-     * APIMethod: remove
-     * 
-     * Parameters:
-     * node - {DOMElement} The node to be removed.
-     */
-    remove: function(node) {
-        var nodeId = node.id;
-        var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId);
-        if (arrayIndex >= 0) {
-            // Remove it from the order array, as well as deleting the node
-            // 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 
-            // order array.
-            if (this.order.length > 0) {
-                var lastId = this.order[this.order.length - 1];
-                this.maxZIndex = this.indices[lastId];
-            } else {
-                this.maxZIndex = 0;
-            }
-        }
-    },
-    
-    /**
-     * APIMethod: clear
-     */
-    clear: function() {
-        this.order = [];
-        this.indices = {};
-        this.maxZIndex = 0;
-    },
-    
-    /**
-     * APIMethod: exists
-     *
-     * Parameters:
-     * node- {DOMElement} The node to test for existence.
-     *
-     * Returns:
-     * {Boolean} Whether or not the node exists in the indexer?
-     */
-    exists: function(node) {
-        return (this.indices[node.id] != null);
-    },
+    var img = div.childNodes[0];
 
-    /**
-     * 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 
-     *     data itself).
-     */
-    getZIndex: function(node) {
-        return node._style.graphicZIndex;  
-    },
+    if (imgURL) {
+        img.src = imgURL;
+    }
+    OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, 
+                                     "relative", border);
     
-    /**
-     * Method: determineZIndex
-     * 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} 
-     */
-    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
-        // over all indexing methods, we'll create a new z-index that's
-        // greater than any currently in the indexer.
-        if (zIndex == null) {
-            zIndex = this.maxZIndex;
-            node._style.graphicZIndex = zIndex; 
-        } else if (zIndex > this.maxZIndex) {
-            this.maxZIndex = zIndex;
+    if (OpenLayers.Util.alphaHack()) {
+        if(div.style.display != "none") {
+            div.style.display = "inline-block";
         }
-    },
-
-    /**
-     * 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) {
-            var nextElement = OpenLayers.Util.getElement(this.order[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 
- *     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}
-     */
-    Z_ORDER: function(indexer, newNode, nextNode) {
-        var newZIndex = indexer.getZIndex(newNode);
-
-        var returnVal = 0;
-        if (nextNode) {
-            var nextZIndex = indexer.getZIndex(nextNode);
-            returnVal = newZIndex - nextZIndex; 
+        if (sizing == null) {
+            sizing = "scale";
         }
         
-        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 
-     *     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, 
-            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;
+        div.style.filter = "progid:DXImageTransform.Microsoft" +
+                           ".AlphaImageLoader(src='" + img.src + "', " +
+                           "sizingMethod='" + sizing + "')";
+        if (parseFloat(div.style.opacity) >= 0.0 && 
+            parseFloat(div.style.opacity) < 1.0) {
+            div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
         }
-        
-        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  
-     *     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, 
-            nextNode
-        );
-        
-        if (nextNode && returnVal === 0) {            
-            var result = nextNode._boundsBottom - newNode._boundsBottom;
-            returnVal = (result === 0) ? 1 : result;
-        }
-        
-        return returnVal;       
+        img.style.filter = "alpha(opacity=0)";
     }
 };
 
-/**
- * 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 
- *  functionality between different vector libraries which use nodes/elements
- *  as a base for rendering vectors. 
+/** 
+ * Function: createAlphaImageDiv
  * 
- * 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. 
+ * id - {String}
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ * imgURL - {String}
+ * position - {String}
+ * border - {String}
+ * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale"
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ * delayDisplay - {Boolean} If true waits until the image has been
+ *                          loaded.
  * 
- * Inherits:
- *  - <OpenLayers.Renderer>
- */
-OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
-
-    /**
-     * Property: rendererRoot
-     * {DOMElement}
-     */
-    rendererRoot: null,
+ * Returns:
+ * {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, 
+                                               opacity, delayDisplay) {
     
-    /**
-     * Property: root
-     * {DOMElement}
-     */
-    root: null,
-    
-    /**
-     * Property: vectorRoot
-     * {DOMElement}
-     */
-    vectorRoot: null,
+    var div = OpenLayers.Util.createDiv();
+    var img = OpenLayers.Util.createImage(null, null, null, null, null, null, 
+                                          null, false);
+    div.appendChild(img);
 
-    /**
-     * Property: textRoot
-     * {DOMElement}
-     */
-    textRoot: null,
+    if (delayDisplay) {
+        img.style.display = "none";
+        OpenLayers.Event.observe(img, "load",
+            OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
+        OpenLayers.Event.observe(img, "error",
+            OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
+    }
 
-    /**
-     * Property: xmlns
-     * {String}
-     */    
-    xmlns: null,
+    OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position, 
+                                        border, sizing, opacity);
     
-    /**
-     * Property: Indexer
-     * {<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, 
-    
-    /**
-     * Constant: BACKGROUND_ID_SUFFIX
-     * {String}
-     */
-    BACKGROUND_ID_SUFFIX: "_background",
-    
-    /**
-     * Constant: BACKGROUND_ID_SUFFIX
-     * {String}
-     */
-    LABEL_ID_SUFFIX: "_label",
-    
-    /**
-     * Constructor: OpenLayers.Renderer.Elements
-     * 
-     * Parameters:
-     * containerID - {String}
-     * options - {Object} options for this renderer. Supported options are:
-     *     * yOrdering - {Boolean} Whether to use y-ordering
-     *     * zIndexing - {Boolean} Whether to use z-indexing. Will be ignored
-     *         if yOrdering is set to true.
-     */
-    initialize: function(containerID, options) {
-        OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
+    return div;
+};
 
-        this.rendererRoot = this.createRenderRoot();
-        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(); 
+/** 
+ * Function: upperCaseObject
+ * 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: 
+ * object - {Object}
+ * 
+ * Returns: 
+ * {Object} A new Object with all the same keys but uppercased
+ */
+OpenLayers.Util.upperCaseObject = function (object) {
+    var uObject = {};
+    for (var key in object) {
+        uObject[key.toUpperCase()] = object[key];
+    }
+    return uObject;
+};
 
-        this.rendererRoot = null;
-        this.root = null;
-        this.xmlns = null;
-
-        OpenLayers.Renderer.prototype.destroy.apply(this, arguments);
-    },
-    
-    /**
-     * Method: clear
-     * Remove all the elements from the root
-     */    
-    clear: function() {
-        var child;
-        var root = this.vectorRoot;
-        if (root) {
-            while (child = root.firstChild) {
-                root.removeChild(child);
-            }
-        }
-        root = this.textRoot;
-        if (root) {
-            while (child = root.firstChild) {
-                root.removeChild(child);
-            }
-        }
-        if (this.indexer) {
-            this.indexer.clear();
-        }
-    },
-
-    /** 
-     * 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.  
-     *  
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * style - {Object}
-     * 
-     * Returns:
-     * {String} The corresponding node type for the specified geometry
+/** 
+ * 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
+ *     are undefined in the to object will be set on the to object.
+ *
+ * Returns:
+ * {Object} A reference to the to object.  Note that the to argument is modified
+ *     in place and returned by this function.
+ */
+OpenLayers.Util.applyDefaults = function (to, from) {
+    to = to || {};
+    /*
+     * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
+     * prototype object" when calling hawOwnProperty if the source object is an
+     * instance of window.Event.
      */
-    getNodeType: function(geometry, style) { },
+    var fromIsEvt = typeof window.Event == "function"
+                    && from instanceof window.Event;
 
-    /** 
-     * 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.
-     *
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * style - {Object}
-     * featureId - {String}
-     * 
-     * Returns:
-     * {Boolean} true if the geometry has been drawn completely; null if
-     *     incomplete; false otherwise
-     */
-    drawGeometry: function(geometry, style, featureId) {
-        var className = geometry.CLASS_NAME;
-        var rendered = true;
-        if ((className == "OpenLayers.Geometry.Collection") ||
-            (className == "OpenLayers.Geometry.MultiPoint") ||
-            (className == "OpenLayers.Geometry.MultiLineString") ||
-            (className == "OpenLayers.Geometry.MultiPolygon")) {
-            for (var i = 0, len=geometry.components.length; i<len; i++) {
-                rendered = this.drawGeometry(
-                    geometry.components[i], style, featureId) && rendered;
-            }
-            return rendered;
-        };
-
-        rendered = false;
-        var removeBackground = false;
-        if (style.display != "none") {
-            if (style.backgroundGraphic) {
-                this.redrawBackgroundNode(geometry.id, geometry, style,
-                    featureId);
-            } else {
-                removeBackground = true;
-            }
-            rendered = this.redrawNode(geometry.id, geometry, style,
-                featureId);
+    for (var key in from) {
+        if (to[key] === undefined ||
+            (!fromIsEvt && from.hasOwnProperty
+             && from.hasOwnProperty(key) && !to.hasOwnProperty(key))) {
+            to[key] = from[key];
         }
-        if (rendered == false) {
-            var node = document.getElementById(geometry.id);
-            if (node) {
-                if (node._style.backgroundGraphic) {
-                    removeBackground = true;
-                }
-                node.parentNode.removeChild(node);
-            }
-        }
-        if (removeBackground) {
-            var node = document.getElementById(
-                geometry.id + this.BACKGROUND_ID_SUFFIX);
-            if (node) {
-                node.parentNode.removeChild(node);
-            }
-        }
-        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
+     * IE doesn't include the toString property when iterating over an object's
+     * properties with the for(property in object) syntax.  Explicitly check if
+     * the source has its own toString property.
      */
-    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._boundsBottom = geometry.getBounds().bottom;
-        node._geometryClass = geometry.CLASS_NAME;
-        node._style = style;
-
-        var drawResult = this.drawGeometryNode(node, geometry, style);
-        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
-        // likely where it would be.
-        if (this.indexer) {
-            var insert = this.indexer.insert(node);
-            if (insert) {
-                this.vectorRoot.insertBefore(node, insert);
-            } else {
-                this.vectorRoot.appendChild(node);
-            }
-        } 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){ 
-                this.vectorRoot.appendChild(node);
-            }
-        }
-        
-        this.postDraw(node);
-        
-        return drawResult.complete;
-    },
+    if(!fromIsEvt && from && from.hasOwnProperty
+       && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) {
+        to.toString = from.toString;
+    }
     
-    /**
-     * 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 
-     *     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;
-        backgroundStyle.graphicYOffset = backgroundStyle.backgroundYOffset;
-        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, 
-            null
-        );
-    },
+    return to;
+};
 
-    /**
-     * Method: drawGeometryNode
-     * Given a node, draw a geometry on the specified layer.
-     *     node and geometry are required arguments, style is optional.
-     *     This method is only called by the render itself.
-     *
-     * Parameters:
-     * 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
-     *     could be drawn)
-     */
-    drawGeometryNode: function(node, geometry, style) {
-        style = style || node._style;
-
-        var options = {
-            'isFilled': style.fill === undefined ?
-                true :
-                style.fill,
-            'isStroked': style.stroke === undefined ?
-                !!style.strokeWidth :
-                style.stroke
-        };
-        var drawn;
-        switch (geometry.CLASS_NAME) {
-            case "OpenLayers.Geometry.Point":
-                if(style.graphic === false) {
-                    options.isFilled = false;
-                    options.isStroked = false;
-                }
-                drawn = this.drawPoint(node, geometry);
-                break;
-            case "OpenLayers.Geometry.LineString":
-                options.isFilled = false;
-                drawn = this.drawLineString(node, geometry);
-                break;
-            case "OpenLayers.Geometry.LinearRing":
-                drawn = this.drawLinearRing(node, geometry);
-                break;
-            case "OpenLayers.Geometry.Polygon":
-                drawn = this.drawPolygon(node, geometry);
-                break;
-            case "OpenLayers.Geometry.Surface":
-                drawn = this.drawSurface(node, geometry);
-                break;
-            case "OpenLayers.Geometry.Rectangle":
-                drawn = this.drawRectangle(node, geometry);
-                break;
-            default:
-                break;
-        }
-
-        node._options = options; 
-
-        //set style
-        //TBD simplify this
-        if (drawn != false) {
-            return {
-                node: this.setStyle(node, style, options, geometry),
-                complete: drawn
-            };
-        } else {
-            return false;
-        }
-    },
+/**
+ * Function: getParameterString
+ * 
+ * Parameters:
+ * params - {Object}
+ * 
+ * Returns:
+ * {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). 
+ */
+OpenLayers.Util.getParameterString = function(params) {
+    var paramsArray = [];
     
-    /**
-     * 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. 
-     *     Should be implemented by subclasses.
-     *     This method is only called by the renderer itself.
-     * 
-     * 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. 
-     *     Should be implemented by subclasses.
-     *     This method is only called by the renderer itself.
-     * 
-     * 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. 
-     *     Should be implemented by subclasses.
-     *     This method is only called by the renderer itself.
-     * 
-     * 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. 
-     *    Should be implemented by subclasses.
-     *    This method is only called by the renderer itself.
-     * 
-     * 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. 
-     *     Should be implemented by subclasses.
-     *     This method is only called by the renderer itself.
-     * 
-     * 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. 
-     *     Should be implemented by subclasses.
-     *     This method is only called by the renderer itself.
-     * 
-     * 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. 
-     *     Should be implemented by subclasses.
-     *     This method is only called by the renderer itself.
-     * 
-     * 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}
-     */
-    removeText: function(featureId) {
-        var label = document.getElementById(featureId + this.LABEL_ID_SUFFIX);
-        if (label) {
-            this.textRoot.removeChild(label);
+    for (var key in params) {
+      var value = params[key];
+      if ((value != null) && (typeof value != 'function')) {
+        var encodedValue;
+        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++) {
+            item = value[itemIndex];
+            encodedItemArray.push(encodeURIComponent(
+                (item === null || item === undefined) ? "" : item)
+            );
+          }
+          encodedValue = encodedItemArray.join(",");
         }
-    },
-
-    /**
-     * 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 target = evt.target;
-        var useElement = target && target.correspondingUseElement;
-        var node = useElement ? useElement : (target || evt.srcElement);
-        var featureId = node._featureId;
-        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 
-     *     node with the geometry.id, destroy its geometry, and remove it from
-     *     the DOM.
-     * 
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * featureId - {String}
-     */
-    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], featureId);
-            }
-        } else {    
-            var element = OpenLayers.Util.getElement(geometry.id);
-            if (element && element.parentNode) {
-                if (element.geometry) {
-                    element.geometry.destroy();
-                    element.geometry = null;
-                }
-                element.parentNode.removeChild(element);
-
-                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);
-                    if (bElem && bElem.parentNode) {
-                        // No need to destroy the geometry since the element and the background
-                        // node share the same geometry.
-                        bElem.parentNode.removeChild(bElem);
-                    }
-                }
-            }
+        else {
+          /* value is a string; simply encode */
+          encodedValue = encodeURIComponent(value);
         }
-    },
-
-    /** 
-     * 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.
-     */
-    nodeFactory: function(id, type) {
-        var node = OpenLayers.Util.getElement(id);
-        if (node) {
-            if (!this.nodeTypeCompare(node, type)) {
-                node.parentNode.removeChild(node);
-                node = this.nodeFactory(id, type);
-            }
-        } else {
-            node = this.createNode(type, id);
-        }
-        return node;
-    },
+        paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
+      }
+    }
     
-    /** 
-     * 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.
-     */
-    createNode: function(type, id) {},
+    return paramsArray.join("&");
+};
 
-    /**
-     * Method: moveRoot
-     * moves this renderer's root to a different renderer.
-     * 
-     * Parameters:
-     * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
-     */
-    moveRoot: function(renderer) {
-        var root = this.root;
-        if(renderer.root.parentNode == this.rendererRoot) {
-            root = renderer.root;
-        }
-        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
-     */
-    isComplexSymbol: function(graphicName) {
-        return (graphicName != "circle") && !!graphicName;
-    },
-
-    CLASS_NAME: "OpenLayers.Renderer.Elements"
-});
-
-
 /**
- * Constant: OpenLayers.Renderer.symbol
- * Coordinate arrays for well known (named) symbols.
+ * 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.Renderer.symbol = {
-    "star": [350,75, 379,161, 469,161, 397,215, 423,301, 350,250, 277,301,
-            303,215, 231,161, 321,161, 350,75],
-    "cross": [4,0, 6,0, 6,4, 10,4, 10,6, 6,6, 6,10, 4,10, 4,6, 0,6, 0,4, 4,4,
-            4,0],
-    "x": [0,0, 25,0, 50,35, 75,0, 100,0, 65,50, 100,100, 75,100, 50,65, 25,100, 0,100, 35,50, 0,0],
-    "square": [0,0, 0,1, 1,1, 1,0, 0,0],
-    "triangle": [0,10, 10,10, 5,0, 0,10]
+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;
 };
-/* ======================================================================
-    OpenLayers/Strategy/Cluster.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/Strategy.js
+ * Property: ImgPath
+ * {String} Default is ''.
  */
+OpenLayers.ImgPath = '';
 
-/**
- * Class: OpenLayers.Strategy.Cluster
- * Strategy for vector feature clustering.
- *
- * Inherits from:
- *  - <OpenLayers.Strategy>
+/** 
+ * Function: getImagesLocation
+ * 
+ * Returns:
+ * {String} The fully formatted image location string
  */
-OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, {
-    
-    /**
-     * APIProperty: distance
-     * {Integer} Pixel distance between features that should be considered a
-     *     single cluster.  Default is 20 pixels.
-     */
-    distance: 20,
-    
-    /**
-     * APIProperty: threshold
-     * {Integer} Optional threshold below which original features will be
-     *     added to the layer instead of clusters.  For example, a threshold
-     *     of 3 would mean that any time there are 2 or fewer features in
-     *     a cluster, those features will be added directly to the layer instead
-     *     of a cluster representing those features.  Default is null (which is
-     *     equivalent to 1 - meaning that clusters may contain just one feature).
-     */
-    threshold: null,
-    
-    /**
-     * Property: features
-     * {Array(<OpenLayers.Feature.Vector>)} Cached features.
-     */
-    features: null,
-    
-    /**
-     * Property: clusters
-     * {Array(<OpenLayers.Feature.Vector>)} Calculated clusters.
-     */
-    clusters: null,
-    
-    /**
-     * Property: clustering
-     * {Boolean} The strategy is currently clustering features.
-     */
-    clustering: false,
-    
-    /**
-     * Property: resolution
-     * {Float} The resolution (map units per pixel) of the current cluster set.
-     */
-    resolution: null,
+OpenLayers.Util.getImagesLocation = function() {
+    return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
+};
 
-    /**
-     * Constructor: OpenLayers.Strategy.Cluster
-     * Create a new clustering strategy.
-     *
-     * Parameters:
-     * options - {Object} Optional object whose properties will be set on the
-     *     instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
-    },
-    
-    /**
-     * APIMethod: activate
-     * Activate the strategy.  Register any listeners, do appropriate setup.
-     * 
-     * Returns:
-     * {Boolean} The strategy was successfully activated.
-     */
-    activate: function() {
-        var activated = OpenLayers.Strategy.prototype.activate.call(this);
-        if(activated) {
-            this.layer.events.on({
-                "beforefeaturesadded": this.cacheFeatures,
-                "moveend": this.cluster,
-                scope: this
-            });
-        }
-        return activated;
-    },
-    
-    /**
-     * APIMethod: deactivate
-     * Deactivate the strategy.  Unregister any listeners, do appropriate
-     *     tear-down.
-     * 
-     * Returns:
-     * {Boolean} The strategy was successfully deactivated.
-     */
-    deactivate: function() {
-        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
-        if(deactivated) {
-            this.clearCache();
-            this.layer.events.un({
-                "beforefeaturesadded": this.cacheFeatures,
-                "moveend": this.cluster,
-                scope: this
-            });
-        }
-        return deactivated;
-    },
-    
-    /**
-     * Method: cacheFeatures
-     * Cache features before they are added to the layer.
-     *
-     * Parameters:
-     * event - {Object} The event that this was listening for.  This will come
-     *     with a batch of features to be clustered.
-     *     
-     * Returns:
-     * {Boolean} False to stop features from being added to the layer.
-     */
-    cacheFeatures: function(event) {
-        var propagate = true;
-        if(!this.clustering) {
-            this.clearCache();
-            this.features = event.features;
-            this.cluster();
-            propagate = false;
-        }
-        return propagate;
-    },
-    
-    /**
-     * Method: clearCache
-     * Clear out the cached features.
-     */
-    clearCache: function() {
-        this.features = null;
-    },
-    
-    /**
-     * Method: cluster
-     * Cluster features based on some threshold distance.
-     *
-     * Parameters:
-     * event - {Object} The event received when cluster is called as a
-     *     result of a moveend event.
-     */
-    cluster: function(event) {
-        if((!event || event.zoomChanged) && this.features) {
-            var resolution = this.layer.map.getResolution();
-            if(resolution != this.resolution || !this.clustersExist()) {
-                this.resolution = resolution;
-                var clusters = [];
-                var feature, clustered, cluster;
-                for(var i=0; i<this.features.length; ++i) {
-                    feature = this.features[i];
-                    if(feature.geometry) {
-                        clustered = false;
-                        for(var j=clusters.length-1; j>=0; --j) {
-                            cluster = clusters[j];
-                            if(this.shouldCluster(cluster, feature)) {
-                                this.addToCluster(cluster, feature);
-                                clustered = true;
-                                break;
-                            }
-                        }
-                        if(!clustered) {
-                            clusters.push(this.createCluster(this.features[i]));
-                        }
-                    }
-                }
-                this.layer.removeAllFeatures();
-                if(clusters.length > 0) {
-                    if(this.threshold > 1) {
-                        var clone = clusters.slice();
-                        clusters = [];
-                        var candidate;
-                        for(var i=0, len=clone.length; i<len; ++i) {
-                            candidate = clone[i];
-                            if(candidate.attributes.count < this.threshold) {
-                                Array.prototype.push.apply(clusters, candidate.cluster);
-                            } else {
-                                clusters.push(candidate);
-                            }
-                        }
-                    }
-                    this.clustering = true;
-                    // A legitimate feature addition could occur during this
-                    // addFeatures call.  For clustering to behave well, features
-                    // should be removed from a layer before requesting a new batch.
-                    this.layer.addFeatures(clusters);
-                    this.clustering = false;
-                }
-                this.clusters = clusters;
-            }
-        }
-    },
-    
-    /**
-     * Method: clustersExist
-     * Determine whether calculated clusters are already on the layer.
-     *
-     * Returns:
-     * {Boolean} The calculated clusters are already on the layer.
-     */
-    clustersExist: function() {
-        var exist = false;
-        if(this.clusters && this.clusters.length > 0 &&
-           this.clusters.length == this.layer.features.length) {
-            exist = true;
-            for(var i=0; i<this.clusters.length; ++i) {
-                if(this.clusters[i] != this.layer.features[i]) {
-                    exist = false;
-                    break;
-                }
-            }
-        }
-        return exist;
-    },
-    
-    /**
-     * Method: shouldCluster
-     * Determine whether to include a feature in a given cluster.
-     *
-     * Parameters:
-     * cluster - {<OpenLayers.Feature.Vector>} A cluster.
-     * feature - {<OpenLayers.Feature.Vector>} A feature.
-     *
-     * Returns:
-     * {Boolean} The feature should be included in the cluster.
-     */
-    shouldCluster: function(cluster, feature) {
-        var cc = cluster.geometry.getBounds().getCenterLonLat();
-        var fc = feature.geometry.getBounds().getCenterLonLat();
-        var distance = (
-            Math.sqrt(
-                Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2)
-            ) / this.resolution
-        );
-        return (distance <= this.distance);
-    },
-    
-    /**
-     * Method: addToCluster
-     * Add a feature to a cluster.
-     *
-     * Parameters:
-     * cluster - {<OpenLayers.Feature.Vector>} A cluster.
-     * feature - {<OpenLayers.Feature.Vector>} A feature.
-     */
-    addToCluster: function(cluster, feature) {
-        cluster.cluster.push(feature);
-        cluster.attributes.count += 1;
-    },
-    
-    /**
-     * Method: createCluster
-     * Given a feature, create a cluster.
-     *
-     * Parameters:
-     * feature - {<OpenLayers.Feature.Vector>}
-     *
-     * Returns:
-     * {<OpenLayers.Feature.Vector>} A cluster.
-     */
-    createCluster: function(feature) {
-        var center = feature.geometry.getBounds().getCenterLonLat();
-        var cluster = new OpenLayers.Feature.Vector(
-            new OpenLayers.Geometry.Point(center.lon, center.lat),
-            {count: 1}
-        );
-        cluster.cluster = [feature];
-        return cluster;
-    },
 
-    CLASS_NAME: "OpenLayers.Strategy.Cluster" 
-});
-/* ======================================================================
-    OpenLayers/Strategy/Fixed.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/Strategy.js
+/** 
+ * Function: Try
+ * 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. 
+ *    If none executes successfully, returns null.
+ * 
+ * Returns:
+ * {*} The value returned by the first successfully executed function.
  */
+OpenLayers.Util.Try = function() {
+    var returnValue = null;
 
-/**
- * Class: OpenLayers.Strategy.Fixed
- * A simple strategy that requests features once and never requests new data.
- *
- * Inherits from:
- *  - <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 false.
-     */
-    preload: false,
+    for (var i=0, len=arguments.length; i<len; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) {}
+    }
 
-    /**
-     * Constructor: OpenLayers.Strategy.Fixed
-     * Create a new Fixed strategy.
-     *
-     * Parameters:
-     * options - {Object} Optional object whose properties will be set on the
-     *     instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
-    },
+    return returnValue;
+};
 
-    /**
-     * APIMethod: destroy
-     * Clean up the strategy.
-     */
-    destroy: function() {
-        OpenLayers.Strategy.prototype.destroy.apply(this, arguments);
-    },
 
-    /**
-     * Method: activate
-     * Activate the strategy: load data or add listener to load when visible
-     *
-     * Returns:
-     * {Boolean} True if the strategy was successfully activated or false if
-     *      the strategy was already active.
-     */
-    activate: function() {
-        if(OpenLayers.Strategy.prototype.activate.apply(this, arguments)) {
-            this.layer.events.on({
-                "refresh": this.load,
-                scope: this
-            });
-            if(this.layer.visibility == true || this.preload) {
-                this.load();
-            } else {
-                this.layer.events.on({
-                    "visibilitychanged": this.load,
-                    scope: this
-                });
-            }
-            return true;
+/** 
+ * Function: getNodes
+ * 
+ * These could/should be made namespace aware?
+ * 
+ * Parameters:
+ * p - {}
+ * tagName - {String}
+ * 
+ * Returns:
+ * {Array}
+ */
+OpenLayers.Util.getNodes=function(p, tagName) {
+    var nodes = OpenLayers.Util.Try(
+        function () {
+            return OpenLayers.Util._getNodes(p.documentElement.childNodes,
+                                            tagName);
+        },
+        function () {
+            return OpenLayers.Util._getNodes(p.childNodes, tagName);
         }
-        return false;
-    },
-    
-    /**
-     * Method: deactivate
-     * Deactivate the strategy.  Undo what is done in <activate>.
-     * 
-     * Returns:
-     * {Boolean} The strategy was successfully deactivated.
-     */
-    deactivate: function() {
-        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
-        if(deactivated) {
-            this.layer.events.un({
-                "refresh": this.load,
-                "visibilitychanged": this.load,
-                scope: this
-            });
-        }
-        return deactivated;
-    },
+    );
+    return nodes;
+};
 
-    /**
-     * Method: load
-     * Tells protocol to load data and unhooks the visibilitychanged event
-     *
-     * Parameters:
-     * options - {Object} options to pass to protocol read.
-     */
-    load: function(options) {
-        var layer = this.layer;
-        layer.events.triggerEvent("loadstart");
-        layer.protocol.read(OpenLayers.Util.applyDefaults({
-            callback: OpenLayers.Function.bind(this.merge, this,
-                layer.map.getProjectionObject()),
-            filter: layer.filter
-        }, options));
-        layer.events.un({
-            "visibilitychanged": this.load,
-            scope: this
-        });
-    },
-
-    /**
-     * Method: merge
-     * Add all features to the layer.
-     *
-     * Parameters:
-     * mapProjection - {OpenLayers.Projection} the map projection
-     * resp - {Object} options to pass to protocol read.
-     */
-    merge: function(mapProjection, resp) {
-        var layer = this.layer;
-        layer.destroyFeatures();
-        var features = resp.features;
-        if (features && features.length > 0) {
-            if(!mapProjection.equals(layer.projection)) {
-                var geom;
-                for(var i=0, len=features.length; i<len; ++i) {
-                    geom = features[i].geometry;
-                    if(geom) {
-                        geom.transform(layer.projection, mapProjection);
-                    }
-                }
-            }
-            layer.addFeatures(features);
+/**
+ * Function: _getNodes
+ * 
+ * Parameters:
+ * nodes - {Array}
+ * tagName - {String}
+ * 
+ * Returns:
+ * {Array}
+ */
+OpenLayers.Util._getNodes=function(nodes, tagName) {
+    var retArray = [];
+    for (var i=0, len=nodes.length; i<len; i++) {
+        if (nodes[i].nodeName==tagName) {
+            retArray.push(nodes[i]);
         }
-        layer.events.triggerEvent("loadend");
-    },
+    }
 
-    CLASS_NAME: "OpenLayers.Strategy.Fixed"
-});
-/* ======================================================================
-    OpenLayers/Strategy/Paging.js
-   ====================================================================== */
+    return retArray;
+};
 
-/* 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/Strategy.js
- */
 
 /**
- * Class: OpenLayers.Strategy.Paging
- * Strategy for vector feature paging
- *
- * Inherits from:
- *  - <OpenLayers.Strategy>
+ * Function: getTagText
+ * 
+ * Parameters:
+ * parent - {}
+ * item - {String}
+ * index - {Integer}
+ * 
+ * Returns:
+ * {String}
  */
-OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, {
-    
-    /**
-     * Property: features
-     * {Array(<OpenLayers.Feature.Vector>)} Cached features.
-     */
-    features: null,
-    
-    /**
-     * Property: length
-     * {Integer} Number of features per page.  Default is 10.
-     */
-    length: 10,
-    
-    /**
-     * Property: num
-     * {Integer} The currently displayed page number.
-     */
-    num: null,
-    
-    /**
-     * Property: paging
-     * {Boolean} The strategy is currently changing pages.
-     */
-    paging: false,
-
-    /**
-     * Constructor: OpenLayers.Strategy.Paging
-     * Create a new paging strategy.
-     *
-     * Parameters:
-     * options - {Object} Optional object whose properties will be set on the
-     *     instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
-    },
-    
-    /**
-     * APIMethod: activate
-     * Activate the strategy.  Register any listeners, do appropriate setup.
-     * 
-     * Returns:
-     * {Boolean} The strategy was successfully activated.
-     */
-    activate: function() {
-        var activated = OpenLayers.Strategy.prototype.activate.call(this);
-        if(activated) {
-            this.layer.events.on({
-                "beforefeaturesadded": this.cacheFeatures,
-                scope: this
-            });
+OpenLayers.Util.getTagText = function (parent, item, index) {
+    var result = OpenLayers.Util.getNodes(parent, item);
+    if (result && (result.length > 0))
+    {
+        if (!index) {
+            index=0;
         }
-        return activated;
-    },
-    
-    /**
-     * APIMethod: deactivate
-     * Deactivate the strategy.  Unregister any listeners, do appropriate
-     *     tear-down.
-     * 
-     * Returns:
-     * {Boolean} The strategy was successfully deactivated.
-     */
-    deactivate: function() {
-        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
-        if(deactivated) {
-            this.clearCache();
-            this.layer.events.un({
-                "beforefeaturesadded": this.cacheFeatures,
-                scope: this
-            });
+        if (result[index].childNodes.length > 1) {
+            return result.childNodes[1].nodeValue; 
         }
-        return deactivated;
-    },
-    
-    /**
-     * Method: cacheFeatures
-     * Cache features before they are added to the layer.
-     *
-     * Parameters:
-     * event - {Object} The event that this was listening for.  This will come
-     *     with a batch of features to be paged.
-     */
-    cacheFeatures: function(event) {
-        if(!this.paging) {
-            this.clearCache();
-            this.features = event.features;
-            this.pageNext(event);
+        else if (result[index].childNodes.length == 1) {
+            return result[index].firstChild.nodeValue; 
         }
-    },
-    
-    /**
-     * Method: clearCache
-     * Clear out the cached features.  This destroys features, assuming
-     *     nothing else has a reference.
-     */
-    clearCache: function() {
-        if(this.features) {
-            for(var i=0; i<this.features.length; ++i) {
-                this.features[i].destroy();
-            }
-        }
-        this.features = null;
-        this.num = null;
-    },
-    
-    /**
-     * APIMethod: pageCount
-     * Get the total count of pages given the current cache of features.
-     *
-     * Returns:
-     * {Integer} The page count.
-     */
-    pageCount: function() {
-        var numFeatures = this.features ? this.features.length : 0;
-        return Math.ceil(numFeatures / this.length);
-    },
+    } else { 
+        return ""; 
+    }
+};
 
-    /**
-     * APIMethod: pageNum
-     * Get the zero based page number.
-     *
-     * Returns:
-     * {Integer} The current page number being displayed.
-     */
-    pageNum: function() {
-        return this.num;
-    },
-
-    /**
-     * APIMethod: pageLength
-     * Gets or sets page length.
-     *
-     * Parameters:
-     * newLength: {Integer} Optional length to be set.
-     *
-     * Returns:
-     * {Integer} The length of a page (number of features per page).
-     */
-    pageLength: function(newLength) {
-        if(newLength && newLength > 0) {
-            this.length = newLength;
-        }
-        return this.length;
-    },
-
-    /**
-     * APIMethod: pageNext
-     * Display the next page of features.
-     *
-     * Returns:
-     * {Boolean} A new page was displayed.
-     */
-    pageNext: function(event) {
-        var changed = false;
-        if(this.features) {
-            if(this.num === null) {
-                this.num = -1;
+/**
+ * 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( 
+        function() {
+            val = node.text;
+            if (!val) {
+                val = node.textContent;
             }
-            var start = (this.num + 1) * this.length;
-            changed = this.page(start, event);
-        }
-        return changed;
-    },
-
-    /**
-     * APIMethod: pagePrevious
-     * Display the previous page of features.
-     *
-     * Returns:
-     * {Boolean} A new page was displayed.
-     */
-    pagePrevious: function() {
-        var changed = false;
-        if(this.features) {
-            if(this.num === null) {
-                this.num = this.pageCount();
+            if (!val) {
+                val = node.firstChild.nodeValue;
             }
-            var start = (this.num - 1) * this.length;
-            changed = this.page(start);
-        }
-        return changed;
-    },
-    
-    /**
-     * Method: page
-     * Display the page starting at the given index from the cache.
-     *
-     * Returns:
-     * {Boolean} A new page was displayed.
-     */
-    page: function(start, event) {
-        var changed = false;
-        if(this.features) {
-            if(start >= 0 && start < this.features.length) {
-                var num = Math.floor(start / this.length);
-                if(num != this.num) {
-                    this.paging = true;
-                    var features = this.features.slice(start, start + this.length);
-                    this.layer.removeFeatures(this.layer.features);
-                    this.num = num;
-                    // modify the event if any
-                    if(event && event.features) {
-                        // this.was called by an event listener
-                        event.features = features;
-                    } else {
-                        // this was called directly on the strategy
-                        this.layer.addFeatures(features);
-                    }
-                    this.paging = false;
-                    changed = true;
-                }
-            }
-        }
-        return changed;
-    },
-    
-    CLASS_NAME: "OpenLayers.Strategy.Paging" 
-});
-/* ======================================================================
-    OpenLayers/Strategy/Refresh.js
-   ====================================================================== */
+        }, 
+        function() {
+            val = node.textContent;
+        }); 
+    return val;
+};
 
-/* 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. */
+/** 
+ * Function: mouseLeft
+ * 
+ * Parameters:
+ * evt - {Event}
+ * div - {HTMLDivElement}
+ * 
+ * Returns:
+ * {Boolean}
+ */
+OpenLayers.Util.mouseLeft = function (evt, div) {
+    // start with the element to which the mouse has moved
+    var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
+    // walk up the DOM tree.
+    while (target != div && target != null) {
+        target = target.parentNode;
+    }
+    // if the target we stop at isn't the div, then we've left the div.
+    return (target != div);
+};
 
 /**
- * @requires OpenLayers/Strategy.js
+ * Property: precision
+ * {Number} The number of significant digits to retain to avoid
+ * floating point precision errors.
+ *
+ * We use 14 as a "safe" default because, although IEEE 754 double floats
+ * (standard on most modern operating systems) support up to about 16
+ * significant digits, 14 significant digits are sufficient to represent
+ * sub-millimeter accuracy in any coordinate system that anyone is likely to
+ * use with OpenLayers.
+ *
+ * If DEFAULT_PRECISION is set to 0, the original non-truncating behavior
+ * of OpenLayers <2.8 is preserved. Be aware that this will cause problems
+ * with certain projections, e.g. spherical Mercator.
+ *
  */
+OpenLayers.Util.DEFAULT_PRECISION = 14;
 
 /**
- * Class: OpenLayers.Strategy.Refresh
- * A strategy that refreshes the layer. By default the strategy waits for a
- *     call to <refresh> before refreshing.  By configuring the strategy with 
- *     the <interval> option, refreshing can take place automatically.
+ * Function: toFloat
+ * Convenience method to cast an object to a Number, rounded to the
+ * desired floating point precision.
  *
- * Inherits from:
- *  - <OpenLayers.Strategy>
+ * Parameters:
+ * number    - {Number} The number to cast and round.
+ * precision - {Number} An integer suitable for use with
+ *      Number.toPrecision(). Defaults to OpenLayers.Util.DEFAULT_PRECISION.
+ *      If set to 0, no rounding is performed.
+ *
+ * Returns:
+ * {Number} The cast, rounded number.
  */
-OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, {
-    
-    /**
-     * Property: force
-     * {Boolean} Force a refresh on the layer. Default is false.
-     */
-    force: false,
+OpenLayers.Util.toFloat = function (number, precision) {
+    if (precision == null) {
+        precision = OpenLayers.Util.DEFAULT_PRECISION;
+    }
+    if (typeof number !== "number") {
+        number = parseFloat(number);
+    }
+    return precision === 0 ? number :
+                             parseFloat(number.toPrecision(precision));
+};
 
-    /**
-     * Property: interval
-     * {Number} Auto-refresh. Default is 0.  If > 0, layer will be refreshed 
-     *     every N milliseconds.
-     */
-    interval: 0,
-    
-    /**
-     * Property: timer
-     * {Number} The id of the timer.
-     */
-    timer: null,
-
-    /**
-     * Constructor: OpenLayers.Strategy.Refresh
-     * Create a new Refresh strategy.
-     *
-     * Parameters:
-     * options - {Object} Optional object whose properties will be set on the
-     *     instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
-    },
-   
-    /**
-     * APIMethod: activate
-     * Activate the strategy. Register any listeners, do appropriate setup.
-     * 
-     * Returns:
-     * {Boolean} True if the strategy was successfully activated.
-     */
-    activate: function() {
-        var activated = OpenLayers.Strategy.prototype.activate.call(this);
-        if(activated) {
-            if(this.layer.visibility === true) {
-                this.start();
-            } 
-            this.layer.events.on({
-                "visibilitychanged": this.reset,
-                scope: this
-            });
-        }
-        return activated;
-    },
-    
-    /**
-     * APIMethod: deactivate
-     * Deactivate the strategy. Unregister any listeners, do appropriate
-     *     tear-down.
-     * 
-     * Returns:
-     * {Boolean} True if the strategy was successfully deactivated.
-     */
-    deactivate: function() {
-        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
-        if(deactivated) {
-            this.stop();
-        }
-        return deactivated;
-    },
-    
-    /**
-     * Method: reset
-     * Start or cancel the refresh interval depending on the visibility of 
-     *     the layer.
-     */
-    reset: function() {
-        if(this.layer.visibility === true) {
-            this.start();
-        } else {
-            this.stop();
-        }
-    },
-    
-    /**
-     * Method: start
-     * Start the refresh interval. 
-     */
-    start: function() {
-        if(this.interval && typeof this.interval === "number" && 
-            this.interval > 0) {
-
-            this.timer = window.setInterval(
-                OpenLayers.Function.bind(this.refresh, this),
-                this.interval);
-        }
-    },
-    
-    /**
-     * APIMethod: refresh
-     * Tell the strategy to refresh which will refresh the layer.
-     */
-    refresh: function() {
-        if (this.layer && this.layer.refresh && 
-            typeof this.layer.refresh == "function") {
-
-            this.layer.refresh({force: this.force});
-        }
-    },
-   
-    /**
-     * Method: stop
-     * Cancels the refresh interval. 
-     */
-    stop: function() {
-        if(this.timer !== null) {
-            window.clearInterval(this.timer);
-            this.timer = null;
-        }
-    },
-    
-    CLASS_NAME: "OpenLayers.Strategy.Refresh" 
-});
-/* ======================================================================
-    OpenLayers/Strategy/Save.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/Strategy.js
+ * Function: rad
+ * 
+ * Parameters:
+ * x - {Float}
+ * 
+ * Returns:
+ * {Float}
  */
+OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
 
 /**
- * Class: OpenLayers.Strategy.Save
- * A strategy that commits newly created or modified features.  By default
- *     the strategy waits for a call to <save> before persisting changes.  By
- *     configuring the strategy with the <auto> option, changes can be saved
- *     automatically.
+ * Function: deg
  *
- * Inherits from:
- *  - <OpenLayers.Strategy>
+ * Parameters:
+ * x - {Float}
+ *
+ * Returns:
+ * {Float}
  */
-OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, {
-    
-    /**
-     * Constant: EVENT_TYPES
-     * {Array(String)} Supported application event types.  Register a listener
-     *     for a particular event with the following syntax:
-     * (code)
-     * strategy.events.register(type, obj, listener);
-     * (end)
-     *
-     *  - *start* Triggered before saving
-     *  - *success* Triggered after a successful transaction
-     *  - *fail* Triggered after a failed transaction
-     *      
-     */
-    EVENT_TYPES: ["start", "success", "fail"],
- 
-    /** 
-     * Property: events
-     * {<OpenLayers.Events>} Events instance for triggering this protocol
-     *    events.
-     */
-    events: null,
-    
-    /**
-     * APIProperty: auto
-     * {Boolean | Number} Auto-save.  Default is false.  If true, features will be
-     *     saved immediately after being added to the layer and with each
-     *     modification or deletion.  If auto is a number, features will be
-     *     saved on an interval provided by the value (in seconds).
-     */
-    auto: false,
-    
-    /**
-     * Property: timer
-     * {Number} The id of the timer.
-     */
-    timer: null,
+OpenLayers.Util.deg = function(x) {return x*180/Math.PI;};
 
-    /**
-     * Constructor: OpenLayers.Strategy.Save
-     * Create a new Save strategy.
-     *
-     * Parameters:
-     * options - {Object} Optional object whose properties will be set on the
-     *     instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
-        this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
-    },
-   
-    /**
-     * APIMethod: activate
-     * Activate the strategy.  Register any listeners, do appropriate setup.
-     * 
-     * Returns:
-     * {Boolean} The strategy was successfully activated.
-     */
-    activate: function() {
-        var activated = OpenLayers.Strategy.prototype.activate.call(this);
-        if(activated) {
-            if(this.auto) {
-                if(typeof this.auto === "number") {
-                    this.timer = window.setInterval(
-                        OpenLayers.Function.bind(this.save, this),
-                        this.auto * 1000
-                    );
-                } else {
-                    this.layer.events.on({
-                        "featureadded": this.triggerSave,
-                        "afterfeaturemodified": this.triggerSave,
-                        scope: this
-                    });
-                }
-            }
-        }
-        return activated;
-    },
-    
-    /**
-     * APIMethod: deactivate
-     * Deactivate the strategy.  Unregister any listeners, do appropriate
-     *     tear-down.
-     * 
-     * Returns:
-     * {Boolean} The strategy was successfully deactivated.
-     */
-    deactivate: function() {
-        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
-        if(deactivated) {
-            if(this.auto) {
-                if(typeof this.auto === "number") {
-                    window.clearInterval(this.timer);
-                } else {
-                    this.layer.events.un({
-                        "featureadded": this.triggerSave,
-                        "afterfeaturemodified": this.triggerSave,
-                        scope: this
-                    });
-                }
-            }
-        }
-        return deactivated;
-    },
-    
-    /**
-     * Method: triggerSave
-     * Registered as a listener.  Calls save if a feature has insert, update,
-     *     or delete state.
-     *
-     * Parameters:
-     * event - {Object} The event this function is listening for.
-     */
-    triggerSave: function(event) {
-        var feature = event.feature;
-        if(feature.state === OpenLayers.State.INSERT ||
-           feature.state === OpenLayers.State.UPDATE ||
-           feature.state === OpenLayers.State.DELETE) {
-            this.save([event.feature]);
-        }
-    },
-    
-    /**
-     * APIMethod: save
-     * Tell the layer protocol to commit unsaved features.  If the layer
-     *     projection differs from the map projection, features will be
-     *     transformed into the layer projection before being committed.
-     *
-     * Parameters:
-     * features - {Array} Features to be saved.  If null, then default is all
-     *     features in the layer.  Features are assumed to be in the map
-     *     projection.
-     */
-    save: function(features) {
-        if(!features) {
-            features = this.layer.features;
-        }
-        this.events.triggerEvent("start", {features:features});
-        var remote = this.layer.projection;
-        var local = this.layer.map.getProjectionObject();
-        if(!local.equals(remote)) {
-            var len = features.length;
-            var clones = new Array(len);
-            var orig, clone;
-            for(var i=0; i<len; ++i) {
-                orig = features[i];
-                clone = orig.clone();
-                clone.fid = orig.fid;
-                clone.state = orig.state;
-                if(orig.url) {
-                    clone.url = orig.url;
-                }
-                clone._original = orig;
-                clone.geometry.transform(local, remote);
-                clones[i] = clone;
-            }
-            features = clones;
-        }
-        this.layer.protocol.commit(features, {
-            callback: this.onCommit,
-            scope: this
-        });
-    },
-    
-    /**
-     * Method: onCommit
-     * Called after protocol commit.
-     *
-     * Parameters:
-     * response - {<OpenLayers.Protocol.Response>} A response object.
-     */
-    onCommit: function(response) {
-        var evt = {"response": response};
-        if(response.success()) {
-            var features = response.reqFeatures;
-            // deal with inserts, updates, and deletes
-            var state, feature;
-            var destroys = [];
-            var insertIds = response.insertIds || [];
-            var j = 0;
-            for(var i=0, len=features.length; i<len; ++i) {
-                feature = features[i];
-                // if projection was different, we may be dealing with clones
-                feature = feature._original || feature;
-                state = feature.state;
-                if(state) {
-                    if(state == OpenLayers.State.DELETE) {
-                        destroys.push(feature);
-                    } else if(state == OpenLayers.State.INSERT) {
-                        feature.fid = insertIds[j];
-                        ++j;
-                    }
-                    feature.state = null;
-                }
-            }
-
-            if(destroys.length > 0) {
-                this.layer.destroyFeatures(destroys);
-            }
-
-            this.events.triggerEvent("success", evt);
-
-        } else {
-            this.events.triggerEvent("fail", evt);
-        }
-    },
-   
-    CLASS_NAME: "OpenLayers.Strategy.Save" 
-});
-/* ======================================================================
-    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
+ * Property: VincentyConstants
+ * {Object} Constants for Vincenty functions.
  */
+OpenLayers.Util.VincentyConstants = {
+    a: 6378137,
+    b: 6356752.3142,
+    f: 1/298.257223563
+};
 
 /**
- * Class: OpenLayers.Symbolizer.Line
- * A symbolizer used to render line features.
+ * APIFunction: distVincenty
+ * Given two objects representing points with geographic coordinates, this
+ *     calculates the distance between those points on the surface of an
+ *     ellipsoid.
+ *
+ * Parameters:
+ * p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
+ * p2 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
+ *
+ * Returns:
+ * {Float} The distance (in km) between the two input points as measured on an
+ *     ellipsoid.  Note that the input point objects must be in geographic
+ *     coordinates (decimal degrees) and the return distance is in kilometers.
  */
-OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, {
+OpenLayers.Util.distVincenty = function(p1, p2) {
+    var ct = OpenLayers.Util.VincentyConstants;
+    var a = ct.a, b = ct.b, f = ct.f;
 
-    /**
-     * APIProperty: strokeColor
-     * {String} Color for line stroke.  This is a RGB hex value (e.g. "#ff0000"
-     *     for red).  
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: strokeOpacity
-     * {Number} Stroke opacity (0-1).
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: strokeWidth
-     * {Number} Pixel stroke width.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: strokeLinecap
-     * {String} Stroke cap type ("butt", "round", or "square").
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * 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.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
+    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)));
+    var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
+    var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
+    var lambda = L, lambdaP = 2*Math.PI;
+    var iterLimit = 20;
+    while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
+        var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
+        var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
+        (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
+        if (sinSigma==0) {
+            return 0;  // co-incident points
+        }
+        var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
+        var sigma = Math.atan2(sinSigma, cosSigma);
+        var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma);
+        var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha);
+        var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
+        var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
+        lambdaP = lambda;
+        lambda = L + (1-C) * f * Math.sin(alpha) *
+        (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
+    }
+    if (iterLimit==0) {
+        return NaN;  // formula failed to converge
+    }
+    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 deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
+        B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
+    var s = b*A*(sigma-deltaSigma);
+    var d = s.toFixed(3)/1000; // round to 1mm precision
+    return d;
+};
 
-    /**
-     * 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
+ * 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;
 
-/**
- * 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).
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: strokeOpacity
-     * {Number} Stroke opacity (0-1).
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: strokeWidth
-     * {Number} Pixel stroke width.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: strokeLinecap
-     * {String} Stroke cap type ("butt", "round", or "square").
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * 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.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
+    var lon1 = lonlat.lon;
+    var lat1 = lonlat.lat;
 
-    /**
-     * APIProperty: fillColor
-     * {String} RGB hex fill color (e.g. "#ff0000" for red).
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: fillOpacity
-     * {Number} Fill opacity (0-1).
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
+    var s = dist;
+    var alpha1 = u.rad(brng);
+    var sinAlpha1 = Math.sin(alpha1);
+    var cosAlpha1 = Math.cos(alpha1);
 
-    /**
-     * APIProperty: pointRadius
-     * {Number} Pixel point radius.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
+    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)));
 
-    /**
-     * APIProperty: externalGraphic
-     * {String} Url to an external graphic that will be used for rendering 
-     *     points.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: graphicWidth
-     * {Number} Pixel width for sizing an external graphic.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: graphicHeight
-     * {Number} Pixel height for sizing an external graphic.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: graphicOpacity
-     * {Number} Opacity (0-1) for an external graphic.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: graphicXOffset
-     * {Number} Pixel offset along the positive x axis for displacing an 
-     *     external graphic.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: graphicYOffset
-     * {Number} Pixel offset along the positive y axis for displacing an 
-     *     external graphic.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
+    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;
+    }
 
-    /**
-     * 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>).
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: graphicName
-     * {String} Named graphic to use when rendering points.  Supported values 
-     *     include "circle", "square", "star", "x", "cross", and "triangle".
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * 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"
-    
-});
+    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)));
 
-/* ======================================================================
-    OpenLayers/Symbolizer/Polygon.js
-   ====================================================================== */
+    var revAz = Math.atan2(sinAlpha, -tmp);  // final bearing
 
-/* 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. */
+    return new OpenLayers.LonLat(lon1+u.deg(L), u.deg(lat2));
+};
 
 /**
- * @requires OpenLayers/Symbolizer.js
+ * Function: getParameters
+ * 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.
  */
+OpenLayers.Util.getParameters = function(url) {
+    // if no url specified, take it from the location bar
+    url = url || window.location.href;
 
-/**
- * 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).
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: strokeOpacity
-     * {Number} Stroke opacity (0-1).
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: strokeWidth
-     * {Number} Pixel stroke width.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: strokeLinecap
-     * {String} Stroke cap type ("butt", "round", or "square").
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * 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.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
+    //parse out parameters portion of url string
+    var paramsString = "";
+    if (OpenLayers.String.contains(url, '?')) {
+        var start = url.indexOf('?') + 1;
+        var end = OpenLayers.String.contains(url, "#") ?
+                    url.indexOf('#') : url.length;
+        paramsString = url.substring(start, end);
+    }
 
-    /**
-     * APIProperty: fillColor
-     * {String} RGB hex fill color (e.g. "#ff0000" for red).
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * APIProperty: fillOpacity
-     * {Number} Fill opacity (0-1).
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
+    var parameters = {};
+    var pairs = paramsString.split(/[&;]/);
+    for(var i=0, len=pairs.length; i<len; ++i) {
+        var keyValue = pairs[i].split('=');
+        if (keyValue[0]) {
 
-    /**
-     * 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"
-    
-});
+            var key = keyValue[0];
+            try {
+                key = decodeURIComponent(key);
+            } catch (err) {
+                key = unescape(key);
+            }
+            
+            // being liberal by replacing "+" with " "
+            var value = (keyValue[1] || '').replace(/\+/g, " ");
 
-/* ======================================================================
-    OpenLayers/Symbolizer/Raster.js
-   ====================================================================== */
+            try {
+                value = decodeURIComponent(value);
+            } catch (err) {
+                value = unescape(value);
+            }
+            
+            // follow OGC convention of comma delimited values
+            value = value.split(",")
 
-/* 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. */
+            //if there's only one value, do not return as array                    
+            if (value.length == 1) {
+                value = value[0];
+            }                
+            
+            parameters[key] = value;
+         }
+     }
+    return parameters;
+};
 
 /**
- * @requires OpenLayers/Symbolizer.js
+ * 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.
  */
+OpenLayers.Util.getArgs = function(url) {
+    OpenLayers.Console.warn(
+        OpenLayers.i18n(
+            "methodDeprecated", {'newMethod': 'OpenLayers.Util.getParameters'}
+        )
+    );
+    return OpenLayers.Util.getParameters(url);
+};
 
 /**
- * Class: OpenLayers.Symbolizer.Raster
- * A symbolizer used to render raster images.
+ * Property: lastSeqID
+ * {Integer} The ever-incrementing count variable.
+ *           Used for generating unique ids.
  */
-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
-   ====================================================================== */
+OpenLayers.Util.lastSeqID = 0;
 
-/* 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
+ * Function: createUniqueID
+ * 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.
  */
+OpenLayers.Util.createUniqueID = function(prefix) {
+    if (prefix == null) {
+        prefix = "id_";
+    }
+    OpenLayers.Util.lastSeqID += 1; 
+    return prefix + OpenLayers.Util.lastSeqID;        
+};
 
 /**
- * Class: OpenLayers.Symbolizer.Text
- * A symbolizer used to render text labels for features.
+ * Constant: INCHES_PER_UNIT
+ * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
+ * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
+ * Includes the full set of units supported by CS-MAP (http://trac.osgeo.org/csmap/)
+ * and PROJ.4 (http://trac.osgeo.org/proj/)
+ * 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.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, {
-    
-    /** 
-     * APIProperty: label
-     * {String} The text for the label.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /** 
-     * APIProperty: fontFamily
-     * {String} The font family for the label.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
+OpenLayers.INCHES_PER_UNIT = { 
+    'inches': 1.0,
+    'ft': 12.0,
+    'mi': 63360.0,
+    'm': 39.3701,
+    'km': 39370.1,
+    'dd': 4374754,
+    'yd': 36
+};
+OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
+OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
+OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
 
-    /** 
-     * APIProperty: fontSize
-     * {String} The font size for the label.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
+// Units from CS-Map
+OpenLayers.METERS_PER_INCH = 0.02540005080010160020;
+OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
+    "Inch": OpenLayers.INCHES_PER_UNIT.inches,
+    "Meter": 1.0 / OpenLayers.METERS_PER_INCH,   //EPSG:9001
+    "Foot": 0.30480060960121920243 / OpenLayers.METERS_PER_INCH,   //EPSG:9003
+    "IFoot": 0.30480000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9002
+    "ClarkeFoot": 0.3047972651151 / OpenLayers.METERS_PER_INCH,   //EPSG:9005
+    "SearsFoot": 0.30479947153867624624 / OpenLayers.METERS_PER_INCH,   //EPSG:9041
+    "GoldCoastFoot": 0.30479971018150881758 / OpenLayers.METERS_PER_INCH,   //EPSG:9094
+    "IInch": 0.02540000000000000000 / OpenLayers.METERS_PER_INCH,
+    "MicroInch": 0.00002540000000000000 / OpenLayers.METERS_PER_INCH,
+    "Mil": 0.00000002540000000000 / OpenLayers.METERS_PER_INCH,
+    "Centimeter": 0.01000000000000000000 / OpenLayers.METERS_PER_INCH,
+    "Kilometer": 1000.00000000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9036
+    "Yard": 0.91440182880365760731 / OpenLayers.METERS_PER_INCH,
+    "SearsYard": 0.914398414616029 / OpenLayers.METERS_PER_INCH,   //EPSG:9040
+    "IndianYard": 0.91439853074444079983 / OpenLayers.METERS_PER_INCH,   //EPSG:9084
+    "IndianYd37": 0.91439523 / OpenLayers.METERS_PER_INCH,   //EPSG:9085
+    "IndianYd62": 0.9143988 / OpenLayers.METERS_PER_INCH,   //EPSG:9086
+    "IndianYd75": 0.9143985 / OpenLayers.METERS_PER_INCH,   //EPSG:9087
+    "IndianFoot": 0.30479951 / OpenLayers.METERS_PER_INCH,   //EPSG:9080
+    "IndianFt37": 0.30479841 / OpenLayers.METERS_PER_INCH,   //EPSG:9081
+    "IndianFt62": 0.3047996 / OpenLayers.METERS_PER_INCH,   //EPSG:9082
+    "IndianFt75": 0.3047995 / OpenLayers.METERS_PER_INCH,   //EPSG:9083
+    "Mile": 1609.34721869443738887477 / OpenLayers.METERS_PER_INCH,
+    "IYard": 0.91440000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9096
+    "IMile": 1609.34400000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9093
+    "NautM": 1852.00000000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9030
+    "Lat-66": 110943.316488932731 / OpenLayers.METERS_PER_INCH,
+    "Lat-83": 110946.25736872234125 / OpenLayers.METERS_PER_INCH,
+    "Decimeter": 0.10000000000000000000 / OpenLayers.METERS_PER_INCH,
+    "Millimeter": 0.00100000000000000000 / OpenLayers.METERS_PER_INCH,
+    "Dekameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
+    "Decameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
+    "Hectometer": 100.00000000000000000000 / OpenLayers.METERS_PER_INCH,
+    "GermanMeter": 1.0000135965 / OpenLayers.METERS_PER_INCH,   //EPSG:9031
+    "CaGrid": 0.999738 / OpenLayers.METERS_PER_INCH,
+    "ClarkeChain": 20.1166194976 / OpenLayers.METERS_PER_INCH,   //EPSG:9038
+    "GunterChain": 20.11684023368047 / OpenLayers.METERS_PER_INCH,   //EPSG:9033
+    "BenoitChain": 20.116782494375872 / OpenLayers.METERS_PER_INCH,   //EPSG:9062
+    "SearsChain": 20.11676512155 / OpenLayers.METERS_PER_INCH,   //EPSG:9042
+    "ClarkeLink": 0.201166194976 / OpenLayers.METERS_PER_INCH,   //EPSG:9039
+    "GunterLink": 0.2011684023368047 / OpenLayers.METERS_PER_INCH,   //EPSG:9034
+    "BenoitLink": 0.20116782494375872 / OpenLayers.METERS_PER_INCH,   //EPSG:9063
+    "SearsLink": 0.2011676512155 / OpenLayers.METERS_PER_INCH,   //EPSG:9043
+    "Rod": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
+    "IntnlChain": 20.1168 / OpenLayers.METERS_PER_INCH,   //EPSG:9097
+    "IntnlLink": 0.201168 / OpenLayers.METERS_PER_INCH,   //EPSG:9098
+    "Perch": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
+    "Pole": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
+    "Furlong": 201.1684023368046 / OpenLayers.METERS_PER_INCH,
+    "Rood": 3.778266898 / OpenLayers.METERS_PER_INCH,
+    "CapeFoot": 0.3047972615 / OpenLayers.METERS_PER_INCH,
+    "Brealey": 375.00000000000000000000 / OpenLayers.METERS_PER_INCH,
+    "ModAmFt": 0.304812252984505969011938 / OpenLayers.METERS_PER_INCH,
+    "Fathom": 1.8288 / OpenLayers.METERS_PER_INCH,
+    "NautM-UK": 1853.184 / OpenLayers.METERS_PER_INCH,
+    "50kilometers": 50000.0 / OpenLayers.METERS_PER_INCH,
+    "150kilometers": 150000.0 / OpenLayers.METERS_PER_INCH
+});
 
-    /** 
-     * APIProperty: fontWeight
-     * {String} The font weight for the label.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-    
-    /**
-     * Property: fontStyle
-     * {String} The font style for the label.
-     * 
-     * No default set here.  Use OpenLayers.Renderer.defaultRenderer for defaults.
-     */
-
-    /**
-     * 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"
-    
+//unit abbreviations supported by PROJ.4
+OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
+    "mm": OpenLayers.INCHES_PER_UNIT["Meter"] / 1000.0,
+    "cm": OpenLayers.INCHES_PER_UNIT["Meter"] / 100.0,
+    "dm": OpenLayers.INCHES_PER_UNIT["Meter"] * 100.0,
+    "km": OpenLayers.INCHES_PER_UNIT["Meter"] * 1000.0,
+    "kmi": OpenLayers.INCHES_PER_UNIT["nmi"],    //International Nautical Mile
+    "fath": OpenLayers.INCHES_PER_UNIT["Fathom"], //International Fathom
+    "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-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
+    "ind-ft": OpenLayers.INCHES_PER_UNIT["IndianFt37"],  //Indian Foot
+    "ind-ch": 20.11669506 / OpenLayers.METERS_PER_INCH  //Indian Chain
 });
 
-/* ======================================================================
-    OpenLayers/Tween.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/Console.js
+/** 
+ * Constant: DOTS_PER_INCH
+ * {Integer} 72 (A sensible default)
  */
+OpenLayers.DOTS_PER_INCH = 72;
 
 /**
- * Namespace: OpenLayers.Tween
+ * Function: normalizeScale
+ * 
+ * Parameters:
+ * scale - {float}
+ * 
+ * Returns:
+ * {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 
+ *         1 / scale
  */
-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
-     *     are functions to be call during the animation. They are passed the
-     *     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
-     * duration - {int} duration of the tween (number of steps)
-     * options - {Object} hash of options (for example callbacks (start, eachStep, done))
-     */
-    start: function(begin, finish, duration, options) {
-        this.playing = true;
-        this.begin = begin;
-        this.finish = finish;
-        this.duration = duration;
-        this.callbacks = options.callbacks;
-        this.time = 0;
-        if (this.interval) {
-            window.clearInterval(this.interval);
-            this.interval = null;
-        }
-        if (this.callbacks && this.callbacks.start) {
-            this.callbacks.start.call(this, this.begin);
-        }
-        this.interval = window.setInterval(
-            OpenLayers.Function.bind(this.play, this), this.INTERVAL);
-    },
-    
-    /**
-     * APIMethod: stop
-     * Stops the Tween, and calls the done callback
-     *     Doesn't do anything if animation is already finished
-     */
-    stop: function() {
-        if (!this.playing) {
-            return;
-        }
-        
-        if (this.callbacks && this.callbacks.done) {
-            this.callbacks.done.call(this, this.finish);
-        }
-        window.clearInterval(this.interval);
-        this.interval = null;
-        this.playing = false;
-    },
-    
-    /**
-     * Method: play
-     * Calls the appropriate easing method
-     */
-    play: function() {
-        var value = {};
-        for (var i in this.begin) {
-            var b = this.begin[i];
-            var f = this.finish[i];
-            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) {
-            this.stop();
-        }
-    },
-    
-    /**
-     * Create empty functions for all easing methods.
-     */
-    CLASS_NAME: "OpenLayers.Tween"
-});
+OpenLayers.Util.normalizeScale = function (scale) {
+    var normScale = (scale > 1.0) ? (1.0 / scale) 
+                                  : scale;
+    return normScale;
+};
 
 /**
- * Namespace: OpenLayers.Easing
+ * Function: getResolutionFromScale
  * 
- * Credits:
- *      Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
+ * 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.  If the given scale is falsey, the returned resolution will
+ *     be undefined.
  */
-OpenLayers.Easing = {
-    /**
-     * Create empty functions for all easing methods.
-     */
-    CLASS_NAME: "OpenLayers.Easing"
+OpenLayers.Util.getResolutionFromScale = function (scale, units) {
+    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);        
+    }
+    return resolution;
 };
 
 /**
- * Namespace: OpenLayers.Easing.Linear
+ * 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 
+ *         parameters.
  */
-OpenLayers.Easing.Linear = {
-    
-    /**
-     * Function: easeIn
-     * 
-     * Parameters:
-     * t - {Float} time
-     * b - {Float} beginning position
-     * c - {Float} total change
-     * d - {Float} duration of the transition
-     */
-    easeIn: function(t, b, c, d) {
-        return c*t/d + b;
-    },
-    
-    /**
-     * Function: easeOut
-     * 
-     * Parameters:
-     * t - {Float} time
-     * b - {Float} beginning position
-     * c - {Float} total change
-     * d - {Float} duration of the transition
-     */
-    easeOut: function(t, b, c, d) {
-        return c*t/d + b;
-    },
-    
-    /**
-     * Function: easeInOut
-     * 
-     * Parameters:
-     * t - {Float} time
-     * b - {Float} beginning position
-     * c - {Float} total change
-     * d - {Float} duration of the transition
-     */
-    easeInOut: function(t, b, c, d) {
-        return c*t/d + b;
-    },
+OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
 
-    CLASS_NAME: "OpenLayers.Easing.Linear"
+    if (units == null) {
+        units = "degrees";
+    }
+
+    var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
+                    OpenLayers.DOTS_PER_INCH;
+    return scale;
 };
 
 /**
- * Namespace: OpenLayers.Easing.Expo
+ * Function: safeStopPropagation
+ * *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}
  */
-OpenLayers.Easing.Expo = {
-    
-    /**
-     * Function: easeIn
-     * 
-     * Parameters:
-     * t - {Float} time
-     * b - {Float} beginning position
-     * c - {Float} total change
-     * d - {Float} duration of the transition
-     */
-    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
-     * c - {Float} total change
-     * d - {Float} duration of the transition
-     */
-    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
-     * c - {Float} total change
-     * d - {Float} duration of the transition
-     */
-    easeInOut: function(t, b, c, d) {
-        if (t==0) return b;
-        if (t==d) return b+c;
-        if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
-        return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
-    },
-
-    CLASS_NAME: "OpenLayers.Easing.Expo"
+OpenLayers.Util.safeStopPropagation = function(evt) {
+    OpenLayers.Event.stop(evt, true);
 };
 
 /**
- * Namespace: OpenLayers.Easing.Quad
+ * Function: pagePositon
+ * Calculates the position of an element on the page (see
+ * http://code.google.com/p/doctype/wiki/ArticlePageOffset)
+ *
+ * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
+ * Copyright (c) 2006, Yahoo! Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use of this software in source and binary forms, with or
+ * without modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * 
+ * * 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.
+ * 
+ * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
+ *   used to endorse or promote products derived from this software without
+ *   specific prior written permission of Yahoo! Inc.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+ *
+ * Parameters:
+ * forElement - {DOMElement}
+ * 
+ * Returns:
+ * {Array} two item array, Left value then Top value.
  */
-OpenLayers.Easing.Quad = {
-    
-    /**
-     * Function: easeIn
-     * 
-     * Parameters:
-     * t - {Float} time
-     * b - {Float} beginning position
-     * c - {Float} total change
-     * d - {Float} duration of the transition
-     */
-    easeIn: function(t, b, c, d) {
-        return c*(t/=d)*t + b;
-    },
-    
-    /**
-     * Function: easeOut
-     * 
-     * Parameters:
-     * t - {Float} time
-     * b - {Float} beginning position
-     * c - {Float} total change
-     * d - {Float} duration of the transition
-     */
-    easeOut: function(t, b, c, d) {
-        return -c *(t/=d)*(t-2) + b;
-    },
-    
-    /**
-     * Function: easeInOut
-     * 
-     * Parameters:
-     * t - {Float} time
-     * b - {Float} beginning position
-     * c - {Float} total change
-     * d - {Float} duration of the transition
-     */
-    easeInOut: function(t, b, c, d) {
-        if ((t/=d/2) < 1) return c/2*t*t + b;
-        return -c/2 * ((--t)*(t-2) - 1) + b;
-    },
+OpenLayers.Util.pagePosition =  function(forElement) {
+    // NOTE: If element is hidden (display none or disconnected or any the
+    // ancestors are hidden) we get (0,0) by default but we still do the
+    // accumulation of scroll position.
 
-    CLASS_NAME: "OpenLayers.Easing.Quad"
-};
-/* ======================================================================
-    OpenLayers/Control/ArgParser.js
-   ====================================================================== */
+    var pos = [0, 0];
+    var viewportElement = OpenLayers.Util.getViewportElement();
+    if (!forElement || forElement == window || forElement == viewportElement) {
+        // viewport is always at 0,0 as that defined the coordinate system for
+        // this function - this avoids special case checks in the code below
+        return pos;
+    }
 
-/* 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. */
+    // Gecko browsers normally use getBoxObjectFor to calculate the position.
+    // When invoked for an element with an implicit absolute position though it
+    // can be off by one. Therefore the recursive implementation is used in
+    // those (relatively rare) cases.
+    var BUGGY_GECKO_BOX_OBJECT =
+        OpenLayers.IS_GECKO && document.getBoxObjectFor &&
+        OpenLayers.Element.getStyle(forElement, 'position') == 'absolute' &&
+        (forElement.style.top == '' || forElement.style.left == '');
 
+    var parent = null;
+    var box;
 
-/**
- * @requires OpenLayers/Control.js
- */
+    if (forElement.getBoundingClientRect) { // IE
+        box = forElement.getBoundingClientRect();
+        var scrollTop = viewportElement.scrollTop;
+        var scrollLeft = viewportElement.scrollLeft;
 
-/**
- * Class: OpenLayers.Control.ArgParser
- * 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. 
- *
- * Inherits from:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, {
+        pos[0] = box.left + scrollLeft;
+        pos[1] = box.top + scrollTop;
 
-    /**
-     * Parameter: center
-     * {<OpenLayers.LonLat>}
-     */
-    center: null,
-    
-    /**
-     * Parameter: zoom
-     * {int}
-     */
-    zoom: null,
+    } else if (document.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT) { // gecko
+        // Gecko ignores the scroll values for ancestors, up to 1.9.  See:
+        // https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and
+        // https://bugzilla.mozilla.org/show_bug.cgi?id=330619
 
-    /**
-     * Parameter: layers 
-     * {Array(<OpenLayers.Layer>)}
-     */
-    layers: null,
-    
-    /** 
-     * APIProperty: displayProjection
-     * {<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
-     *     projection.
-     *
-     *     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. 
-     */
-    displayProjection: null, 
+        box = document.getBoxObjectFor(forElement);
+        var vpBox = document.getBoxObjectFor(viewportElement);
+        pos[0] = box.screenX - vpBox.screenX;
+        pos[1] = box.screenY - vpBox.screenY;
 
-    /**
-     * Constructor: OpenLayers.Control.ArgParser
-     *
-     * Parameters:
-     * options - {Object}
-     */
-    initialize: function(options) {
-        OpenLayers.Control.prototype.initialize.apply(this, arguments);
-    },
-
-    /**
-     * Method: setMap
-     * Set the map property for the control. 
-     * 
-     * Parameters:
-     * map - {<OpenLayers.Map>} 
-     */
-    setMap: function(map) {
-        OpenLayers.Control.prototype.setMap.apply(this, arguments);
-
-        //make sure we dont already have an arg parser attached
-        for(var i=0, len=this.map.controls.length; i<len; i++) {
-            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 
-                // override the displayProjection to be the one added to the
-                // map. 
-                if (control.displayProjection != this.displayProjection) {
-                    this.displayProjection = control.displayProjection;
-                }    
-                
-                break;
+    } else { // safari/opera
+        pos[0] = forElement.offsetLeft;
+        pos[1] = forElement.offsetTop;
+        parent = forElement.offsetParent;
+        if (parent != forElement) {
+            while (parent) {
+                pos[0] += parent.offsetLeft;
+                pos[1] += parent.offsetTop;
+                parent = parent.offsetParent;
             }
         }
-        if (i == this.map.controls.length) {
 
-            var args = OpenLayers.Util.getParameters();
-            // 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, 
-                                         this.configureLayers);
-                this.configureLayers();
-            }
-            if (args.lat && args.lon) {
-                this.center = new OpenLayers.LonLat(parseFloat(args.lon),
-                                                    parseFloat(args.lat));
-                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.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.setCenter);
-            
-            if (this.displayProjection) {
-                this.center.transform(this.displayProjection, 
-                                      this.map.getProjectionObject()); 
-            }      
+        var browser = OpenLayers.BROWSER_NAME;
 
-            this.map.setCenter(this.center, this.zoom);
+        // opera & (safari absolute) incorrectly account for body offsetTop
+        if (browser == "opera" || (browser == "safari" &&
+              OpenLayers.Element.getStyle(forElement, 'position') == 'absolute')) {
+            pos[1] -= document.body.offsetTop;
         }
-    },
 
-    /** 
-     * Method: configureLayers
-     * 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) { 
-            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") ) {
-                    layer.setVisibility(c == "T");
-                }
+        // accumulate the scroll positions for everything but the body element
+        parent = forElement.offsetParent;
+        while (parent && parent != document.body) {
+            pos[0] -= parent.scrollLeft;
+            // see https://bugs.opera.com/show_bug.cgi?id=249965
+            if (browser != "opera" || parent.tagName != 'TR') {
+                pos[1] -= parent.scrollTop;
             }
+            parent = parent.offsetParent;
         }
-    },     
+    }
+    
+    return pos;
+};
 
-    CLASS_NAME: "OpenLayers.Control.ArgParser"
-});
-/* ======================================================================
-    OpenLayers/Control/MousePosition.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/Control.js
+ * Function: getViewportElement
+ * Returns die viewport element of the document. The viewport element is
+ * usually document.documentElement, except in IE,where it is either
+ * document.body or document.documentElement, depending on the document's
+ * compatibility mode (see
+ * http://code.google.com/p/doctype/wiki/ArticleClientViewportElement)
  */
+OpenLayers.Util.getViewportElement = function() {
+    var viewportElement = arguments.callee.viewportElement;
+    if (viewportElement == undefined) {
+        viewportElement = (OpenLayers.BROWSER_NAME == "msie" &&
+            document.compatMode != 'CSS1Compat') ? document.body :
+            document.documentElement;
+        arguments.callee.viewportElement = viewportElement;
+    }
+    return viewportElement;
+};
 
-/**
- * Class: OpenLayers.Control.MousePosition
- * The MousePosition control displays geographic coordinates of the mouse
- * pointer, as it is moved about the map.
+/** 
+ * Function: isEquivalentUrl
+ * Test two URLs for equivalence. 
+ * 
+ * Setting 'ignoreCase' allows for case-independent comparison.
+ * 
+ * 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) 
+ *  - Arguments (so they can be out of order)
+ *  
+ * Parameters:
+ * url1 - {String}
+ * url2 - {String}
+ * options - {Object} Allows for customization of comparison:
+ *                    'ignoreCase' - Default is True
+ *                    'ignorePort80' - Default is True
+ *                    'ignoreHash' - Default is True
  *
- * Inherits from:
- *  - <OpenLayers.Control>
+ * Returns:
+ * {Boolean} Whether or not the two URLs are equivalent
  */
-OpenLayers.Control.MousePosition = OpenLayers.Class(OpenLayers.Control, {
-    
-    /**
-     * APIProperty: autoActivate
-     * {Boolean} Activate the control when it is added to a map.  Default is
-     *     true.
-     */
-    autoActivate: true,
+OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
+    options = options || {};
 
-    /** 
-     * Property: element
-     * {DOMElement} 
-     */
-    element: null,
-    
-    /** 
-     * APIProperty: prefix
-     * {String}
-     */
-    prefix: '',
-    
-    /** 
-     * APIProperty: separator
-     * {String}
-     */
-    separator: ', ',
-    
-    /** 
-     * APIProperty: suffix
-     * {String}
-     */
-    suffix: '',
-    
-    /** 
-     * APIProperty: numDigits
-     * {Integer}
-     */
-    numDigits: 5,
-    
-    /** 
-     * APIProperty: granularity
-     * {Integer} 
-     */
-    granularity: 10,
+    OpenLayers.Util.applyDefaults(options, {
+        ignoreCase: true,
+        ignorePort80: true,
+        ignoreHash: true
+    });
 
-    /**
-     * APIProperty: emptyString 
-     * {String} Set this to some value to set when the mouse is outside the
-     *     map.
-     */
-    emptyString: null,
-    
-    /** 
-     * Property: lastXy
-     * {<OpenLayers.Pixel>}
-     */
-    lastXy: null,
+    var urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
+    var urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
 
-    /**
-     * APIProperty: displayProjection
-     * {<OpenLayers.Projection>} The projection in which the 
-     * mouse position is displayed
-     */
-    displayProjection: null, 
-    
-    /**
-     * Constructor: OpenLayers.Control.MousePosition
-     * 
-     * Parameters:
-     * options - {Object} Options for control.
-     */
-    initialize: function(options) {
-        OpenLayers.Control.prototype.initialize.apply(this, arguments);
-    },
+    //compare all keys except for "args" (treated below)
+    for(var key in urlObj1) {
+        if(key !== "args") {
+            if(urlObj1[key] != urlObj2[key]) {
+                return false;
+            }
+        }
+    }
 
-    /**
-     * Method: destroy
-     */
-     destroy: function() {
-         this.deactivate();
-         OpenLayers.Control.prototype.destroy.apply(this, arguments);
-     },
-
-    /**
-     * APIMethod: activate
-     */
-    activate: function() {
-        if (OpenLayers.Control.prototype.activate.apply(this, arguments)) {
-            this.map.events.register('mousemove', this, this.redraw);
-            this.map.events.register('mouseout', this, this.reset);
-            this.redraw();
-            return true;
-        } else {
+    // compare search args - irrespective of order
+    for(var key in urlObj1.args) {
+        if(urlObj1.args[key] != urlObj2.args[key]) {
             return false;
         }
-    },
+        delete urlObj2.args[key];
+    }
+    // urlObj2 shouldn't have any args left
+    for(var key in urlObj2.args) {
+        return false;
+    }
     
-    /**
-     * APIMethod: deactivate
-     */
-    deactivate: function() {
-        if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
-            this.map.events.unregister('mousemove', this, this.redraw);
-            this.map.events.unregister('mouseout', this, this.reset);
-            this.element.innerHTML = "";
-            return true;
-        } else {
-            return false;
-        }
-    },
+    return true;
+};
 
-    /**
-     * Method: draw
-     * {DOMElement}
-     */    
-    draw: function() {
-        OpenLayers.Control.prototype.draw.apply(this, arguments);
+/**
+ * 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 
+ *          and ready for comparison
+ */
+OpenLayers.Util.createUrlObject = function(url, options) {
+    options = options || {};
 
-        if (!this.element) {
-            this.div.left = "";
-            this.div.top = "";
-            this.element = this.div;
-        }
-        
-        return this.div;
-    },
-   
-    /**
-     * Method: redraw  
-     */
-    redraw: function(evt) {
-
-        var lonLat;
-
-        if (evt == null) {
-            this.reset();
-            return;
+    // deal with relative urls first
+    if(!(/^\w+:\/\//).test(url)) {
+        var loc = window.location;
+        var port = loc.port ? ":" + loc.port : "";
+        var fullUrl = loc.protocol + "//" + loc.host.split(":").shift() + port;
+        if(url.indexOf("/") === 0) {
+            // full pathname
+            url = fullUrl + url;
         } else {
-            if (this.lastXy == null ||
-                Math.abs(evt.xy.x - this.lastXy.x) > this.granularity ||
-                Math.abs(evt.xy.y - this.lastXy.y) > this.granularity)
-            {
-                this.lastXy = evt.xy;
-                return;
-            }
-
-            lonLat = this.map.getLonLatFromPixel(evt.xy);
-            if (!lonLat) { 
-                // map has not yet been properly initialized
-                return;
-            }    
-            if (this.displayProjection) {
-                lonLat.transform(this.map.getProjectionObject(), 
-                                 this.displayProjection );
-            }      
-            this.lastXy = evt.xy;
-            
+            // relative to current path
+            var parts = loc.pathname.split("/");
+            parts.pop();
+            url = fullUrl + parts.join("/") + "/" + url;
         }
-        
-        var newHtml = this.formatOutput(lonLat);
+    }
+  
+    if (options.ignoreCase) {
+        url = url.toLowerCase(); 
+    }
 
-        if (newHtml != this.element.innerHTML) {
-            this.element.innerHTML = newHtml;
-        }
-    },
+    var a = document.createElement('a');
+    a.href = url;
+    
+    var urlObject = {};
+    
+    //host (without port)
+    urlObject.host = a.host.split(":").shift();
 
-    /**
-     * Method: reset
-     */
-    reset: function(evt) {
-        if (this.emptyString != null) {
-            this.element.innerHTML = this.emptyString;
-        }
-    },
+    //protocol
+    urlObject.protocol = a.protocol;  
 
-    /**
-     * Method: formatOutput
-     * Override to provide custom display output
-     *
-     * Parameters:
-     * lonLat - {<OpenLayers.LonLat>} Location to display
-     */
-    formatOutput: function(lonLat) {
-        var digits = parseInt(this.numDigits);
-        var newHtml =
-            this.prefix +
-            lonLat.lon.toFixed(digits) +
-            this.separator + 
-            lonLat.lat.toFixed(digits) +
-            this.suffix;
-        return newHtml;
-    },
+    //port (get uniform browser behavior with port 80 here)
+    if(options.ignorePort80) {
+        urlObject.port = (a.port == "80" || a.port == "0") ? "" : a.port;
+    } else {
+        urlObject.port = (a.port == "" || a.port == "0") ? "80" : a.port;
+    }
 
-    CLASS_NAME: "OpenLayers.Control.MousePosition"
-});
-/* ======================================================================
-    OpenLayers/Control/PanZoom.js
-   ====================================================================== */
+    //hash
+    urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash;  
+    
+    //args
+    var queryString = a.search;
+    if (!queryString) {
+        var qMark = url.indexOf("?");
+        queryString = (qMark != -1) ? url.substr(qMark) : "";
+    }
+    urlObject.args = OpenLayers.Util.getParameters(queryString);
 
-/* 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. */
+    //pathname (uniform browser behavior with leading "/")
+    urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname;
+    
+    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)) 
+                                  : url.substr(0, qMark);
+    }
+    return head;
+};
 
 /**
- * @requires OpenLayers/Control.js
+ * Constant: IS_GECKO
+ * {Boolean} True if the userAgent reports the browser to use the Gecko engine
  */
+OpenLayers.IS_GECKO = (function() {
+    var ua = navigator.userAgent.toLowerCase();
+    return ua.indexOf("webkit") == -1 && ua.indexOf("gecko") != -1;
+})();
 
 /**
- * Class: OpenLayers.Control.PanZoom
- * The PanZoom is a visible control, composed of a
- * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomPanel>. By
- * default it is drawn in the upper left corner of the map.
- *
- * Inherits from:
- *  - <OpenLayers.Control>
+ * Constant: BROWSER_NAME
+ * {String}
+ * A substring of the navigator.userAgent property.  Depending on the userAgent
+ *     property, this will be the empty string or one of the following:
+ *     * "opera" -- Opera
+ *     * "msie"  -- Internet Explorer
+ *     * "safari" -- Safari
+ *     * "firefox" -- FireFox
+ *     * "mozilla" -- Mozilla
  */
-OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, {
+OpenLayers.BROWSER_NAME = (function() {
+    var name = "";
+    var ua = navigator.userAgent.toLowerCase();
+    if (ua.indexOf("opera") != -1) {
+        name = "opera";
+    } else if (ua.indexOf("msie") != -1) {
+        name = "msie";
+    } else if (ua.indexOf("safari") != -1) {
+        name = "safari";
+    } else if (ua.indexOf("mozilla") != -1) {
+        if (ua.indexOf("firefox") != -1) {
+            name = "firefox";
+        } else {
+            name = "mozilla";
+        }
+    }
+    return name;
+})();
 
-    /** 
-     * APIProperty: slideFactor
-     * {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,
+/**
+ * Function: getBrowserName
+ * 
+ * Returns:
+ * {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 
+ *           return an empty string.
+ */
+OpenLayers.Util.getBrowserName = function() {
+    return OpenLayers.BROWSER_NAME;
+};
 
-    /** 
-     * APIProperty: slideRatio
-     * {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. 
-     */
-    slideRatio: null,
-
-    /** 
-     * Property: buttons
-     * {Array(DOMElement)} Array of Button Divs 
-     */
-    buttons: null,
-
-    /** 
-     * Property: position
-     * {<OpenLayers.Pixel>} 
-     */
-    position: null,
-
-    /**
-     * Constructor: OpenLayers.Control.PanZoom
-     * 
-     * Parameters:
-     * options - {Object}
-     */
-    initialize: function(options) {
-        this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
-                                             OpenLayers.Control.PanZoom.Y);
-        OpenLayers.Control.prototype.initialize.apply(this, arguments);
-    },
-
-    /**
-     * APIMethod: destroy
-     */
-    destroy: function() {
-        OpenLayers.Control.prototype.destroy.apply(this, arguments);
-        this.removeButtons();
-        this.buttons = null;
-        this.position = null;
-    },
-
-    /**
-     * Method: draw
-     *
-     * Parameters:
-     * px - {<OpenLayers.Pixel>} 
-     * 
-     * Returns:
-     * {DOMElement} A reference to the container div for the PanZoom control.
-     */
-    draw: function(px) {
-        // initialize our internal div
-        OpenLayers.Control.prototype.draw.apply(this, arguments);
-        px = this.position;
-
-        // place the controls
-        this.buttons = [];
-
-        var sz = new OpenLayers.Size(18,18);
-        var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
-
-        this._addButton("panup", "north-mini.png", centered, sz);
-        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", 
-                        centered.add(0, sz.h*2), sz);
-        this._addButton("zoomin", "zoom-plus-mini.png", 
-                        centered.add(0, sz.h*3+5), sz);
-        this._addButton("zoomworld", "zoom-world-mini.png", 
-                        centered.add(0, sz.h*4+5), sz);
-        this._addButton("zoomout", "zoom-minus-mini.png", 
-                        centered.add(0, sz.h*5+5), sz);
-        return this.div;
-    },
+/**
+ * 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 
+ *     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 
+ *     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. 
+ * 
+ * Returns:
+ * {OpenLayers.Size}
+ */
+OpenLayers.Util.getRenderedDimensions = function(contentHTML, size, options) {
     
-    /**
-     * Method: _addButton
-     * 
-     * Parameters:
-     * 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.
-     */
-    _addButton:function(id, img, xy, sz) {
-        var imgLocation = OpenLayers.Util.getImagesLocation() + img;
-        var btn = OpenLayers.Util.createAlphaImageDiv(
-                                    this.id + "_" + id, 
-                                    xy, sz, imgLocation, "absolute");
+    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;
 
-        //we want to add the outer div
-        this.div.appendChild(btn);
-
-        OpenLayers.Event.observe(btn, "mousedown", 
-            OpenLayers.Function.bindAsEventListener(this.buttonDown, btn));
-        OpenLayers.Event.observe(btn, "dblclick", 
-            OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
-        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() {
-                return slideFactorPixels;
-            };
-        } else {
-            var slideRatio = this.slideRatio;
-            var getSlideFactor = function(dim) {
-                return this.map.getSize()[dim] * slideRatio;
-            };
+    //fix a dimension, if specified.
+    if (size) {
+        if (size.w) {
+            w = size.w;
+            container.style.width = w + "px";
+        } else if (size.h) {
+            h = size.h;
+            container.style.height = h + "px";
         }
+    }
 
-        btn.getSlideFactor = getSlideFactor;
-
-        //we want to remember/reference the outer div
-        this.buttons.push(btn);
-        return btn;
-    },
+    //add css classes, if specified
+    if (options && options.displayClass) {
+        container.className = options.displayClass;
+    }
     
-    /**
-     * 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);
-    },
+    // create temp content div and assign content
+    var content = document.createElement("div");
+    content.innerHTML = contentHTML;
     
-    /**
-     * Method: removeButtons
-     */
-    removeButtons: function() {
-        for(var i=this.buttons.length-1; i>=0; --i) {
-            this._removeButton(this.buttons[i]);
+    // we need overflow visible when calculating the size
+    content.style.overflow = "visible";
+    if (content.childNodes) {
+        for (var i=0, l=content.childNodes.length; i<l; i++) {
+            if (!content.childNodes[i].style) continue;
+            content.childNodes[i].style.overflow = "visible";
         }
-    },
+    }
     
-    /**
-     * Method: doubleClick
-     *
-     * Parameters:
-     * evt - {Event} 
-     *
-     * Returns:
-     * {Boolean}
-     */
-    doubleClick: function (evt) {
-        OpenLayers.Event.stop(evt);
-        return false;
-    },
+    // add content to restricted container 
+    container.appendChild(content);
     
-    /**
-     * Method: buttonDown
-     *
-     * Parameters:
-     * evt - {Event} 
-     */
-    buttonDown: function (evt) {
-        if (!OpenLayers.Event.isLeftClick(evt)) {
-            return;
+    // 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;
+    var parent = container.parentNode;
+    while (parent && parent.tagName.toLowerCase()!="body") {
+        var parentPosition = OpenLayers.Element.getStyle(parent, "position");
+        if(parentPosition == "absolute") {
+            parentHasPositionAbsolute = true;
+            break;
+        } else if (parentPosition && parentPosition != "static") {
+            break;
         }
+        parent = parent.parentNode;
+    }
 
-        switch (this.action) {
-            case "panup": 
-                this.map.pan(0, -this.getSlideFactor("h"));
-                break;
-            case "pandown": 
-                this.map.pan(0, this.getSlideFactor("h"));
-                break;
-            case "panleft": 
-                this.map.pan(-this.getSlideFactor("w"), 0);
-                break;
-            case "panright": 
-                this.map.pan(this.getSlideFactor("w"), 0);
-                break;
-            case "zoomin": 
-                this.map.zoomIn(); 
-                break;
-            case "zoomout": 
-                this.map.zoomOut(); 
-                break;
-            case "zoomworld": 
-                this.map.zoomToMaxExtent(); 
-                break;
-        }
+    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);
+    }
 
-        OpenLayers.Event.stop(evt);
-    },
+    // remove elements
+    container.removeChild(content);
+    containerElement.removeChild(container);
+    
+    return new OpenLayers.Size(w, h);
+};
 
-    CLASS_NAME: "OpenLayers.Control.PanZoom"
-});
-
 /**
- * Constant: X
+ * APIFunction: getScrollbarWidth
+ * This function has been modified by the OpenLayers from the original version,
+ *     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. 
+ * 
+ * Returns:
  * {Integer}
  */
-OpenLayers.Control.PanZoom.X = 4;
+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';
+        scr.style.top = '-1000px';
+        scr.style.left = '-1000px';
+        scr.style.width = '100px';
+        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;
+    }
 
-/**
- * Constant: Y
- * {Integer}
- */
-OpenLayers.Control.PanZoom.Y = 4;
-/* ======================================================================
-    OpenLayers/Control/ScaleLine.js
-   ====================================================================== */
+    return scrollbarWidth;
+};
 
-/* 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
- */
-
-/**
- * Class: OpenLayers.Control.ScaleLine
- * 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.
+ * 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
  * 
- * Inherits from:
- *  - <OpenLayers.Control>
- *  
- * Is a very close copy of:
- *  - <OpenLayers.Control.Scale>
+ * Returns:
+ * {String} the coordinate value formatted as a string
  */
-OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, {
+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);
 
-    /**
-     * Property: maxWidth
-     * {Integer} Maximum width of the scale line in pixels.  Default is 100.
-     */
-    maxWidth: 100,
+    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;
 
-    /**
-     * Property: topOutUnits
-     * {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.
-     */
-    topInUnits: "m",
+    if( coordinatedegrees < 10 ) {
+        coordinatedegrees = "0" + coordinatedegrees;
+    }
+    var str = coordinatedegrees + "\u00B0";
 
-    /**
-     * Property: bottomOutUnits
-     * {String} Units for zoomed out on bottom bar.  Default is mi.
-     */
-    bottomOutUnits: "mi",
-
-    /**
-     * Property: bottomInUnits
-     * {String} Units for zoomed in on bottom bar.  Default is ft.
-     */
-    bottomInUnits: "ft",
-    
-    /**
-     * Property: eTop
-     * {DOMElement}
-     */
-    eTop: null,
-
-    /**
-     * Property: eBottom
-     * {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]);     
-    },
-
-    /**
-     * Method: draw
-     * 
-     * Returns:
-     * {DOMElement}
-     */
-    draw: function() {
-        OpenLayers.Control.prototype.draw.apply(this, arguments);
-        if (!this.eTop) {
-            // stick in the top bar
-            this.eTop = document.createElement("div");
-            this.eTop.className = this.displayClass + "Top";
-            var theLen = this.topInUnits.length;
-            this.div.appendChild(this.eTop);
-            if((this.topOutUnits == "") || (this.topInUnits == "")) {
-                this.eTop.style.visibility = "hidden";
-            } else {
-                this.eTop.style.visibility = "visible";
+    if (dmsOption.indexOf('dm') >= 0) {
+        if( coordinateminutes < 10 ) {
+            coordinateminutes = "0" + coordinateminutes;
+        }
+        str += coordinateminutes + "'";
+  
+        if (dmsOption.indexOf('dms') >= 0) {
+            if( coordinateseconds < 10 ) {
+                coordinateseconds = "0" + coordinateseconds;
             }
-
-            // and the bottom bar
-            this.eBottom = document.createElement("div");
-            this.eBottom.className = this.displayClass + "Bottom";
-            this.div.appendChild(this.eBottom);
-            if((this.bottomOutUnits == "") || (this.bottomInUnits == "")) {
-                this.eBottom.style.visibility = "hidden";
-            } else {
-                this.eBottom.style.visibility = "visible";
-            }
+            str += coordinateseconds + '"';
         }
-        this.map.events.register('moveend', this, this.update);
-        this.update();
-        return this.div;
-    },
+    }
+    
+    if (axis == "lon") {
+        str += coordinate < 0 ? OpenLayers.i18n("W") : OpenLayers.i18n("E");
+    } else {
+        str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N");
+    }
+    return str;
+};
 
-    /** 
-     * 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)
-     */
-    getBarLen: function(maxLen) {
-        // 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);
-
-        // right, put it into the correct bracket
-        var barLen;
-        if(firstChar > 5) {
-            barLen = 5;
-        } else if(firstChar > 2) {
-            barLen = 2;
-        } else {
-            barLen = 1;
-        }
-
-        // scale it up the correct power of 10
-        return barLen * pow10;
-    },
-
-    /**
-     * Method: update
-     * Update the size of the bars, and the labels they contain.
-     */
-    update: function() {
-        var res = this.map.getResolution();
-        if (!res) {
-            return;
-        }
-
-        var curMapUnits = this.map.getUnits();
-        var inches = OpenLayers.INCHES_PER_UNIT;
-
-        // 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     
-        var topUnits;
-        var bottomUnits;
-        if(maxSizeData > 100000) {
-            topUnits = this.topOutUnits;
-            bottomUnits = this.bottomOutUnits;
-        } else {
-            topUnits = this.topInUnits;
-            bottomUnits = this.bottomInUnits;
-        }
-
-        // and to map units units
-        var topMax = maxSizeData / inches[topUnits];
-        var bottomMax = maxSizeData / inches[bottomUnits];
-
-        // now trim this down to useful block length
-        var topRounded = this.getBarLen(topMax);
-        var bottomRounded = this.getBarLen(bottomMax);
-
-        // and back to display units
-        topMax = topRounded / inches[curMapUnits] * inches[topUnits];
-        bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits];
-
-        // and to pixel units
-        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.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"
-});
-
 /* ======================================================================
     OpenLayers/Events.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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. */
@@ -12226,8 +5114,8 @@
      * Construct an OpenLayers.Events object.
      *
      * Parameters:
-     * object - {Object} The js object to which this Events object  is being
-     * added element - {DOMElement} A dom element to respond to browser events
+     * 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 
      * fallThrough - {Boolean} Allow events to fall through after these have
      *                         been handled?
@@ -12519,7 +5407,7 @@
 
         // fast path
         if(!listeners || listeners.length == 0) {
-            return;
+            return undefined;
         }
 
         // prep evt object with object & div references
@@ -12535,7 +5423,8 @@
         // execute all callbacks registered for specified type
         // get a clone of the listeners array to
         // allow for splicing during callbacks
-        var listeners = listeners.slice(), continueChain;
+        listeners = listeners.slice();
+        var continueChain;
         for (var i=0, len=listeners.length; i<len; i++) {
             var callback = listeners[i];
             // bind the context to callback.obj
@@ -12563,10 +5452,15 @@
      * evt - {Event} 
      */
     handleBrowserEvent: function (evt) {
+        var type = evt.type, listeners = this.listeners[type];
+        if(!listeners || listeners.length == 0) {
+            // noone's listening, bail out
+            return;
+        }
         if (this.includeXY) {
             evt.xy = this.getMousePosition(evt);
         } 
-        this.triggerEvent(evt.type, evt);
+        this.triggerEvent(type, evt);
     },
 
     /**
@@ -12600,11 +5494,10 @@
         }
         
         if (!this.element.scrolls) {
+            var viewportElement = OpenLayers.Util.getViewportElement();
             this.element.scrolls = [
-                (document.documentElement.scrollLeft
-                         || document.body.scrollLeft),
-                (document.documentElement.scrollTop
-                         || document.body.scrollTop)
+                viewportElement.scrollLeft,
+                viewportElement.scrollTop
             ];
         }
 
@@ -12617,8 +5510,6 @@
         
         if (!this.element.offsets) {
             this.element.offsets = OpenLayers.Util.pagePosition(this.element);
-            this.element.offsets[0] += this.element.scrolls[0];
-            this.element.offsets[1] += this.element.scrolls[1];
         }
         return new OpenLayers.Pixel(
             (evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]
@@ -12631,4540 +5522,344 @@
     CLASS_NAME: "OpenLayers.Events"
 });
 /* ======================================================================
-    OpenLayers/Format.js
+    OpenLayers/Tween.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/BaseTypes/Class.js
  * @requires OpenLayers/Console.js
  */
 
 /**
- * Class: OpenLayers.Format
- * Base class for format reading/writing a variety of formats.  Subclasses
- *     of OpenLayers.Format are expected to have read and write methods.
+ * Namespace: OpenLayers.Tween
  */
-OpenLayers.Format = OpenLayers.Class({
+OpenLayers.Tween = OpenLayers.Class({
     
     /**
-     * Property: options
-     * {Object} A reference to options passed to the constructor.
+     * Constant: INTERVAL
+     * {int} Interval in milliseconds between 2 steps
      */
-    options: null,
+    INTERVAL: 10,
     
     /**
-     * APIProperty: externalProjection
-     * {<OpenLayers.Projection>} When passed a externalProjection and
-     *     internalProjection, the format will reproject the geometries it
-     *     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 
-     *     provided via proj4js or via a custom transformation function. See
-     *     {<OpenLayers.Projection.addTransform>} for more information on
-     *     custom transformations.
+     * APIProperty: easing
+     * {<OpenLayers.Easing>(Function)} Easing equation used for the animation
+     *     Defaultly set to OpenLayers.Easing.Expo.easeOut
      */
-    externalProjection: null,
-
-    /**
-     * APIProperty: internalProjection
-     * {<OpenLayers.Projection>} When passed a externalProjection and
-     *     internalProjection, the format will reproject the geometries it
-     *     reads or writes. The internalProjection is the projection used by
-     *     the geometries which are returned by read or which are passed into
-     *     write.  In order to reproject, a projection transformation function
-     *     for the 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.
-     */
-    internalProjection: null,
-
-    /**
-     * APIProperty: data
-     * {Object} When <keepData> is true, this is the parsed string sent to
-     *     <read>.
-     */
-    data: null,
-
-    /**
-     * APIProperty: keepData
-     * {Object} Maintain a reference (<data>) to the most recently read data.
-     *     Default is false.
-     */
-    keepData: false,
-
-    /**
-     * Constructor: OpenLayers.Format
-     * Instances of this class are not useful.  See one of the subclasses.
-     *
-     * Parameters:
-     * options - {Object} An optional object with properties to set on the
-     *           format
-     *
-     * Valid options:
-     * keepData - {Boolean} If true, upon <read>, the data property will be
-     *     set to the parsed object (e.g. the json or xml object).
-     *
-     * Returns:
-     * An instance of OpenLayers.Format
-     */
-    initialize: function(options) {
-        OpenLayers.Util.extend(this, options);
-        this.options = options;
-    },
+    easing: null,
     
     /**
-     * APIMethod: destroy
-     * Clean up.
+     * APIProperty: begin
+     * {Object} Values to start the animation with
      */
-    destroy: function() {
-    },
-
-    /**
-     * Method: read
-     * Read data from a string, and return an object whose type depends on the
-     * subclass. 
-     * 
-     * Parameters:
-     * data - {string} Data to read/parse.
-     *
-     * Returns:
-     * Depends on the subclass
-     */
-    read: function(data) {
-        OpenLayers.Console.userError(OpenLayers.i18n("readNotImplemented"));
-    },
+    begin: null,
     
     /**
-     * Method: write
-     * Accept an object, and return a string. 
-     *
-     * Parameters:
-     * object - {Object} Object to be serialized
-     *
-     * Returns:
-     * {String} A string representation of the object.
+     * APIProperty: finish
+     * {Object} Values to finish the animation with
      */
-    write: function(object) {
-        OpenLayers.Console.userError(OpenLayers.i18n("writeNotImplemented"));
-    },
-
-    CLASS_NAME: "OpenLayers.Format"
-});     
-/* ======================================================================
-    OpenLayers/Lang/en.js
-   ====================================================================== */
-
-/**
- * @requires OpenLayers/Lang.js
- */
-
-/**
- * Namespace: OpenLayers.Lang["en"]
- * Dictionary for English.  Keys for entries are used in calls to
- *     <OpenLayers.Lang.translate>.  Entry bodies are normal strings or
- *     strings formatted for use with <OpenLayers.String.format> calls.
- */
-OpenLayers.Lang.en = {
-
-    'unhandledRequest': "Unhandled request return ${statusText}",
-
-    'permalink': "Permalink",
-
-    'overlays': "Overlays",
-
-    'baseLayer': "Base Layer",
-
-    'sameProjection':
-        "The overview map only works when it is in the same projection as the main map",
-
-    'readNotImplemented': "Read not implemented.",
-
-    'writeNotImplemented': "Write not implemented.",
-
-    'noFID': "Can't update a feature for which there is no FID.",
-
-    'errorLoadingGML': "Error in loading GML file ${url}",
-
-    'browserNotSupported':
-        "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",
-
-    'componentShouldBe': "addFeatures : component should be an ${geomType}",
-
-    // console message
-    'getFeatureError':
-        "getFeatureFromEvent called on layer with no renderer. This usually means you " +
-        "destroyed a layer, but not some handler which is associated with it.",
-
-    // console message
-    'minZoomLevelError':
-        "The minZoomLevel property is only intended for use " +
-        "with the FixedZoomLevels-descendent layers. That this " +
-        "wfs layer checks for minZoomLevel is a relic of the" +
-        "past. We cannot, however, remove it without possibly " +
-        "breaking OL based applications that may depend on it." +
-        " Therefore we are deprecating it -- the minZoomLevel " +
-        "check below will be removed at 3.0. Please instead " +
-        "use min/max resolution setting as described here: " +
-        "http://trac.openlayers.org/wiki/SettingZoomLevels",
-
-    'commitSuccess': "WFS Transaction: SUCCESS ${response}",
-
-    'commitFailed': "WFS Transaction: FAILED ${response}",
-
-    'googleWarning':
-        "The Google Layer was unable to load correctly.<br><br>" +
-        "To get rid of this message, select a new BaseLayer " +
-        "in the layer switcher in the upper-right corner.<br><br>" +
-        "Most likely, this is because the Google Maps library " +
-        "script was either not included, or does not contain the " +
-        "correct API key for your site.<br><br>" +
-        "Developers: For help getting this working correctly, " +
-        "<a href='http://trac.openlayers.org/wiki/Google' " +
-        "target='_blank'>click here</a>",
-
-    'getLayerWarning':
-        "The ${layerType} Layer was unable to load correctly.<br><br>" +
-        "To get rid of this message, select a new BaseLayer " +
-        "in the layer switcher in the upper-right corner.<br><br>" +
-        "Most likely, this is because the ${layerLib} library " +
-        "script was not correctly included.<br><br>" +
-        "Developers: For help getting this working correctly, " +
-        "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
-        "target='_blank'>click here</a>",
-
-    'scale': "Scale = 1 : ${scaleDenom}",
+    finish: null,
     
-    //labels for the graticule control
-    'W': 'W',
-    'E': 'E',
-    'N': 'N',
-    'S': 'S',
-    'graticule': 'Graticule',
-
-    // console message
-    'layerAlreadyAdded':
-        "You tried to add the layer: ${layerName} to the map, but it has already been added",
-
-    // console message
-    '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 " + 
-        "basemaps, but that functionality should now be achieved by using " +
-        "Spherical Mercator support. More information is available from " +
-        "http://trac.openlayers.org/wiki/SphericalMercator.",
-
-    // console message
-    'methodDeprecated':
-        "This method has been deprecated and will be removed in 3.0. " +
-        "Please use ${newMethod} instead.",
-
-    // console message
-    'boundsAddError': "You must pass both x and y values to the add function.",
-
-    // console message
-    'lonlatAddError': "You must pass both lon and lat values to the add function.",
-
-    // console message
-    'pixelAddError': "You must pass both x and y values to the add function.",
-
-    // console message
-    'unsupportedGeometryType': "Unsupported geometry type: ${geomType}",
-
-    // console message
-    'pagePositionFailed':
-        "OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",
-
-    // console message
-    'filterEvaluateNotImplemented': "evaluate is not implemented for this filter type.",
-
-    // **** end ****
-    'end': ''
-    
-};
-/* ======================================================================
-    OpenLayers/Popup/AnchoredBubble.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/Popup/Anchored.js
- */
-
-/**
- * Class: OpenLayers.Popup.AnchoredBubble
- * 
- * Inherits from: 
- *  - <OpenLayers.Popup.Anchored>
- */
-OpenLayers.Popup.AnchoredBubble = 
-  OpenLayers.Class(OpenLayers.Popup.Anchored, {
-
     /**
-     * Property: rounded
-     * {Boolean} Has the popup been rounded yet?
+     * APIProperty: duration
+     * {int} duration of the tween (number of steps)
      */
-    rounded: false, 
+    duration: null,
     
-    /** 
-     * 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>) 
-     *     (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
-        );
-        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(); 
-        this.setOpacity();
-
-        return this.div;
-    },
-
     /**
-     * Method: updateRelativePosition
-     * The popup has been moved to a new relative location, in which case
-     *     we will want to re-do the rico corners.
+     * APIProperty: callbacks
+     * {Object} An object with start, eachStep and done properties whose values
+     *     are functions to be call during the animation. They are passed the
+     *     current computed value as argument.
      */
-    updateRelativePosition: function() {
-        this.setRicoCorners();
-    },
-
-    /**
-     * APIMethod: setSize
-     * 
-     * Parameters:
-     * contentSize - {<OpenLayers.Size>} the new size for the popup's 
-     *     contents div (in pixels).
-     */
-    setSize:function(contentSize) { 
-        OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments);
-
-        this.setRicoCorners();
-    },  
-
-    /**
-     * APIMethod: setBackgroundColor
-     * 
-     * Parameters:
-     * color - {String}
-     */
-    setBackgroundColor:function(color) { 
-        if (color != undefined) {
-            this.backgroundColor = color; 
-        }
-        
-        if (this.div != null) {
-            if (this.contentDiv != null) {
-                this.div.style.background = "transparent";
-                OpenLayers.Rico.Corner.changeColor(this.groupDiv, 
-                                                   this.backgroundColor);
-            }
-        }
-    },  
+    callbacks: null,
     
     /**
-     * APIMethod: setOpacity
-     * 
-     * Parameters: 
-     * opacity - {float}
+     * Property: time
+     * {int} Step counter
      */
-    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, 
-                                                     this.opacity);
-            }
-        }
-    },  
- 
-    /** 
-     * Method: setBorder
-     * Always sets border to 0. Bubble Popups can not have a border.
-     * 
-     * Parameters:
-     * border - {Integer}
-     */
-    setBorder:function(border) { 
-        this.border = 0;
-    },      
- 
-    /** 
-     * Method: setRicoCorners
-     * Update RICO corners according to the popup's current relative postion.
-     */
-    setRicoCorners:function() {
+    time: null,
     
-        var corners = this.getCornersToRound(this.relativePosition);
-        var options = {corners: corners,
-                         color: this.backgroundColor,
-                       bgColor: "transparent",
-                         blend: false};
-
-        if (!this.rounded) {
-            OpenLayers.Rico.Corner.round(this.div, options);
-            this.rounded = true;
-        } else {
-            OpenLayers.Rico.Corner.reRound(this.groupDiv, options);
-            //set the popup color and opacity
-            this.setBackgroundColor(); 
-            this.setOpacity();
-        }
-    },
-
-    /** 
-     * Method: getCornersToRound
-     *  
-     * Returns:
-     * {String} The proper corners string ("tr tl bl br") for rico to round.
-     */
-    getCornersToRound:function() {
-
-        var corners = ['tl', 'tr', 'bl', 'br'];
-
-        //we want to round all the corners _except_ the opposite one. 
-        var corner = OpenLayers.Bounds.oppositeQuadrant(this.relativePosition);
-        OpenLayers.Util.removeItem(corners, corner);
-
-        return corners.join(" ");
-    },
-
-    CLASS_NAME: "OpenLayers.Popup.AnchoredBubble"
-});
-
-/**
- * Constant: CORNER_SIZE
- * {Integer} 5. Border space for the RICO corners.
- */
-OpenLayers.Popup.AnchoredBubble.CORNER_SIZE = 5;
-
-/* ======================================================================
-    OpenLayers/Projection.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/Util.js
- */
-
-/**
- * Class: OpenLayers.Projection
- * Class for coordinate transforms between coordinate systems.
- *     Depends on the proj4js library. If proj4js is not available, 
- *     then this is just an empty stub.
- */
-OpenLayers.Projection = OpenLayers.Class({
-
     /**
-     * Property: proj
-     * {Object} Proj4js.Proj instance.
+     * Property: interval
+     * {int} Interval id returned by window.setInterval
      */
-    proj: null,
+    interval: null,
     
     /**
-     * Property: projCode
-     * {String}
+     * Property: playing
+     * {Boolean} Tells if the easing is currently playing
      */
-    projCode: null,
-
-    /**
-     * Constructor: OpenLayers.Projection
-     * This class offers several methods for interacting with a wrapped 
-     *     pro4js projection object. 
-     *
-     * Parameters:
-     * projCode - {String} A string identifying the Well Known Identifier for
-     *    the projection.
-     * options - {Object} An optional object to set additional properties
-     *     on the layer.
-     *
-     * Returns:
-     * {<OpenLayers.Projection>} A projection object.
-     */
-    initialize: function(projCode, options) {
-        OpenLayers.Util.extend(this, options);
-        this.projCode = projCode;
-        if (window.Proj4js) {
-            this.proj = new Proj4js.Proj(projCode);
-        }
-    },
+    playing: false,
     
-    /**
-     * APIMethod: getCode
-     * Get the string SRS code.
-     *
-     * Returns:
-     * {String} The SRS code.
-     */
-    getCode: function() {
-        return this.proj ? this.proj.srsCode : this.projCode;
-    },
-   
-    /**
-     * APIMethod: getUnits
-     * Get the units string for the projection -- returns null if 
-     *     proj4js is not available.
-     *
-     * Returns:
-     * {String} The units abbreviation.
-     */
-    getUnits: function() {
-        return this.proj ? this.proj.units : null;
-    },
-
-    /**
-     * Method: toString
-     * Convert projection to string (getCode wrapper).
-     *
-     * Returns:
-     * {String} The projection code.
-     */
-    toString: function() {
-        return this.getCode();
-    },
-
-    /**
-     * Method: equals
-     * Test equality of two projection instances.  Determines equality based
-     *     soley on the projection code.
-     *
-     * Returns:
-     * {Boolean} The two projections are equivalent.
-     */
-    equals: function(projection) {
-        if (projection && projection.getCode) {
-            return this.getCode() == projection.getCode();
-        } else {
-            return false;
-        }    
-    },
-
-    /* Method: destroy
-     * Destroy projection object.
-     */
-    destroy: function() {
-        delete this.proj;
-        delete this.projCode;
-    },
-    
-    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 
- * 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. 
- * 
- * 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
- * transformed according to the transformation function.
- *
- * Note - Properties on this object should not be set directly.  To add a
- *     transform method to this object, use the <addTransform> method.  For an
- *     example of usage, see the OpenLayers.Layer.SphericalMercator file.
- */
-OpenLayers.Projection.transforms = {};
-
-/**
- * APIMethod: addTransform
- * Set a custom transform method between two projections.  Use this method in
- *     cases where the proj4js lib is not available or where custom projections
- *     need to be handled.
- *
- * Parameters:
- * from - {String} The code for the source projection
- * to - {String} the code for the destination projection
- * method - {Function} A function that takes a point as an argument and
- *     transforms that point from the source to the destination projection
- *     in place.  The original point should be modified.
- */
-OpenLayers.Projection.addTransform = function(from, to, method) {
-    if(!OpenLayers.Projection.transforms[from]) {
-        OpenLayers.Projection.transforms[from] = {};
-    }
-    OpenLayers.Projection.transforms[from][to] = method;
-};
-
-/**
- * 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.
- * sourceProj - {OpenLayers.Projection} Source map coordinate system
- * destProj - {OpenLayers.Projection} Destination map coordinate system
- *
- * Returns:
- * point - {object} A transformed coordinate.  The original point is modified.
- */
-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()] && 
-               OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]) {
-        OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point); 
-    }
-    return point;
-};
-/* ======================================================================
-    OpenLayers/Protocol/WFS/v1.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/WFS.js
- */
-
-/**
- * Class: OpenLayers.Protocol.WFS.v1
- * Abstract class for for v1.0.0 and v1.1.0 protocol.
- *
- * Inherits from:
- *  - <OpenLayers.Protocol>
- */
-OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, {
-    
-    /**
-     * Property: version
-     * {String} WFS version number.
-     */
-    version: null,
-    
-    /**
-     * Property: srsName
-     * {String} Name of spatial reference system.  Default is "EPSG:4326".
-     */
-    srsName: "EPSG:4326",
-    
-    /**
-     * Property: featureType
-     * {String} Local feature typeName.
-     */
-    featureType: null,
-    
-    /**
-     * Property: featureNS
-     * {String} Feature namespace.
-     */
-    featureNS: null,
-    
-    /**
-     * Property: geometryName
-     * {String} Name of the geometry attribute for features.  Default is
-     *     "the_geom".
-     */
-    geometryName: "the_geom",
-    
-    /**
-     * Property: schema
-     * {String} Optional schema location that will be included in the
-     *     schemaLocation attribute value.  Note that the feature type schema
-     *     is required for a strict XML validator (on transactions with an
-     *     insert for example), but is *not* required by the WFS specification
-     *     (since the server is supposed to know about feature type schemas).
-     */
-    schema: null,
-
-    /**
-     * Property: featurePrefix
-     * {String} Namespace alias for feature type.  Default is "feature".
-     */
-    featurePrefix: "feature",
-    
-    /**
-     * Property: formatOptions
-     * {Object} Optional options for the format.  If a format is not provided,
-     *     this property can be used to extend the default format options.
-     */
-    formatOptions: null,
-
     /** 
-     * Property: readFormat 
-     * {<OpenLayers.Format>} For WFS requests it is possible to get a  
-     *     different output format than GML. In that case, we cannot parse  
-     *     the response with the default format (WFST) and we need a different 
-     *     format for reading. 
-     */ 
-    readFormat: null,     
-    
-    /**
-     * Property: readOptions
-     * {Object} Optional object to pass to format's read.
-     */
-    readOptions: null,
-    
-    /**
-     * Constructor: OpenLayers.Protocol.WFS
-     * A class for giving layers WFS protocol.
+     * Constructor: OpenLayers.Tween
+     * Creates a Tween.
      *
      * Parameters:
-     * options - {Object} Optional object whose properties will be set on the
-     *     instance.
-     *
-     * Valid options properties:
-     * url - {String} URL to send requests to (required).
-     * featureType - {String} Local (without prefix) feature typeName (required).
-     * featureNS - {String} Feature namespace (required, but can be autodetected
-     *     for reading if featurePrefix is provided and identical to the prefix
-     *     in the server response).
-     * featurePrefix - {String} Feature namespace alias (optional - only used
-     *     for writing if featureNS is provided).  Default is 'feature'.
-     * geometryName - {String} Name of geometry attribute.  Default is 'the_geom'.
-     */
-    initialize: function(options) {
-        OpenLayers.Protocol.prototype.initialize.apply(this, [options]);
-        if(!options.format) {
-            this.format = OpenLayers.Format.WFST(OpenLayers.Util.extend({
-                version: this.version,
-                featureType: this.featureType,
-                featureNS: this.featureNS,
-                featurePrefix: this.featurePrefix,
-                geometryName: this.geometryName,
-                srsName: this.srsName,
-                schema: this.schema
-            }, this.formatOptions));
-        }
-        if(!this.featureNS && this.featurePrefix) {
-            // featureNS autodetection
-            var readNode = this.format.readNode;
-            this.format.readNode = function(node, obj) {
-                if(!this.featureNS && node.prefix == this.featurePrefix) {
-                    this.featureNS = node.namespaceURI;
-                    this.setNamespace("feature", this.featureNS);
-                }
-                return readNode.apply(this, arguments);
-            };
-        }
+     * easing - {<OpenLayers.Easing>(Function)} easing function method to use
+     */ 
+    initialize: function(easing) {
+        this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
     },
     
     /**
-     * APIMethod: destroy
-     * Clean up the protocol.
-     */
-    destroy: function() {
-        if(this.options && !this.options.format) {
-            this.format.destroy();
-        }
-        this.format = null;
-        OpenLayers.Protocol.prototype.destroy.apply(this);
-    },
-
-    /**
-     * Method: read
-     * Construct a request for reading new features.  Since WFS splits the
-     *     basic CRUD operations into GetFeature requests (for read) and
-     *     Transactions (for all others), this method does not make use of the
-     *     format's read method (that is only about reading transaction
-     *     responses).
-     */
-    read: function(options) {
-        OpenLayers.Protocol.prototype.read.apply(this, arguments);
-        options = OpenLayers.Util.extend({}, options);
-        OpenLayers.Util.applyDefaults(options, this.options || {});
-        var response = new OpenLayers.Protocol.Response({requestType: "read"});
-        
-        var data = OpenLayers.Format.XML.prototype.write.apply(
-            this.format, [this.format.writeNode("wfs:GetFeature", options)]
-        );
-
-        response.priv = OpenLayers.Request.POST({
-            url: options.url,
-            callback: this.createCallback(this.handleRead, response, options),
-            params: options.params,
-            headers: options.headers,
-            data: data
-        });        
-
-        return response;
-    },
-    
-    /**
-     * Method: handleRead
-     * Deal with response from the read request.
-     *
-     * Parameters:
-     * response - {<OpenLayers.Protocol.Response>} The response object to pass
-     *     to the user callback.
-     * options - {Object} The user options passed to the read call.
-     */
-    handleRead: function(response, options) {
-        if(options.callback) {
-            var request = response.priv;
-            if(request.status >= 200 && request.status < 300) {
-                // success
-                if (this.readOptions && this.readOptions.output == "object") {
-                    OpenLayers.Util.extend(response, 
-                        this.parseResponse(request, this.readOptions));
-                } else {
-                    response.features = this.parseResponse(request);
-                }
-                response.code = OpenLayers.Protocol.Response.SUCCESS;
-            } else {
-                // failure
-                response.code = OpenLayers.Protocol.Response.FAILURE;
-            }
-            options.callback.call(options.scope, response);
-        }
-    },
-
-    /**
-     * Method: parseResponse
-     * Read HTTP response body and return features
-     *
-     * Parameters:
-     * request - {XMLHttpRequest} The request object
-     * options - {Object} Optional object to pass to format's read
-     *
-     * Returns:
-     * {Object} or {Array({<OpenLayers.Feature.Vector>})} or
-     *     {<OpenLayers.Feature.Vector>} 
-     * An object with a features property, an array of features or a single 
-     * feature.
-     */
-    parseResponse: function(request, options) {
-        var doc = request.responseXML;
-        if(!doc || !doc.documentElement) {
-            doc = request.responseText;
-        }
-        if(!doc || doc.length <= 0) {
-            return null;
-        }
-        return (this.readFormat !== null) ? this.readFormat.read(doc) : 
-            this.format.read(doc, options);
-    },
-
-    /**
-     * Method: commit
-     * Given a list of feature, assemble a batch request for update, create,
-     *     and delete transactions.  A commit call on the prototype amounts
-     *     to writing a WFS transaction - so the write method on the format
-     *     is used.
-     *
-     * Parameters:
-     * features - {Array(<OpenLayers.Feature.Vector>}
-     *
-     * Returns:
-     * {<OpenLayers.Protocol.Response>} A response object with a features
-     *     property containing any insertIds and a priv property referencing
-     *     the XMLHttpRequest object.
-     */
-    commit: function(features, options) {
-
-        options = OpenLayers.Util.extend({}, options);
-        OpenLayers.Util.applyDefaults(options, this.options);
-        
-        var response = new OpenLayers.Protocol.Response({
-            requestType: "commit",
-            reqFeatures: features
-        });
-        response.priv = OpenLayers.Request.POST({
-            url: options.url,
-            data: this.format.write(features, options),
-            callback: this.createCallback(this.handleCommit, response, options)
-        });
-        
-        return response;
-    },
-    
-    /**
-     * Method: handleCommit
-     * Called when the commit request returns.
+     * APIMethod: start
+     * Plays the Tween, and calls the callback method on each step
      * 
      * Parameters:
-     * response - {<OpenLayers.Protocol.Response>} The response object to pass
-     *     to the user callback.
-     * options - {Object} The user options passed to the commit call.
+     * begin - {Object} values to start the animation with
+     * finish - {Object} values to finish the animation with
+     * duration - {int} duration of the tween (number of steps)
+     * options - {Object} hash of options (for example callbacks (start, eachStep, done))
      */
-    handleCommit: function(response, options) {
-        if(options.callback) {
-            var request = response.priv;
-
-            // ensure that we have an xml doc
-            var data = request.responseXML;
-            if(!data || !data.documentElement) {
-                data = request.responseText;
-            }
-            
-            var obj = this.format.read(data) || {};
-            
-            response.insertIds = obj.insertIds || [];
-            response.code = (obj.success) ?
-                OpenLayers.Protocol.Response.SUCCESS :
-                OpenLayers.Protocol.Response.FAILURE;
-            options.callback.call(options.scope, response);
+    start: function(begin, finish, duration, options) {
+        this.playing = true;
+        this.begin = begin;
+        this.finish = finish;
+        this.duration = duration;
+        this.callbacks = options.callbacks;
+        this.time = 0;
+        if (this.interval) {
+            window.clearInterval(this.interval);
+            this.interval = null;
         }
-    },
-    
-    /**
-     * Method: filterDelete
-     * Send a request that deletes all features by their filter.
-     * 
-     * Parameters:
-     * filter - {OpenLayers.Filter} filter
-     */
-    filterDelete: function(filter, options) {
-        options = OpenLayers.Util.extend({}, options);
-        OpenLayers.Util.applyDefaults(options, this.options);    
-        
-        var response = new OpenLayers.Protocol.Response({
-            requestType: "commit"
-        });    
-        
-        var root = this.format.createElementNSPlus("wfs:Transaction", {
-            attributes: {
-                service: "WFS",
-                version: this.version
-            }
-        });
-        
-        var deleteNode = this.format.createElementNSPlus("wfs:Delete", {
-            attributes: {
-                typeName: (options.featureNS ? this.featurePrefix + ":" : "") +
-                    options.featureType
-            }
-        });       
-        
-        if(options.featureNS) {
-            deleteNode.setAttribute("xmlns:" + this.featurePrefix, options.featureNS);
+        if (this.callbacks && this.callbacks.start) {
+            this.callbacks.start.call(this, this.begin);
         }
-        var filterNode = this.format.writeNode("ogc:Filter", filter);
-        
-        deleteNode.appendChild(filterNode);
-        
-        root.appendChild(deleteNode);
-        
-        var data = OpenLayers.Format.XML.prototype.write.apply(
-            this.format, [root]
-        );
-        
-        return OpenLayers.Request.POST({
-            url: this.url,
-            callback : options.callback || function(){},
-            data: data
-        });   
-        
+        this.interval = window.setInterval(
+            OpenLayers.Function.bind(this.play, this), this.INTERVAL);
     },
-
-    /**
-     * Method: abort
-     * Abort an ongoing request, the response object passed to
-     * this method must come from this protocol (as a result
-     * of a read, or commit operation).
-     *
-     * Parameters:
-     * response - {<OpenLayers.Protocol.Response>}
-     */
-    abort: function(response) {
-        if (response) {
-            response.priv.abort();
-        }
-    },
-  
-    CLASS_NAME: "OpenLayers.Protocol.WFS.v1" 
-});
-/* ======================================================================
-    OpenLayers/Renderer/SVG.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/Renderer/Elements.js
- */
-
-/**
- * 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}
+     * APIMethod: stop
+     * Stops the Tween, and calls the done callback
+     *     Doesn't do anything if animation is already finished
      */
-    xlinkns: "http://www.w3.org/1999/xlink",
-
-    /**
-     * 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 
-     *           works around it.
-     */
-    MAX_PIXEL: 15000,
-
-    /**
-     * Property: translationParameters
-     * {Object} Hash with "x" and "y" properties
-     */
-    translationParameters: null,
-    
-    /**
-     * 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].
-     */
-    symbolMetrics: null,
-    
-    /**
-     * Property: isGecko
-     * {Boolean}
-     */
-    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; 
+    stop: function() {
+        if (!this.playing) {
+            return;
         }
-        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 = {};
-    },
-
-    /**
-     * APIMethod: destroy
-     */
-    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") || 
-            document.implementation.hasFeature(svgFeature + "BasicStructure", "1.1") ));
-    },    
-
-    /**
-     * Method: inValidRange
-     * See #669 for more information
-     *
-     * Parameters:
-     * x      - {Integer}
-     * 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  
-     *           valid range.
-     */ 
-    inValidRange: function(x, y, xyOnly) {
-        var left = x + (xyOnly ? 0 : this.translationParameters.x);
-        var top = y + (xyOnly ? 0 : this.translationParameters.y);
-        return (left >= -this.MAX_PIXEL && left <= this.MAX_PIXEL &&
-                top >= -this.MAX_PIXEL && top <= this.MAX_PIXEL);
-    },
-
-    /**
-     * 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, 
-                                                               arguments);
-        
-        var resolution = this.getResolution();
-        var left = -extent.left / resolution;
-        var top = extent.top / resolution;
-
-        // If the resolution has changed, start over changing the corner, because
-        // the features will redraw.
-        if (resolutionChanged) {
-            this.left = left;
-            this.top = top;
-            // Set the viewbox
-            var extentString = "0 0 " + this.size.w + " " + this.size.h;
-
-            this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
-            this.translate(0, 0);
-            return true;
-        } else {
-            var inRange = this.translate(left - this.left, top - this.top);
-            if (!inRange) {
-                // recenter the coordinate system
-                this.setExtent(extent, true);
-            }
-            return inRange;
+        if (this.callbacks && this.callbacks.done) {
+            this.callbacks.done.call(this, this.finish);
         }
+        window.clearInterval(this.interval);
+        this.interval = null;
+        this.playing = false;
     },
     
     /**
-     * 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.
+     * Method: play
+     * Calls the appropriate easing method
      */
-    translate: function(x, y) {
-        if (!this.inValidRange(x, y, true)) {
-            return false;
-        } else {
-            var transformString = "";
-            if (x || y) {
-                transformString = "translate(" + x + "," + y + ")";
+    play: function() {
+        var value = {};
+        for (var i in this.begin) {
+            var b = this.begin[i];
+            var f = this.finish[i];
+            if (b == null || f == null || isNaN(b) || isNaN(f)) {
+                OpenLayers.Console.error('invalid value for Tween');
             }
-            this.root.setAttributeNS(null, "transform", transformString);
-            this.translationParameters = {x: x, y: y};
-            return true;
-        }
-    },
-
-    /**
-     * 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 
-     * 
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * style - {Object}
-     * 
-     * Returns:
-     * {String} The corresponding node type for the specified geometry
-     */
-    getNodeType: function(geometry, style) {
-        var nodeType = null;
-        switch (geometry.CLASS_NAME) {
-            case "OpenLayers.Geometry.Point":
-                if (style.externalGraphic) {
-                    nodeType = "image";
-                } else if (this.isComplexSymbol(style.graphicName)) {
-                    nodeType = this.supportUse === false ? "svg" : "use";
-                } else {
-                    nodeType = "circle";
-                }
-                break;
-            case "OpenLayers.Geometry.Rectangle":
-                nodeType = "rect";
-                break;
-            case "OpenLayers.Geometry.LineString":
-                nodeType = "polyline";
-                break;
-            case "OpenLayers.Geometry.LinearRing":
-                nodeType = "polygon";
-                break;
-            case "OpenLayers.Geometry.Polygon":
-            case "OpenLayers.Geometry.Curve":
-            case "OpenLayers.Geometry.Surface":
-                nodeType = "path";
-                break;
-            default:
-                break;
-        }
-        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 
-     *                              'isFilled' {Boolean} and
-     *                              'isStroked' {Boolean}
-     */
-    setStyle: function(node, style, options) {
-        style = style  || node._style;
-        options = options || node._options;
-        var r = parseFloat(node.getAttributeNS(null, "r"));
-        var widthFactor = 1;
-        var pos;
-        if (node._geometryClass == "OpenLayers.Geometry.Point" && r) {
-            node.style.visibility = "";
-            if (style.graphic === false) {
-                node.style.visibility = "hidden";
-            } else if (style.externalGraphic) {
-                pos = this.getPosition(node);
-                
-                if (style.graphicTitle) {
-                    node.setAttributeNS(null, "title", style.graphicTitle);
-                }
-                if (style.graphicWidth && style.graphicHeight) {
-                  node.setAttributeNS(null, "preserveAspectRatio", "none");
-                }
-                var width = style.graphicWidth || style.graphicHeight;
-                var height = style.graphicHeight || style.graphicWidth;
-                width = width ? width : style.pointRadius*2;
-                height = height ? height : style.pointRadius*2;
-                var xOffset = (style.graphicXOffset != undefined) ?
-                    style.graphicXOffset : -(0.5 * width);
-                var yOffset = (style.graphicYOffset != undefined) ?
-                    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);
-                node.setAttributeNS(null, "height", height);
-                node.setAttributeNS(this.xlinkns, "href", style.externalGraphic);
-                node.setAttributeNS(null, "style", "opacity: "+opacity);
-            } else if (this.isComplexSymbol(style.graphicName)) {
-                // the symbol viewBox is three times as large as the symbol
-                var offset = style.pointRadius * 3;
-                var size = offset * 2;
-                var id = this.importSymbol(style.graphicName);
-                pos = this.getPosition(node);
-                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;
-                var nextSibling = node.nextSibling;
-                if(parent) {
-                    parent.removeChild(node);
-                }
-                
-                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) {
-                    parent.insertBefore(node, nextSibling);
-                } else if(parent) {
-                    parent.appendChild(node);
-                }
-            } else {
-                node.setAttributeNS(null, "r", style.pointRadius);
-            }
-
-            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);
-        } else {
-            node.setAttributeNS(null, "fill", "none");
-        }
-
-        if (options.isStroked) {
-            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 || "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");
-            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;
-        var str = style.strokeDashstyle;
-        switch (str) {
-            case 'solid':
-                return 'none';
-            case 'dot':
-                return [1, 4 * w].join();
-            case 'dash':
-                return [4 * w, 4 * w].join();
-            case 'dashdot':
-                return [4 * w, 4 * w, 1, 4 * w].join();
-            case 'longdash':
-                return [8 * w, 4 * w].join();
-            case 'longdashdot':
-                return [8 * w, 4 * w, 1, 4 * w].join();
-            default:
-                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
-     */
-    createNode: function(type, id) {
-        var node = document.createElementNS(this.xmlns, type);
-        if (id) {
-            node.setAttributeNS(null, "id", id);
-        }
-        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
-     */
-    createRenderRoot: function() {
-        return this.nodeFactory(this.container.id + "_svgRoot", "svg");
-    },
-
-    /**
-     * Method: createRoot
-     * 
-     * Parameter:
-     * suffix - {String} suffix to append to the id
-     * 
-     * Returns:
-     * {DOMElement}
-     */
-    createRoot: function(suffix) {
-        return this.nodeFactory(this.container.id + suffix, "g");
-    },
-
-    /**
-     * Method: createDefs
-     *
-     * Returns:
-     * {DOMElement} The element to which we'll add the symbol definitions
-     */
-    createDefs: function() {
-        var defs = this.nodeFactory(this.container.id + "_defs", "defs");
-        this.rendererRoot.appendChild(defs);
-        return defs;
-    },
-
-    /**************************************
-     *                                    *
-     *     GEOMETRY DRAWING FUNCTIONS     *
-     *                                    *
-     **************************************/
-
-    /**
-     * Method: drawPoint
-     * This method is only called by the renderer itself.
-     * 
-     * 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);
-    },
-
-    /**
-     * Method: drawCircle
-     * This method is only called by the renderer itself.
-     * 
-     * Parameters: 
-     * node - {DOMElement}
-     * geometry - {<OpenLayers.Geometry>}
-     * radius - {Float}
-     * 
-     * Returns:
-     * {DOMElement} or false if the renderer could not draw the circle
-     */
-    drawCircle: function(node, geometry, radius) {
-        var resolution = this.getResolution();
-        var x = (geometry.x / resolution + this.left);
-        var y = (this.top - geometry.y / resolution);
-
-        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: 
-     * 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);  
-        } else {
-            return false;
+            var c = f - b;
+            value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
         }
-    },
-    
-    /**
-     * Method: drawLinearRing
-     * This method is only called by the renderer itself.
-     * 
-     * 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);  
-        } else {
-            return false;
-        }
-    },
-    
-    /**
-     * Method: drawPolygon
-     * This method is only called by the renderer itself.
-     * 
-     * 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;
-        var complete = true;
-        var linearRingResult, path;
-        for (var j=0, len=geometry.components.length; j<len; j++) {
-            d += " M";
-            linearRingResult = this.getComponentsString(
-                geometry.components[j].components, " ");
-            path = linearRingResult.path;
-            if (path) {
-                d += " " + path;
-                complete = linearRingResult.complete && complete;
-            } else {
-                draw = false;
-            }
-        }
-        d += " z";
-        if (draw) {
-            node.setAttributeNS(null, "d", d);
-            node.setAttributeNS(null, "fill-rule", "evenodd");
-            return complete ? node : null;
-        } else {
-            return false;
-        }    
-    },
-    
-    /**
-     * Method: drawRectangle
-     * This method is only called by the renderer itself.
-     * 
-     * 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)) { 
-            node.setAttributeNS(null, "x", x);
-            node.setAttributeNS(null, "y", y);
-            node.setAttributeNS(null, "width", geometry.width / resolution);
-            node.setAttributeNS(null, "height", geometry.height / resolution);
-            return node;
-        } else {
-            return false;
-        }
-    },
-    
-    /**
-     * Method: drawSurface
-     * This method is only called by the renderer itself.
-     * 
-     * 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
-        var d = null;
-        var draw = true;
-        for (var i=0, len=geometry.components.length; i<len; i++) {
-            if ((i%3) == 0 && (i/3) == 0) {
-                var component = this.getShortString(geometry.components[i]);
-                if (!component) { draw = false; }
-                d = "M " + component;
-            } else if ((i%3) == 1) {
-                var component = this.getShortString(geometry.components[i]);
-                if (!component) { draw = false; }
-                d += " C " + component;
-            } else {
-                var component = this.getShortString(geometry.components[i]);
-                if (!component) { draw = false; }
-                d += " " + component;
-            }
-        }
-        d += " Z";
-        if (draw) {
-            node.setAttributeNS(null, "d", d);
-            return node;
-        } else {
-            return false;
-        }    
-    },
-    
-    /**
-     * Method: drawText
-     * This method is only called by the renderer itself.
-     * 
-     * Parameters: 
-     * featureId - {String}
-     * style -
-     * location - {<OpenLayers.Geometry.Point>}
-     */
-    drawText: function(featureId, style, location) {
-        var resolution = this.getResolution();
+        this.time++;
         
-        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);
-        
-        if (style.fontColor) {
-            label.setAttributeNS(null, "fill", style.fontColor);
+        if (this.callbacks && this.callbacks.eachStep) {
+            this.callbacks.eachStep.call(this, value);
         }
-        if (style.fontOpacity) {
-            label.setAttributeNS(null, "opacity", style.fontOpacity);
-        }
-        if (style.fontFamily) {
-            label.setAttributeNS(null, "font-family", style.fontFamily);
-        }
-        if (style.fontSize) {
-            label.setAttributeNS(null, "font-size", style.fontSize);
-        }
-        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");
-
-        if (this.isGecko) {
-            label.setAttributeNS(null, "dominant-baseline",
-                OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central");
-        } else {
-            tspan.setAttributeNS(null, "baseline-shift",
-                OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%");
-        }
-
-        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
-     *     draw all components)
-     */
-    getComponentsString: function(components, separator) {
-        var renderCmp = [];
-        var complete = true;
-        var len = components.length;
-        var strings = [];
-        var str, component;
-        for(var i=0; i<len; i++) {
-            component = components[i];
-            renderCmp.push(component);
-            str = this.getShortString(component);
-            if (str) {
-                strings.push(str);
-            } else {
-                // The current component is outside the valid range. Let's
-                // see if the previous or next component is inside the range.
-                // If so, add the coordinate of the intersection with the
-                // valid range bounds.
-                if (i > 0) {
-                    if (this.getShortString(components[i - 1])) {
-                        strings.push(this.clipLine(components[i],
-                            components[i-1]));
-                    }
-                }
-                if (i < len - 1) {
-                    if (this.getShortString(components[i + 1])) {
-                        strings.push(this.clipLine(components[i],
-                            components[i+1]));
-                    }
-                }
-                complete = false;
-            }
+        if (this.time > this.duration) {
+            this.stop();
         }
-
-        return {
-            path: strings.join(separator || ","),
-            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
-     * goodComponent - {<OpenLayers.Geometry.Point>)} original geometry of the
-     *     valid point
-     * Returns
-     * {String} the SVG coordinate pair of the clipped point (like
-     *     getShortString), or an empty string if both passed componets are at
-     *     the same point.
+     * Create empty functions for all easing methods.
      */
-    clipLine: function(badComponent, goodComponent) {
-        if (goodComponent.equals(badComponent)) {
-            return "";
-        }
-        var resolution = this.getResolution();
-        var maxX = this.MAX_PIXEL - this.translationParameters.x;
-        var maxY = this.MAX_PIXEL - this.translationParameters.y;
-        var x1 = goodComponent.x / resolution + this.left;
-        var y1 = this.top - goodComponent.y / resolution;
-        var x2 = badComponent.x / resolution + this.left;
-        var y2 = this.top - badComponent.y / resolution;
-        var k;
-        if (x2 < -maxX || x2 > maxX) {
-            k = (y2 - y1) / (x2 - x1);
-            x2 = x2 < 0 ? -maxX : maxX;
-            y2 = y1 + (x2 - x1) * k;
-        }
-        if (y2 < -maxY || y2 > maxY) {
-            k = (x2 - x1) / (y2 - y1);
-            y2 = y2 < 0 ? -maxY : maxY;
-            x2 = x1 + (y2 - y1) * k;
-        }
-        return x2 + "," + y2;
-    },
-
-    /** 
-     * Method: getShortString
-     * 
-     * Parameters:
-     * point - {<OpenLayers.Geometry.Point>}
-     * 
-     * Returns:
-     * {String} or false if point is outside the valid range
-     */
-    getShortString: function(point) {
-        var resolution = this.getResolution();
-        var x = (point.x / resolution + this.left);
-        var y = (this.top - point.y / resolution);
-
-        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
-     */
-    getPosition: function(node) {
-        return({
-            x: parseFloat(node.getAttributeNS(null, "cx")),
-            y: parseFloat(node.getAttributeNS(null, "cy"))
-        });
-    },
-
-    /**
-     * 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');
-        }
-
-        var symbolNode = this.nodeFactory(id, "symbol");
-        var node = this.nodeFactory(null, "polygon");
-        symbolNode.appendChild(node);
-        var symbolExtent = new OpenLayers.Bounds(
-                                    Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
-
-        var points = [];
-        var x,y;
-        for (var i=0; i<symbol.length; i=i+2) {
-            x = symbol[i];
-            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);
-            symbolExtent.top = Math.max(symbolExtent.top, y);
-            points.push(x, ",", y);
-        }
-        
-        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,
-        // to allow for strokeWidth being displayed correctly at the corners.
-        var viewBox = [symbolExtent.left - width,
-                        symbolExtent.bottom - height, width * 3, height * 3];
-        symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" "));
-        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"
+    CLASS_NAME: "OpenLayers.Tween"
 });
 
 /**
- * Constant: OpenLayers.Renderer.SVG.LABEL_ALIGN
- * {Object}
+ * Namespace: OpenLayers.Easing
+ * 
+ * Credits:
+ *      Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
  */
-OpenLayers.Renderer.SVG.LABEL_ALIGN = {
-    "l": "start",
-    "r": "end",
-    "b": "bottom",
-    "t": "hanging"
+OpenLayers.Easing = {
+    /**
+     * Create empty functions for all easing methods.
+     */
+    CLASS_NAME: "OpenLayers.Easing"
 };
 
 /**
- * Constant: OpenLayers.Renderer.SVG.LABEL_VSHIFT
- * {Object}
+ * Namespace: OpenLayers.Easing.Linear
  */
-OpenLayers.Renderer.SVG.LABEL_VSHIFT = {
-    // according to
-    // http://www.w3.org/Graphics/SVG/Test/20061213/htmlObjectHarness/full-text-align-02-b.html
-    // a baseline-shift of -70% shifts the text exactly from the
-    // bottom to the top of the baseline, so -35% moves the text to
-    // the center of the baseline.
-    "t": "-70%",
-    "b": "0"    
-};
-/* ======================================================================
-    OpenLayers/Renderer/VML.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/Renderer/Elements.js
- */
-
-/**
- * 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 (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:
- *  - <OpenLayers.Renderer.Elements>
- */
-OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
-
-    /**
-     * Property: xmlns
-     * {String} XML Namespace URN
-     */
-    xmlns: "urn:schemas-microsoft-com:vml",
+OpenLayers.Easing.Linear = {
     
     /**
-     * Property: symbolCache
-     * {DOMElement} node holding symbols. This hash is keyed by symbol name,
-     *     and each value is a hash with a "path" and an "extent" property.
-     */
-    symbolCache: {},
-
-    /**
-     * Property: offset
-     * {Object} Hash with "x" and "y" properties
-     */
-    offset: null,
-    
-    /**
-     * Constructor: OpenLayers.Renderer.VML
-     * Create a new VML renderer.
-     *
-     * Parameters:
-     * containerID - {String} The id for the element that contains the renderer
-     */
-    initialize: function(containerID) {
-        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']; 
-            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, 
-                                                                arguments);
-    },
-
-    /**
-     * APIMethod: destroy
-     * Deconstruct the renderer.
-     */
-    destroy: function() {
-        OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments);
-    },
-
-    /**
-     * APIMethod: supported
-     * Determine whether a browser supports this renderer.
-     *
-     * Returns:
-     * {Boolean} The browser supports the VML renderer
-     */
-    supported: function() {
-        return !!(document.namespaces);
-    },    
-
-    /**
-     * Method: setExtent
-     * Set the renderer's extent
-     *
-     * Parameters:
-     * extent - {<OpenLayers.Bounds>}
-     * resolutionChanged - {Boolean}
+     * Function: easeIn
      * 
-     * 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, 
-                                                               arguments);
-        var resolution = this.getResolution();
-    
-        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;
-        } else {
-            left = left - this.offset.x;
-            top = top - this.offset.y;
-        }
-
-        
-        var org = left + " " + top;
-        this.root.coordorigin = org;
-        var roots = [this.root, this.vectorRoot, this.textRoot];
-        var root;
-        for(var i=0, len=roots.length; i<len; ++i) {
-            root = roots[i];
-
-            var size = this.size.w + " " + this.size.h;
-            root.coordsize = size;
-            
-        }
-        // 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;
-    },
-
-
-    /**
-     * Method: setSize
-     * Set the size of the drawing surface
-     *
      * Parameters:
-     * size - {<OpenLayers.Size>} the size of the drawing surface
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
      */
-    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 = [
-            this.rendererRoot,
-            this.root,
-            this.vectorRoot,
-            this.textRoot
-        ];
-        var w = this.size.w + "px";
-        var h = this.size.h + "px";
-        var root;
-        for(var i=0, len=roots.length; i<len; ++i) {
-            root = roots[i];
-            root.style.width = w;
-            root.style.height = h;
-        }
+    easeIn: function(t, b, c, d) {
+        return c*t/d + b;
     },
-
-    /**
-     * Method: getNodeType
-     * Get the node type for a geometry and style
-     *
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * style - {Object}
-     *
-     * Returns:
-     * {String} The corresponding node type for the specified geometry
-     */
-    getNodeType: function(geometry, style) {
-        var nodeType = null;
-        switch (geometry.CLASS_NAME) {
-            case "OpenLayers.Geometry.Point":
-                if (style.externalGraphic) {
-                    nodeType = "olv:rect";
-                } else if (this.isComplexSymbol(style.graphicName)) {
-                    nodeType = "olv:shape";
-                } else {
-                    nodeType = "olv:oval";
-                }
-                break;
-            case "OpenLayers.Geometry.Rectangle":
-                nodeType = "olv:rect";
-                break;
-            case "OpenLayers.Geometry.LineString":
-            case "OpenLayers.Geometry.LinearRing":
-            case "OpenLayers.Geometry.Polygon":
-            case "OpenLayers.Geometry.Curve":
-            case "OpenLayers.Geometry.Surface":
-                nodeType = "olv:shape";
-                break;
-            default:
-                break;
-        }
-        return nodeType;
-    },
-
-    /**
-     * Method: setStyle
-     * Use to set all the style attributes to a VML node.
-     *
-     * Parameters:
-     * node - {DOMElement} An VML element to decorate
-     * style - {Object}
-     * options - {Object} Currently supported options include 
-     *                              'isFilled' {Boolean} and
-     *                              'isStroked' {Boolean}
-     * geometry - {<OpenLayers.Geometry>}
-     */
-    setStyle: function(node, style, options, geometry) {
-        style = style  || node._style;
-        options = options || node._options;
-        var fillColor = style.fillColor;
-
-        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;
-                height = height ? height : style.pointRadius*2;
-
-                var resolution = this.getResolution();
-                var xOffset = (style.graphicXOffset != undefined) ?
-                    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) | 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 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;        
-                this.drawCircle(node, geometry, style.pointRadius);
-                node.style.flip = "y";
-            } else {
-                this.drawCircle(node, geometry, style.pointRadius);
-            }
-        }
-
-        // fill 
-        if (options.isFilled) { 
-            node.fillcolor = fillColor; 
-        } else { 
-            node.filled = "false"; 
-        }
-        var fills = node.getElementsByTagName("fill");
-        var fill = (fills.length == 0) ? null : fills[0];
-        if (!options.isFilled) {
-            if (fill) {
-                node.removeChild(fill);
-            }
-        } else {
-            if (!fill) {
-                fill = this.createNode('olv:fill', node.id + "_fill");
-            }
-            fill.opacity = style.fillOpacity;
-
-            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);
-            }
-        }
-
-        // additional rendering for rotated graphics or symbols
-        var rotation = style.rotation;
-        if ((rotation !== undefined || node._rotation !== undefined)) {
-            node._rotation = rotation;
-            if (style.externalGraphic) {
-                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 if(node._geometryClass === "OpenLayers.Geometry.Point") {
-                node.style.rotation = rotation || 0;
-            }
-        }
-
-        // stroke 
-        var strokes = node.getElementsByTagName("stroke");
-        var stroke = (strokes.length == 0) ? null : strokes[0];
-        if (!options.isStroked) {
-            node.stroked = false;
-            if (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 == '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;
-        }
-        return node;
-    },
-
-    /**
-     * Method: graphicRotate
-     * If a point is to be styled with externalGraphic and rotation, VML fills
-     * cannot be used to display the graphic, because rotation of graphic
-     * fills is not supported by the VML implementation of Internet Explorer.
-     * This method creates a olv:imagedata element inside the VML node,
-     * DXImageTransform.Matrix and BasicImage filters for rotation and
-     * opacity, and a 3-step hack to remove rendering artefacts from the
-     * graphic and preserve the ability of graphics to trigger events.
-     * Finally, OpenLayers methods are used to determine the correct
-     * 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, style) {
-        var style = style || node._style;
-        var rotation = style.rotation || 0;
-        
-        var aspectRatio, size;
-        if (!(style.graphicWidth && style.graphicHeight)) {
-            // load the image to determine its size
-            var img = new Image();
-            img.onreadystatechange = OpenLayers.Function.bind(function() {
-                if(img.readyState == "complete" ||
-                        img.readyState == "interactive") {
-                    aspectRatio = img.width / img.height;
-                    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, 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
-        // events on images:
-        // - Use the fill as usual (like for unrotated images) to handle
-        //   events
-        // - specify an imagedata element with the same src as the fill
-        // - style the imagedata element with an AlphaImageLoader filter
-        //   with empty src
-        var image = document.getElementById(node.id + "_image");
-        if (!image) {
-            image = this.createNode("olv:imagedata", node.id + "_image");
-            node.appendChild(image);
-        }
-        image.style.width = width + "px";
-        image.style.height = height + "px";
-        image.src = style.externalGraphic;
-        image.style.filter =
-            "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + 
-            "src='', sizingMethod='scale')";
-
-        var rot = rotation * Math.PI / 180;
-        var sintheta = Math.sin(rot);
-        var costheta = Math.cos(rot);
-
-        // do the rotation on the image
-        var filter =
-            "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta +
-            ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta +
-            ",SizingMethod='auto expand')\n";
-
-        // set the opacity (needed for the imagedata)
-        var opacity = style.graphicOpacity || style.fillOpacity;
-        if (opacity && opacity != 1) {
-            filter += 
-                "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + 
-                opacity+")\n";
-        }
-        node.style.filter = filter;
-
-        // do the rotation again on a box, so we know the insertion point
-        var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset);
-        var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry();
-        imgBox.rotate(style.rotation, centerPoint);
-        var imgBounds = imgBox.getBounds();
-
-        node.style.left = Math.round(
-            parseInt(node.style.left) + imgBounds.left) + "px";
-        node.style.top = Math.round(
-            parseInt(node.style.top) - imgBounds.bottom) + "px";
-    },
-
-    /**
-     * Method: postDraw
-     * 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" &&
-                node.fillcolor != fillColor) {
-            node.fillcolor = fillColor;
-        }
-        if (strokeColor == "none" &&
-                node.strokecolor != strokeColor) {
-            node.strokecolor = strokeColor;
-        }
-    },
-
-
-    /**
-     * Method: setNodeDimension
-     * 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>}
-     */
-    setNodeDimension: function(node, geometry) {
-
-        var bbox = geometry.getBounds();
-        if(bbox) {
-            var resolution = this.getResolution();
-        
-            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
-     */
-    dashStyle: function(style) {
-        var dash = style.strokeDashstyle;
-        switch (dash) {
-            case 'solid':
-            case 'dot':
-            case 'dash':
-            case 'dashdot':
-            case 'longdash':
-            case 'longdashdot':
-                return dash;
-            default:
-                // very basic guessing of dash style patterns
-                var parts = dash.split(/[ ,]/);
-                if (parts.length == 2) {
-                    if (1*parts[0] >= 2*parts[1]) {
-                        return "longdash";
-                    }
-                    return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash";
-                } else if (parts.length == 4) {
-                    return (1*parts[0] >= 2*parts[1]) ? "longdashdot" :
-                        "dashdot";
-                }
-                return "solid";
-        }
-    },
-
     /**
-     * Method: createNode
-     * Create a new node
-     *
-     * Parameters:
-     * type - {String} Kind of node to draw
-     * id - {String} Id for node
-     *
-     * Returns:
-     * {DOMElement} A new node of the given type and id
-     */
-    createNode: function(type, id) {
-        var node = document.createElement(type);
-        if (id) {
-            node.id = id;
-        }
-        
-        // IE hack to make elements unselectable, to prevent 'blue flash'
-        // while dragging vectors; #1410
-        node.unselectable = 'on';
-        node.onselectstart = OpenLayers.Function.False;
-        
-        return node;    
-    },
-    
-    /**
-     * Method: nodeTypeCompare
-     * Determine whether a node is of a given type
-     *
-     * Parameters:
-     * node - {DOMElement} An VML element
-     * type - {String} Kind of node
-     *
-     * Returns:
-     * {Boolean} Whether or not the specified node is of the specified type
-     */
-    nodeTypeCompare: function(node, type) {
-
-        //split type
-        var subType = type;
-        var splitIndex = subType.indexOf(":");
-        if (splitIndex != -1) {
-            subType = subType.substr(splitIndex+1);
-        }
-
-        //split nodeName
-        var nodeName = node.nodeName;
-        splitIndex = nodeName.indexOf(":");
-        if (splitIndex != -1) {
-            nodeName = nodeName.substr(splitIndex+1);
-        }
-
-        return (subType == nodeName);
-    },
-
-    /**
-     * Method: createRenderRoot
-     * Create the renderer root
-     *
-     * Returns:
-     * {DOMElement} The specific render engine's root element
-     */
-    createRenderRoot: function() {
-        return this.nodeFactory(this.container.id + "_vmlRoot", "div");
-    },
-
-    /**
-     * Method: createRoot
-     * Create the main root element
+     * Function: easeOut
      * 
      * Parameters:
-     * suffix - {String} suffix to append to the id
-     *
-     * Returns:
-     * {DOMElement}
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
      */
-    createRoot: function(suffix) {
-        return this.nodeFactory(this.container.id + suffix, "olv:group");
+    easeOut: function(t, b, c, d) {
+        return c*t/d + b;
     },
     
-    /**************************************
-     *                                    *
-     *     GEOMETRY DRAWING FUNCTIONS     *
-     *                                    *
-     **************************************/
-    
     /**
-     * Method: drawPoint
-     * Render a point
+     * Function: easeInOut
      * 
      * Parameters:
-     * node - {DOMElement}
-     * geometry - {<OpenLayers.Geometry>}
-     * 
-     * Returns:
-     * {DOMElement} or false if the point could not be drawn
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
      */
-    drawPoint: function(node, geometry) {
-        return this.drawCircle(node, geometry, 1);
+    easeInOut: function(t, b, c, d) {
+        return c*t/d + b;
     },
 
-    /**
-     * 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
-     */
-    drawCircle: function(node, geometry, radius) {
-        if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
-            var resolution = this.getResolution();
+    CLASS_NAME: "OpenLayers.Easing.Linear"
+};
 
-            node.style.left = (((geometry.x /resolution - this.offset.x) | 0) - radius) + "px";
-            node.style.top = (((geometry.y /resolution - this.offset.y) | 0) - radius) + "px";
+/**
+ * Namespace: OpenLayers.Easing.Expo
+ */
+OpenLayers.Easing.Expo = {
     
-            var diameter = radius * 2;
-            
-            node.style.width = diameter + "px";
-            node.style.height = diameter + "px";
-            return node;
-        }
-        return false;
-    },
-
-
     /**
-     * Method: drawLineString
-     * Render a linestring.
+     * Function: easeIn
      * 
      * Parameters:
-     * node - {DOMElement}
-     * geometry - {<OpenLayers.Geometry>}
-     * 
-     * Returns:
-     * {DOMElement}
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
      */
-    drawLineString: function(node, geometry) {
-        return this.drawLine(node, geometry, false);
+    easeIn: function(t, b, c, d) {
+        return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
     },
-
-    /**
-     * Method: drawLinearRing
-     * Render a linearring
-     * 
-     * Parameters:
-     * node - {DOMElement}
-     * geometry - {<OpenLayers.Geometry>}
-     * 
-     * Returns:
-     * {DOMElement}
-     */
-    drawLinearRing: function(node, geometry) {
-        return this.drawLine(node, geometry, true);
-    },
-
-    /**
-     * Method: DrawLine
-     * Render a line.
-     * 
-     * Parameters:
-     * node - {DOMElement}
-     * geometry - {<OpenLayers.Geometry>}
-     * closeLine - {Boolean} Close the line? (make it a ring?)
-     * 
-     * Returns:
-     * {DOMElement}
-     */
-    drawLine: function(node, geometry, closeLine) {
-
-        this.setNodeDimension(node, geometry);
-
-        var resolution = this.getResolution();
-        var numComponents = geometry.components.length;
-        var parts = new Array(numComponents);
-
-        var comp, x, y;
-        for (var i = 0; i < numComponents; i++) {
-            comp = geometry.components[i];
-            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;
-        return node;
-    },
-
-    /**
-     * Method: drawPolygon
-     * Render a polygon
-     * 
-     * Parameters:
-     * node - {DOMElement}
-     * geometry - {<OpenLayers.Geometry>}
-     * 
-     * Returns:
-     * {DOMElement}
-     */
-    drawPolygon: function(node, geometry) {
-        this.setNodeDimension(node, geometry);
-
-        var resolution = this.getResolution();
     
-        var path = [];
-        var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y;
-        for (j=0, jj=geometry.components.length; j<jj; j++) {
-            path.push("m");
-            points = geometry.components[j].components;
-            // we only close paths of interior rings with area
-            area = (j === 0);
-            first = null;
-            second = null;
-            for (i=0, ii=points.length; i<ii; i++) {
-                comp = points[i];
-                x = (comp.x / resolution - this.offset.x) | 0;
-                y = (comp.y / resolution - this.offset.y) | 0;
-                pathComp = " " + x + "," + y;
-                path.push(pathComp)
-                if (i==0) {
-                    path.push(" l");
-                }
-                if (!area) {
-                    // IE improperly renders sub-paths that have no area.
-                    // Instead of checking the area of every ring, we confirm
-                    // the ring has at least three distinct points.  This does
-                    // not catch all non-zero area cases, but it greatly improves
-                    // interior ring digitizing and is a minor performance hit
-                    // when rendering rings with many points.
-                    if (!first) {
-                        first = pathComp;
-                    } else if (first != pathComp) {
-                        if (!second) {
-                            second = pathComp;
-                        } else if (second != pathComp) {
-                            // stop looking
-                            area = true;
-                        }
-                    }
-                }
-            }
-            path.push(area ? " x " : " ");
-        }
-        path.push("e");
-        node.path = path.join("");
-        return node;
-    },
-
     /**
-     * Method: drawRectangle
-     * Render a rectangle
+     * Function: easeOut
      * 
      * Parameters:
-     * node - {DOMElement}
-     * geometry - {<OpenLayers.Geometry>}
-     * 
-     * Returns:
-     * {DOMElement}
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
      */
-    drawRectangle: function(node, geometry) {
-        var resolution = this.getResolution();
-    
-        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;
+    easeOut: function(t, b, c, d) {
+        return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
     },
     
     /**
-     * Method: drawText
-     * This method is only called by the renderer itself.
+     * Function: easeInOut
      * 
-     * Parameters: 
-     * featureId - {String}
-     * style -
-     * location - {<OpenLayers.Geometry.Point>}
-     */
-    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) | 0) + "px";
-        label.style.top = ((location.y/resolution - this.offset.y) | 0) + "px";
-        label.style.flip = "y";
-
-        textbox.innerText = style.label;
-
-        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;
-        }
-        if (style.fontSize) {
-            textbox.style.fontSize = style.fontSize;
-        }
-        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
-        // pixel later when we set label.style.left
-        textbox.inset = "1px,0px,0px,0px";
-
-        if(!label.parentNode) {
-            label.appendChild(textbox);
-            this.textRoot.appendChild(label);
-        }
-
-        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}
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
      */
-    drawSurface: function(node, geometry) {
-
-        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) | 0;
-            y = (comp.y / resolution - this.offset.y) | 0;
-            if ((i%3)==0 && (i/3)==0) {
-                path.push("m");
-            } else if ((i%3)==1) {
-                path.push(" c");
-            }
-            path.push(" " + x + "," + y);
-        }
-        path.push(" x e");
-
-        node.path = path.join("");
-        return node;
+    easeInOut: function(t, b, c, d) {
+        if (t==0) return b;
+        if (t==d) return b+c;
+        if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
+        return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
     },
-    
-    /**
-     * 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
-     */
-    moveRoot: function(renderer) {
-        var layer = this.map.getLayer(renderer.container.id);
-        if(layer instanceof OpenLayers.Layer.Vector.RootContainer) {
-            layer = this.map.getLayer(this.container.id);
-        }
-        layer && layer.renderer.clear();
-        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');
-        }
 
-        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) {
-            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);
-            symbolExtent.top = Math.max(symbolExtent.top, y);
-
-            pathitems.push(x);
-            pathitems.push(y);
-            if (i == 0) {
-                pathitems.push("l");
-            }
-        }
-        pathitems.push("x e");
-        var path = pathitems.join(" ");
-
-        var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2;
-        if(diff > 0) {
-            symbolExtent.bottom = symbolExtent.bottom - diff;
-            symbolExtent.top = symbolExtent.top + diff;
-        } else {
-            symbolExtent.left = symbolExtent.left + diff;
-            symbolExtent.right = symbolExtent.right - diff;
-        }
-        
-        cache = {
-            path: path,
-            size: symbolExtent.getWidth(), // equals getHeight() now
-            left: symbolExtent.left,
-            bottom: symbolExtent.bottom
-        };
-        this.symbolCache[id] = cache;
-        
-        return cache;
-    },
-    
-    CLASS_NAME: "OpenLayers.Renderer.VML"
-});
-
-/**
- * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT
- * {Object}
- */
-OpenLayers.Renderer.VML.LABEL_SHIFT = {
-    "l": 0,
-    "c": .5,
-    "r": 1,
-    "t": 0,
-    "m": .5,
-    "b": 1
+    CLASS_NAME: "OpenLayers.Easing.Expo"
 };
-/* ======================================================================
-    OpenLayers/Tile.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/Util.js
- * @requires OpenLayers/Console.js
- */
-
-/*
- * Class: OpenLayers.Tile 
- * This is a class designed to designate a single tile, however
- *     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. 
- * 
- * 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 
-     *                       events on the tile.
-     */
-    events: null,
-
-    /**
-     * Property: id 
-     * {String} null
-     */
-    id: null,
-    
-    /** 
-     * 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 
-     * handled in subclasses. Does not belong here.
-     */
-    url: null,
-
-    /** 
-     * APIProperty: bounds 
-     * {<OpenLayers.Bounds>} null
-     */
-    bounds: null,
-    
-    /** 
-     * Property: size 
-     * {<OpenLayers.Size>} null
-     */
-    size: null,
-    
-    /** 
-     * Property: position 
-     * {<OpenLayers.Pixel>} Top Left pixel of the tile
-     */    
-    position: null,
-
-    /**
-     * Property: isLoading
-     * {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>}
-     * options - {Object}
-     */   
-    initialize: function(layer, position, bounds, url, size, options) {
-        this.layer = layer;
-        this.position = position.clone();
-        this.bounds = bounds.clone();
-        this.url = url;
-        this.size = size.clone();
-
-        //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);
-
-        OpenLayers.Util.extend(this, options);
-    },
-
-    /**
-     * Method: unload
-     * Call immediately before destroying if you are listening to tile
-     * events, so that counters are properly handled if tile is still
-     * loading at destroy-time. Will only fire an event if the tile is
-     * still loading.
-     */
-    unload: function() {
-       if (this.isLoading) { 
-           this.isLoading = false; 
-           this.events.triggerEvent("unload"); 
-       }
-    },
-    
-    /** 
-     * APIMethod: destroy
-     * Nullify references to prevent circular references and memory leaks.
-     */
-    destroy:function() {
-        this.layer  = null;
-        this.bounds = null;
-        this.size = null;
-        this.position = null;
-        
-        this.events.destroy();
-        this.events = null;
-    },
-    
-    /**
-     * Method: clone
-     *
-     * Parameters:
-     * obj - {<OpenLayers.Tile>} The tile to be cloned
-     *
-     * Returns:
-     * {<OpenLayers.Tile>} An exact clone of this <OpenLayers.Tile>
-     */
-    clone: function (obj) {
-        if (obj == null) {
-            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 
-     *     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 
-     *     the way the code has been developed. Subclasses call this and
-     *     depend on the return to know if they should draw or not.
-     */
-    draw: function() {
-        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 
-        // 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.
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * position - {<OpenLayers.Pixel>}
-     * redraw - {Boolean} Call draw method on tile after moving.
-     *     Default is true
-     */
-    moveTo: function (bounds, position, redraw) {
-        if (redraw == null) {
-            redraw = true;
-        }
-
-        this.bounds = bounds.clone();
-        this.position = position.clone();
-        if (redraw) {
-            this.draw();
-        }
-    },
-
-    /** 
-     * Method: clear
-     * 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 
-     *     displaying tiles over Google works fine.
-     *
-     * Parameters:
-     * position - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     * 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 bottomRightPx = position.clone();
-        bottomRightPx.x += this.size.w;
-        bottomRightPx.y += this.size.h;
-        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.  
-        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);  
-        return bounds;
-    },        
-        
-    /** 
-     * Method: showTile
-     * Show the tile only if it should be drawn.
-     */
-    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/WFST.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.js
+ * Namespace: OpenLayers.Easing.Quad
  */
-
-/**
- * Function: OpenLayers.Format.WFST
- * Used to create a versioned WFS protocol.  Default version is 1.0.0.
- *
- * Returns:
- * {<OpenLayers.Format>} A WFST format of the given version.
- */
-OpenLayers.Format.WFST = function(options) {
-    options = OpenLayers.Util.applyDefaults(
-        options, OpenLayers.Format.WFST.DEFAULTS
-    );
-    var cls = OpenLayers.Format.WFST["v"+options.version.replace(/\./g, "_")];
-    if(!cls) {
-        throw "Unsupported WFST version: " + options.version;
-    }
-    return new cls(options);
-};
-
-/**
- * Constant: OpenLayers.Format.WFST.DEFAULTS
- * {Object} Default properties for the WFST format.
- */
-OpenLayers.Format.WFST.DEFAULTS = {
-    "version": "1.0.0"
-};
-/* ======================================================================
-    OpenLayers/Format/XML.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.js
- */
-
-/**
- * Class: OpenLayers.Format.XML
- * Read and write XML.  For cross-browser XML generation, use methods on an
- *     instance of the XML format class instead of on <code>document<end>.
- *     The DOM creation and traversing methods exposed here all mimic the
- *     W3C XML DOM methods.  Create a new parser with the
- *     <OpenLayers.Format.XML> constructor.
- *
- * Inherits from:
- *  - <OpenLayers.Format>
- */
-OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
+OpenLayers.Easing.Quad = {
     
     /**
-     * Property: namespaces
-     * {Object} Mapping of namespace aliases to namespace URIs.  Properties
-     *     of this object should not be set individually.  Read-only.  All
-     *     XML subclasses should have their own namespaces object.  Use
-     *     <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
-     *     be applied when a namespaced node is found matching the function
-     *     name.  The function will be applied in the scope of this parser
-     *     with two arguments: the node being read and a context object passed
-     *     from the parent.
-     */
-    readers: {},
-    
-    /**
-     * Property: writers
-     * As a compliment to the <readers> property, this structure contains public
-     *     writing functions grouped by namespace alias and named like the
-     *     node names they produce.
-     */
-    writers: {},
-
-    /**
-     * Property: xmldom
-     * {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
-     *     object.  It is not intended to be a browser sniffing property.
-     *     Instead, the xmldom property is used instead of <code>document<end>
-     *     where namespaced node creation methods are not supported. In all
-     *     other browsers, this remains null.
-     */
-    xmldom: null,
-
-    /**
-     * Constructor: OpenLayers.Format.XML
-     * Construct an XML parser.  The parser is used to read and write XML.
-     *     Reading XML from a string returns a DOM element.  Writing XML from
-     *     a DOM element returns a string.
-     *
-     * Parameters:
-     * options - {Object} Optional object whose properties will be set on
-     *     the object.
-     */
-    initialize: function(options) {
-        if(window.ActiveXObject) {
-            this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
-        }
-        OpenLayers.Format.prototype.initialize.apply(this, [options]);
-        // clone the namespace object and set all namespace aliases
-        this.namespaces = OpenLayers.Util.extend({}, this.namespaces);
-        this.namespaceAlias = {};
-        for(var alias in this.namespaces) {
-            this.namespaceAlias[this.namespaces[alias]] = alias;
-        }
-    },
-    
-    /**
-     * APIMethod: destroy
-     * Clean up.
-     */
-    destroy: function() {
-        this.xmldom = null;
-        OpenLayers.Format.prototype.destroy.apply(this, arguments);
-    },
-    
-    /**
-     * Method: setNamespace
-     * Set a namespace alias and URI for the format.
-     *
-     * Parameters:
-     * alias - {String} The namespace alias (prefix).
-     * uri - {String} The namespace URI.
-     */
-    setNamespace: function(alias, uri) {
-        this.namespaces[alias] = uri;
-        this.namespaceAlias[uri] = alias;
-    },
-
-    /**
-     * APIMethod: read
-     * Deserialize a XML string and return a DOM node.
-     *
-     * Parameters:
-     * text - {String} A XML string
-     
-     * Returns:
-     * {DOMElement} A DOM node
-     */
-    read: function(text) {
-        var index = text.indexOf('<');
-        if(index > 0) {
-            text = text.substring(index);
-        }
-        var node = OpenLayers.Util.Try(
-            OpenLayers.Function.bind((
-                function() {
-                    var xmldom;
-                    /**
-                     * Since we want to be able to call this method on the prototype
-                     * itself, this.xmldom may not exist even if in IE.
-                     */
-                    if(window.ActiveXObject && !this.xmldom) {
-                        xmldom = new ActiveXObject("Microsoft.XMLDOM");
-                    } else {
-                        xmldom = this.xmldom;
-                        
-                    }
-                    xmldom.loadXML(text);
-                    return xmldom;
-                }
-            ), this),
-            function() {
-                return new DOMParser().parseFromString(text, 'text/xml');
-            },
-            function() {
-                var req = new XMLHttpRequest();
-                req.open("GET", "data:" + "text/xml" +
-                         ";charset=utf-8," + encodeURIComponent(text), false);
-                if(req.overrideMimeType) {
-                    req.overrideMimeType("text/xml");
-                }
-                req.send(null);
-                return req.responseXML;
-            }
-        );
-
-        if(this.keepData) {
-            this.data = node;
-        }
-
-        return node;
-    },
-
-    /**
-     * APIMethod: write
-     * Serialize a DOM node into a XML string.
+     * Function: easeIn
      * 
      * Parameters:
-     * node - {DOMElement} A DOM node.
-     *
-     * Returns:
-     * {String} The XML string representation of the input node.
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
      */
-    write: function(node) {
-        var data;
-        if(this.xmldom) {
-            data = node.xml;
-        } else {
-            var serializer = new XMLSerializer();
-            if (node.nodeType == 1) {
-                // Add nodes to a document before serializing. Everything else
-                // is serialized as is. This may need more work. See #1218 .
-                var doc = document.implementation.createDocument("", "", null);
-                if (doc.importNode) {
-                    node = doc.importNode(node, true);
-                }
-                doc.appendChild(node);
-                data = serializer.serializeToString(doc);
-            } else {
-                data = serializer.serializeToString(node);
-            }
-        }
-        return data;
+    easeIn: function(t, b, c, d) {
+        return c*(t/=d)*t + b;
     },
-
-    /**
-     * APIMethod: createElementNS
-     * Create a new element with namespace.  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.createElementNS.
-     *
-     * 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.
-     */
-    createElementNS: function(uri, name) {
-        var element;
-        if(this.xmldom) {
-            if(typeof uri == "string") {
-                element = this.xmldom.createNode(1, name, uri);
-            } else {
-                element = this.xmldom.createNode(1, name, "");
-            }
-        } else {
-            element = document.createElementNS(uri, name);
-        }
-        return element;
-    },
-
-    /**
-     * APIMethod: createTextNode
-     * 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: 
-     * {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 {
-            node = document.createTextNode(text);
-        }
-        return node;
-    },
-
-    /**
-     * APIMethod: getElementsByTagNameNS
-     * Get a list of elements on a node given the namespace URI and local name.
-     *     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.
-     */
-    getElementsByTagNameNS: function(node, uri, name) {
-        var elements = [];
-        if(node.getElementsByTagNameNS) {
-            elements = node.getElementsByTagNameNS(uri, name);
-        } else {
-            // brute force method
-            var allNodes = node.getElementsByTagName("*");
-            var potentialNode, fullName;
-            for(var i=0, len=allNodes.length; i<len; ++i) {
-                potentialNode = allNodes[i];
-                fullName = (potentialNode.prefix) ?
-                           (potentialNode.prefix + ":" + name) : name;
-                if((name == "*") || (fullName == potentialNode.nodeName)) {
-                    if((uri == "*") || (uri == potentialNode.namespaceURI)) {
-                        elements.push(potentialNode);
-                    }
-                }
-            }
-        }
-        return elements;
-    },
-
-    /**
-     * 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.
-     */
-    getAttributeNodeNS: function(node, uri, name) {
-        var attributeNode = null;
-        if(node.getAttributeNodeNS) {
-            attributeNode = node.getAttributeNodeNS(uri, name);
-        } else {
-            var attributes = node.attributes;
-            var potentialNode, fullName;
-            for(var i=0, len=attributes.length; i<len; ++i) {
-                potentialNode = attributes[i];
-                if(potentialNode.namespaceURI == uri) {
-                    fullName = (potentialNode.prefix) ?
-                               (potentialNode.prefix + ":" + name) : name;
-                    if(fullName == potentialNode.nodeName) {
-                        attributeNode = potentialNode;
-                        break;
-                    }
-                }
-            }
-        }
-        return attributeNode;
-    },
-
-    /**
-     * 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.
-     */
-    getAttributeNS: function(node, uri, name) {
-        var attributeValue = "";
-        if(node.getAttributeNS) {
-            attributeValue = node.getAttributeNS(uri, name) || "";
-        } else {
-            var attributeNode = this.getAttributeNodeNS(node, uri, name);
-            if(attributeNode) {
-                attributeValue = attributeNode.nodeValue;
-            }
-        }
-        return attributeValue;
-    },
     
     /**
-     * APIMethod: getChildValue
-     * Get the textual value of the node if it exists, or return an
-     *     optional default string.  Returns an empty string if no first child
-     *     exists and no default value is supplied.
-     *
-     * Parameters:
-     * node - {DOMElement} The element used to look for a first child value.
-     * def - {String} Optional string to return in the event that no
-     *     first child value exists.
-     *
-     * Returns:
-     * {String} The value of the first child of the given node.
-     */
-    getChildValue: function(node, def) {
-        var value = def || "";
-        if(node) {
-            for(var child=node.firstChild; child; child=child.nextSibling) {
-                switch(child.nodeType) {
-                    case 3: // text node
-                    case 4: // cdata section
-                        value += child.nodeValue;
-                }
-            }
-        }
-        return value;
-    },
-
-    /**
-     * APIMethod: concatChildValues
-     * *Deprecated*. Use <getChildValue> instead.
-     *
-     * Concatenate the value of all child nodes if any exist, or return an
-     *     optional default string.  Returns an empty string if no children
-     *     exist and no default value is supplied.  Not optimized for large
-     *     numbers of child nodes.
-     *
-     * Parameters:
-     * node - {DOMElement} The element used to look for child values.
-     * def - {String} Optional string to return in the event that no
-     *     child exist.
-     *
-     * Returns:
-     * {String} The concatenated value of all child nodes of the given node.
-     */
-    concatChildValues: function(node, def) {
-        var value = "";
-        var child = node.firstChild;
-        var childValue;
-        while(child) {
-            childValue = child.nodeValue;
-            if(childValue) {
-                value += childValue;
-            }
-            child = child.nextSibling;
-        }
-        if(value == "" && def != undefined) {
-            value = def;
-        }
-        return value;
-    },
-    
-    /**
-     * APIMethod: isSimpleContent
-     * Test if the given node has only simple content (i.e. no child element
-     *     nodes).
-     *
-     * Parameters:
-     * node - {DOMElement} An element node.
-     *
-     * Returns:
-     * {Boolean} The node has no child element nodes (nodes of type 1). 
-     */
-    isSimpleContent: function(node) {
-        var simple = true;
-        for(var child=node.firstChild; child; child=child.nextSibling) {
-            if(child.nodeType === 1) {
-                simple = false;
-                break;
-            }
-        }
-        return simple;
-    },
-    
-    /**
-     * APIMethod: contentType
-     * Determine the content type for a given node.
-     *
-     * Parameters:
-     * node - {DOMElement}
-     *
-     * Returns:
-     * {Integer} One of OpenLayers.Format.XML.CONTENT_TYPE.{EMPTY,SIMPLE,COMPLEX,MIXED}
-     *     if the node has no, simple, complex, or mixed content.
-     */
-    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) {
-            switch(child.nodeType) {
-                case 1: // element
-                    complex = true;
-                    break;
-                case 8: // comment
-                    break;
-                default:
-                    simple = true;
-            }
-            if(complex && simple) {
-                break;
-            }
-        }
-        
-        if(complex && simple) {
-            type = OpenLayers.Format.XML.CONTENT_TYPE.MIXED;
-        } else if(complex) {
-            return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;
-        } else if(simple) {
-            return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE;
-        }
-        return type;
-    },
-
-    /**
-     * APIMethod: hasAttributeNS
-     * Determine whether a node has a particular attribute matching the given
-     *     name and namespace.
+     * Function: easeOut
      * 
      * 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.
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
      */
-    hasAttributeNS: function(node, uri, name) {
-        var found = false;
-        if(node.hasAttributeNS) {
-            found = node.hasAttributeNS(uri, name);
-        } else {
-            found = !!this.getAttributeNodeNS(node, uri, name);
-        }
-        return found;
+    easeOut: function(t, b, c, d) {
+        return -c *(t/=d)*(t-2) + b;
     },
     
     /**
-     * APIMethod: setAttributeNS
-     * Adds a new attribute or changes the value of an attribute with the given
-     *     namespace and name.
-     *
-     * Parameters:
-     * node - {Element} Element node on which to set the attribute.
-     * uri - {String} Namespace URI for the attribute.
-     * name - {String} Qualified name (prefix:localname) for the attribute.
-     * value - {String} Attribute value.
-     */
-    setAttributeNS: function(node, uri, name, value) {
-        if(node.setAttributeNS) {
-            node.setAttributeNS(uri, name, value);
-        } else {
-            if(this.xmldom) {
-                if(uri) {
-                    var attribute = node.ownerDocument.createNode(
-                        2, name, uri
-                    );
-                    attribute.nodeValue = value;
-                    node.setAttributeNode(attribute);
-                } else {
-                    node.setAttribute(name, value);
-                }
-            } else {
-                throw "setAttributeNS not implemented";
-            }
-        }
-    },
-
-    /**
-     * Method: createElementNSPlus
-     * Shorthand for creating namespaced elements with optional attributes and
-     *     child text nodes.
-     *
-     * Parameters:
-     * name - {String} The qualified node name.
-     * options - {Object} Optional object for node configuration.
-     *
-     * Valid options:
-     * uri - {String} Optional namespace uri for the element - supply a prefix
-     *     instead if the namespace uri is a property of the format's namespace
-     *     object.
-     * attributes - {Object} Optional attributes to be set using the
-     *     <setAttributes> method.
-     * value - {String} Optional text to be appended as a text node.
-     *
-     * Returns:
-     * {Element} An element node.
-     */
-    createElementNSPlus: function(name, options) {
-        options = options || {};
-        // order of prefix preference
-        // 1. in the uri option
-        // 2. in the prefix option
-        // 3. in the qualified name
-        // 4. from the defaultPrefix
-        var uri = options.uri || this.namespaces[options.prefix];
-        if(!uri) {
-            var loc = name.indexOf(":");
-            uri = this.namespaces[name.substring(0, loc)];
-        }
-        if(!uri) {
-            uri = this.namespaces[this.defaultPrefix];
-        }
-        var node = this.createElementNS(uri, name);
-        if(options.attributes) {
-            this.setAttributes(node, options.attributes);
-        }
-        var value = options.value;
-        if(value != null) {
-            node.appendChild(this.createTextNode(value));
-        }
-        return node;
-    },
-    
-    /**
-     * Method: setAttributes
-     * Set multiple attributes given key value pairs from an object.
-     *
-     * Parameters:
-     * node - {Element} An element node.
-     * obj - {Object || Array} An object whose properties represent attribute
-     *     names and values represent attribute values.  If an attribute name
-     *     is a qualified name ("prefix:local"), the prefix will be looked up
-     *     in the parsers {namespaces} object.  If the prefix is found,
-     *     setAttributeNS will be used instead of setAttribute.
-     */
-    setAttributes: function(node, obj) {
-        var value, uri;
-        for(var name in obj) {
-            if(obj[name] != null && obj[name].toString) {
-                value = obj[name].toString();
-                // check for qualified attribute name ("prefix:local")
-                uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null;
-                this.setAttributeNS(node, uri, name, value);
-            }
-        }
-    },
-
-    /**
-     * Method: readNode
-     * Shorthand for applying one of the named readers given the node
-     *     namespace and local name.  Readers take two args (node, obj) and
-     *     generally extend or modify the second.
-     *
-     * Parameters:
-     * node - {DOMElement} The node to be read (required).
-     * obj - {Object} The object to be modified (optional).
-     *
-     * Returns:
-     * {Object} The input object, modified (or a new one if none was provided).
-     */
-    readNode: function(node, obj) {
-        if(!obj) {
-            obj = {};
-        }
-        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["*"];
-            if(reader) {
-                reader.apply(this, [node, obj]);
-            }
-        }
-        return obj;
-    },
-
-    /**
-     * Method: readChildNodes
-     * Shorthand for applying the named readers to all children of a node.
-     *     For each child of type 1 (element), <readSelf> is called.
-     *
-     * Parameters:
-     * node - {DOMElement} The node to be read (required).
-     * obj - {Object} The object to be modified (optional).
-     *
-     * Returns:
-     * {Object} The input object, modified.
-     */
-    readChildNodes: function(node, obj) {
-        if(!obj) {
-            obj = {};
-        }
-        var children = node.childNodes;
-        var child;
-        for(var i=0, len=children.length; i<len; ++i) {
-            child = children[i];
-            if(child.nodeType == 1) {
-                this.readNode(child, obj);
-            }
-        }
-        return obj;
-    },
-
-    /**
-     * Method: writeNode
-     * Shorthand for applying one of the named writers and appending the
-     *     results to a node.  If a qualified name is not provided for the
-     *     second argument (and a local name is used instead), the namespace
-     *     of the parent node will be assumed.
-     *
-     * Parameters:
-     * name - {String} The name of a node to generate.  If a qualified name
-     *     (e.g. "pre:Name") is used, the namespace prefix is assumed to be
-     *     in the <writers> group.  If a local name is used (e.g. "Name") then
-     *     the namespace of the parent is assumed.  If a local name is used
-     *     and no parent is supplied, then the default namespace is assumed.
-     * obj - {Object} Structure containing data for the writer.
-     * parent - {DOMElement} Result will be appended to this node.  If no parent
-     *     is supplied, the node will not be appended to anything.
-     *
-     * Returns:
-     * {DOMElement} The child node.
-     */
-    writeNode: function(name, obj, parent) {
-        var prefix, local;
-        var split = name.indexOf(":");
-        if(split > 0) {
-            prefix = name.substring(0, split);
-            local = name.substring(split + 1);
-        } else {
-            if(parent) {
-                prefix = this.namespaceAlias[parent.namespaceURI];
-            } else {
-                prefix = this.defaultPrefix;
-            }
-            local = name;
-        }
-        var child = this.writers[prefix][local].apply(this, [obj]);
-        if(parent) {
-            parent.appendChild(child);
-        }
-        return child;
-    },
-
-    /**
-     * APIMethod: getChildEl
-     * Get the first child element.  Optionally only return the first child
-     *     if it matches the given name and namespace URI.
-     *
-     * Parameters:
-     * node - {DOMElement} The parent node.
-     * name - {String} Optional node name (local) to search for.
-     * uri - {String} Optional namespace URI to search for.
-     *
-     * Returns:
-     * {DOMElement} The first child.  Returns null if no element is found, if
-     *     something significant besides an element is found, or if the element
-     *     found does not match the optional name and uri.
-     */
-    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
-     *     if it matches the given local name and namespace URI.
-     *
-     * Parameters:
-     * node - {DOMElement} The node.
-     * name - {String} Optional local name of the sibling to search for.
-     * uri - {String} Optional namespace URI of the sibling to search for.
-     *
-     * Returns:
-     * {DOMElement} The next sibling element.  Returns null if no element is
-     *     found, something significant besides an element is found, or the
-     *     found element does not match the optional name and uri.
-     */
-    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
-     *     sibling with the given local name or namespace URI.
-     *
-     * Parameters:
-     * node - {DOMElement} The node.
-     * name - {String} Optional local name of the sibling to search for.
-     * uri - {String} Optional namespace URI of the sibling to search for.
-     *
-     * Returns:
-     * {DOMElement} The next sibling element.  Returns null if no element is
-     *     found, something significant besides an element is found, or the
-     *     found element does not match the query.
-     */
-    getThisOrNextEl: function(node, name, uri) {
-        outer: for(var sibling=node; sibling; sibling=sibling.nextSibling) {
-            switch(sibling.nodeType) {
-                case 1: // Element
-                    if((!name || name === (sibling.localName || sibling.nodeName.split(":").pop())) &&
-                       (!uri || uri === sibling.namespaceURI)) {
-                        // matches
-                        break outer;
-                    }
-                    sibling = null;
-                    break outer;
-                case 3: // Text
-                    if(/^\s*$/.test(sibling.nodeValue)) {
-                        break;
-                    }
-                case 4: // CDATA
-                case 6: // ENTITY_NODE
-                case 12: // NOTATION_NODE
-                case 10: // DOCUMENT_TYPE_NODE
-                case 11: // DOCUMENT_FRAGMENT_NODE
-                    sibling = null;
-                    break outer;
-            } // ignore comments and processing instructions
-        }
-        return sibling || null;
-    },
-    
-    /**
-     * APIMethod: lookupNamespaceURI
-     * Takes a prefix and returns the namespace URI associated with it on the given
-     *     node if found (and null if not). Supplying null for the prefix will
-     *     return the default namespace.
-     *
-     * For browsers that support it, this calls the native lookupNamesapceURI
-     *     function.  In other browsers, this is an implementation of
-     *     http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
-     *
-     * 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.
+     * Function: easeInOut
      * 
-     * Returns:
-     * {String} The namespace URI for the given prefix.  Returns null if the prefix
-     *     cannot be found or the node is the wrong type.
-     */
-    lookupNamespaceURI: function(node, prefix) {
-        var uri = null;
-        if(node) {
-            if(node.lookupNamespaceURI) {
-                uri = node.lookupNamespaceURI(prefix);
-            } else {
-                outer: switch(node.nodeType) {
-                    case 1: // ELEMENT_NODE
-                        if(node.namespaceURI !== null && node.prefix === prefix) {
-                            uri = node.namespaceURI;
-                            break outer;
-                        }
-                        var len = node.attributes.length;
-                        if(len) {
-                            var attr;
-                            for(var i=0; i<len; ++i) {
-                                attr = node.attributes[i];
-                                if(attr.prefix === "xmlns" && attr.name === "xmlns:" + prefix) {
-                                    uri = attr.value || null;
-                                    break outer;
-                                } else if(attr.name === "xmlns" && prefix === null) {
-                                    uri = attr.value || null;
-                                    break outer;
-                                }
-                            }
-                        }
-                        uri = this.lookupNamespaceURI(node.parentNode, prefix);
-                        break outer;
-                    case 2: // ATTRIBUTE_NODE
-                        uri = this.lookupNamespaceURI(node.ownerElement, prefix);
-                        break outer;
-                    case 9: // DOCUMENT_NODE
-                        uri = this.lookupNamespaceURI(node.documentElement, prefix);
-                        break outer;
-                    case 6: // ENTITY_NODE
-                    case 12: // NOTATION_NODE
-                    case 10: // DOCUMENT_TYPE_NODE
-                    case 11: // DOCUMENT_FRAGMENT_NODE
-                        break outer;
-                    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);
-                        break outer;
-                }
-            }
-        }
-        return uri;
-    },
-    
-    CLASS_NAME: "OpenLayers.Format.XML" 
-
-});     
-
-OpenLayers.Format.XML.CONTENT_TYPE = {EMPTY: 0, SIMPLE: 1, COMPLEX: 2, MIXED: 3};
-
-/**
- * APIFunction: OpenLayers.Format.XML.lookupNamespaceURI
- * Takes a prefix and returns the namespace URI associated with it on the given
- *     node if found (and null if not). Supplying null for the prefix will
- *     return the default namespace.
- *
- * For browsers that support it, this calls the native lookupNamesapceURI
- *     function.  In other browsers, this is an implementation of
- *     http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
- *
- * 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.
- */
-OpenLayers.Format.XML.lookupNamespaceURI = OpenLayers.Function.bind(
-    OpenLayers.Format.XML.prototype.lookupNamespaceURI,
-    OpenLayers.Format.XML.prototype
-);
-/* ======================================================================
-    OpenLayers/Handler.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/Events.js
- */
-
-/**
- * Class: OpenLayers.Handler
- * Base class to construct a higher-level handler for event sequences.  All
- *     handlers have activate and deactivate methods.  In addition, they have
- *     methods named like browser events.  When a handler is activated, any
- *     additional methods named like a browser event is registered as a
- *     listener for the corresponding event.  When a handler is deactivated,
- *     those same methods are unregistered as event listeners.
- *
- * Handlers also typically have a callbacks object with keys named like
- *     the abstracted events or event sequences that they are in charge of
- *     handling.  The controls that wrap handlers define the methods that
- *     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
- *     return the application in the same state that they found it.
- */
-OpenLayers.Handler = OpenLayers.Class({
-
-    /**
-     * Property: id
-     * {String}
-     */
-    id: null,
-        
-    /**
-     * APIProperty: 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.
-     */
-    control: null,
-
-    /**
-     * Property: map
-     * {<OpenLayers.Map>}
-     */
-    map: null,
-
-    /**
-     * APIProperty: keyMask
-     * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler
-     *     constants to construct a keyMask.  The keyMask is used by
-     *     <checkModifiers>.  If the keyMask matches the combination of keys
-     *     down on an event, checkModifiers returns true.
-     *
-     * Example:
-     * (code)
-     *     // handler only responds if the Shift key is down
-     *     handler.keyMask = OpenLayers.Handler.MOD_SHIFT;
-     *
-     *     // handler only responds if Ctrl-Shift is down
-     *     handler.keyMask = OpenLayers.Handler.MOD_SHIFT |
-     *                       OpenLayers.Handler.MOD_CTRL;
-     * (end)
-     */
-    keyMask: null,
-
-    /**
-     * Property: active
-     * {Boolean}
-     */
-    active: false,
-    
-    /**
-     * Property: evt
-     * {Event} This property references the last event handled by the handler.
-     *     Note that this property is not part of the stable API.  Use of the
-     *     evt property should be restricted to controls in the library
-     *     or other applications that are willing to update with changes to
-     *     the OpenLayers code.
-     */
-    evt: null,
-
-    /**
-     * Constructor: OpenLayers.Handler
-     * Construct a handler.
-     *
      * 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.  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
-     *     the handler.
-     * options - {Object} An optional object whose properties will be set on
-     *     the handler.
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
      */
-    initialize: function(control, callbacks, options) {
-        OpenLayers.Util.extend(this, options);
-        this.control = control;
-        this.callbacks = callbacks;
-
-        var map = this.map || control.map;
-        if (map) {
-            this.setMap(map); 
-        }
-        
-        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+    easeInOut: function(t, b, c, d) {
+        if ((t/=d/2) < 1) return c/2*t*t + b;
+        return -c/2 * ((--t)*(t-2) - 1) + b;
     },
-    
-    /**
-     * Method: setMap
-     */
-    setMap: function (map) {
-        this.map = map;
-    },
 
-    /**
-     * Method: checkModifiers
-     * Check the keyMask on the handler.  If no <keyMask> is set, this always
-     *     returns true.  If a <keyMask> is set and it matches the combination
-     *     of keys down on an event, this returns true.
-     *
-     * Returns:
-     * {Boolean} The keyMask matches the keys down on an event.
-     */
-    checkModifiers: function (evt) {
-        if(this.keyMask == null) {
-            return true;
-        }
-        /* calculate the keyboard modifier mask for this event */
-        var keyModifiers =
-            (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);
-    },
-
-    /**
-     * APIMethod: activate
-     * Turn on the handler.  Returns false if the handler was already active.
-     * 
-     * Returns: 
-     * {Boolean} The handler was activated.
-     */
-    activate: function() {
-        if(this.active) {
-            return false;
-        }
-        // register for event handlers defined on this class.
-        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.active = true;
-        return true;
-    },
-    
-    /**
-     * APIMethod: deactivate
-     * Turn off the handler.  Returns false if the handler was already inactive.
-     * 
-     * Returns:
-     * {Boolean} The handler was deactivated.
-     */
-    deactivate: function() {
-        if(!this.active) {
-            return false;
-        }
-        // unregister event handlers defined on this class.
-        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.active = false;
-        return true;
-    },
-
-    /**
-    * Method: callback
-    * Trigger the control's named callback with the given arguments
-    *
-    * 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 
-    *     the callback (defined by the control).
-    */
-    callback: function (name, args) {
-        if (name && this.callbacks[name]) {
-            this.callbacks[name].apply(this.control, args);
-        }
-    },
-
-    /**
-    * Method: register
-    * register an event on the map
-    */
-    register: function (name, method) {
-        // TODO: deal with registerPriority in 3.0
-        this.map.events.registerPriority(name, this, method);
-        this.map.events.registerPriority(name, this, this.setEvent);
-    },
-
-    /**
-    * Method: unregister
-    * unregister an event from the map
-    */
-    unregister: function (name, 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
-     *     property.  This property can be accessed by controls if needed
-     *     to get more information about the event that the handler is
-     *     processing.
-     *
-     * This allows modifier keys on the event to be checked (alt, shift,
-     *     and ctrl cannot be checked with the keyboard handler).  For a
-     *     control to determine which modifier keys are associated with the
-     *     event that a handler is currently processing, it should access
-     *     (code)handler.evt.altKey || handler.evt.shiftKey ||
-     *     handler.evt.ctrlKey(end).
-     *
-     * Parameters:
-     * evt - {Event} The browser event.
-     */
-    setEvent: function(evt) {
-        this.evt = evt;
-        return true;
-    },
-
-    /**
-     * Method: destroy
-     * Deconstruct the handler.
-     */
-    destroy: function () {
-        // unregister event listeners
-        this.deactivate();
-        // eliminate circular references
-        this.control = this.map = null;        
-    },
-
-    CLASS_NAME: "OpenLayers.Handler"
-});
-
-/**
- * Constant: OpenLayers.Handler.MOD_NONE
- * If set as the <keyMask>, <checkModifiers> returns false if any key is down.
- */
-OpenLayers.Handler.MOD_NONE  = 0;
-
-/**
- * Constant: OpenLayers.Handler.MOD_SHIFT
- * If set as the <keyMask>, <checkModifiers> returns false if Shift is down.
- */
-OpenLayers.Handler.MOD_SHIFT = 1;
-
-/**
- * Constant: OpenLayers.Handler.MOD_CTRL
- * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down.
- */
-OpenLayers.Handler.MOD_CTRL  = 2;
-
-/**
- * Constant: OpenLayers.Handler.MOD_ALT
- * If set as the <keyMask>, <checkModifiers> returns false if Alt is down.
- */
-OpenLayers.Handler.MOD_ALT   = 4;
-
-
+    CLASS_NAME: "OpenLayers.Easing.Quad"
+};
 /* ======================================================================
     OpenLayers/Map.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/Class.js
  * @requires OpenLayers/Util.js
  * @requires OpenLayers/Events.js
  * @requires OpenLayers/Tween.js
  * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
  */
 
 /**
@@ -17670,7 +6365,7 @@
         this.viewPortDiv.appendChild(this.layerContainerDiv);
 
         this.events = new OpenLayers.Events(this, 
-                                            this.div, 
+                                            this.viewPortDiv, 
                                             this.EVENT_TYPES, 
                                             this.fallThrough, 
                                             {includeXY: true});
@@ -17767,7 +6462,6 @@
     render: function(div) {
         this.div = OpenLayers.Util.getElement(div);
         OpenLayers.Element.addClass(this.div, 'olMap');
-        this.events.attachToElement(this.div);
         this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
         this.div.appendChild(this.viewPortDiv);
         this.updateSize();
@@ -19573,4472 +8267,235 @@
  */
 OpenLayers.Map.TILE_HEIGHT = 256;
 /* ======================================================================
-    OpenLayers/Marker.js
+    OpenLayers/Projection.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/Events.js
- * @requires OpenLayers/Icon.js
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Util.js
  */
 
 /**
- * Class: OpenLayers.Marker
- * 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>.
- *
- * Example:
- * (code)
- * var markers = new OpenLayers.Layer.Markers( "Markers" );
- * map.addLayer(markers);
- *
- * var size = new OpenLayers.Size(21,25);
- * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
- * 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()));
- *
- * (end)
- *
- * Note that if you pass an icon into the Marker constructor, it will take
- * that icon and use it. This means that you should not share icons between
- * markers -- you use them once, but you should clone() for any additional
- * markers using that same icon.
+ * Class: OpenLayers.Projection
+ * Class for coordinate transforms between coordinate systems.
+ *     Depends on the proj4js library. If proj4js is not available, 
+ *     then this is just an empty stub.
  */
-OpenLayers.Marker = OpenLayers.Class({
-    
-    /** 
-     * Property: icon 
-     * {<OpenLayers.Icon>} The icon used by this marker.
-     */
-    icon: null,
+OpenLayers.Projection = OpenLayers.Class({
 
-    /** 
-     * Property: lonlat 
-     * {<OpenLayers.LonLat>} location of object
-     */
-    lonlat: null,
-    
-    /** 
-     * Property: events 
-     * {<OpenLayers.Events>} the event handler.
-     */
-    events: null,
-    
-    /** 
-     * 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
-     * icon - {<OpenLayers.Icon>}  the icon for this marker
-     */
-    initialize: function(lonlat, icon) {
-        this.lonlat = lonlat;
-        
-        var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
-        if (this.icon == null) {
-            this.icon = newIcon;
-        } else {
-            this.icon.url = newIcon.url;
-            this.icon.size = newIcon.size;
-            this.icon.offset = newIcon.offset;
-            this.icon.calculateOffset = newIcon.calculateOffset;
-        }
-        this.events = new OpenLayers.Events(this, this.icon.imageDiv, null);
-    },
-    
     /**
-     * APIMethod: destroy
-     * 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.)
+     * Property: proj
+     * {Object} Proj4js.Proj instance.
      */
-    destroy: function() {
-        // erase any drawn features
-        this.erase();
-
-        this.map = null;
-
-        this.events.destroy();
-        this.events = null;
-
-        if (this.icon != null) {
-            this.icon.destroy();
-            this.icon = null;
-        }
-    },
+    proj: 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 
-    * location passed-in
-    */
-    draw: function(px) {
-        return this.icon.draw(px);
-    }, 
-
-    /** 
-    * Method: erase
-    * Erases any drawn elements for this marker.
-    */
-    erase: function() {
-        if (this.icon != null) {
-            this.icon.erase();
-        }
-    }, 
-
     /**
-    * Method: moveTo
-    * Move the marker to the new location.
-    *
-    * Parameters:
-    * px - {<OpenLayers.Pixel>} the pixel position to move to
-    */
-    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.
+     * Property: projCode
+     * {String}
      */
-    isDrawn: function() {
-        var isDrawn = (this.icon && this.icon.isDrawn());
-        return isDrawn;   
-    },
-
-    /**
-     * Method: onScreen
-     *
-     * Returns:
-     * {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;
-    },
+    projCode: null,
     
     /**
-     * Method: inflate
-     * Englarges the markers icon by the specified ratio.
-     *
-     * Parameters:
-     * inflate - {float} the ratio to enlarge the marker by (passing 2
-     *                   will double the size).
+     * Property: titleRegEx
+     * {RegEx} regular expression to strip the title from a proj4js definition
      */
-    inflate: function(inflate) {
-        if (this.icon) {
-            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 
-     *   its icon
-     * 
-     * Parameters:
-     * opacity - {float}  Specified as fraction (0.4, etc)
-     */
-    setOpacity: function(opacity) {
-        this.icon.setOpacity(opacity);
-    },
+    titleRegEx: /\+title=[^\+]*/,
 
     /**
-     * Method: setUrl
-     * Change URL of the Icon Image.
-     * 
-     * url - {String} 
-     */
-    setUrl: function(url) {
-        this.icon.setUrl(url);
-    },    
-
-    /** 
-     * Method: display
-     * Hide or show the icon
-     * 
-     * display - {Boolean} 
-     */
-    display: function(display) {
-        this.icon.display(display);
-    },
-
-    CLASS_NAME: "OpenLayers.Marker"
-});
-
-
-/**
- * Function: defaultIcon
- * Creates a default <OpenLayers.Icon>.
- * 
- * Returns:
- * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
- */
-OpenLayers.Marker.defaultIcon = function() {
-    var url = OpenLayers.Util.getImagesLocation() + "marker.png";
-    var size = new OpenLayers.Size(21, 25);
-    var calculateOffset = function(size) {
-                    return new OpenLayers.Pixel(-(size.w/2), -size.h);
-                 };
-
-    return new OpenLayers.Icon(url, size, null, calculateOffset);        
-};
-    
-
-/* ======================================================================
-    OpenLayers/Request.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/Events.js
- */
-
-/**
- * Namespace: OpenLayers.Request
- * The OpenLayers.Request namespace contains convenience methods for working
- *     with XMLHttpRequests.  These methods work with a cross-browser
- *     W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
- */
-OpenLayers.Request = {
-    
-    /**
-     * Constant: DEFAULT_CONFIG
-     * {Object} Default configuration for all requests.
-     */
-    DEFAULT_CONFIG: {
-        method: "GET",
-        url: window.location.href,
-        async: true,
-        user: undefined,
-        password: undefined,
-        params: null,
-        proxy: OpenLayers.ProxyHost,
-        headers: {},
-        data: null,
-        callback: function() {},
-        success: null,
-        failure: null,
-        scope: null
-    },
-    
-    /**
-     * APIProperty: events
-     * {<OpenLayers.Events>} An events object that handles all 
-     *     events on the {<OpenLayers.Request>} object.
+     * Constructor: OpenLayers.Projection
+     * This class offers several methods for interacting with a wrapped 
+     *     pro4js projection 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
-     *     place.
-     * success - Triggered when the HTTP response has a success code (200-299).
-     * 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
-     *     a callback to done state, and send any data.  It is recommended that
-     *     you use one <GET>, <POST>, <PUT>, <DELETE>, <OPTIONS>, or <HEAD>.
-     *     This method is only documented to provide detail on the configuration
-     *     options available to all request methods.
-     *
      * Parameters:
-     * config - {Object} Object containing properties for configuring the
-     *     request.  Allowed configuration properties are described below.
-     *     This object is modified and should not be reused.
+     * projCode - {String} A string identifying the Well Known Identifier for
+     *    the projection.
+     * options - {Object} An optional object to set additional properties
+     *     on the layer.
      *
-     * Allowed config properties:
-     * method - {String} One of GET, POST, PUT, DELETE, HEAD, or
-     *     OPTIONS.  Default is GET.
-     * url - {String} URL for the request.
-     * async - {Boolean} Open an asynchronous request.  Default is true.
-     * user - {String} User for relevant authentication scheme.  Set
-     *     to null to clear current user.
-     * password - {String} Password for relevant authentication scheme.
-     *     Set to null to clear current password.
-     * proxy - {String} Optional proxy.  Defaults to
-     *     <OpenLayers.ProxyHost>.
-     * params - {Object} Any key:value pairs to be appended to the
-     *     url as a query string.  Assumes url doesn't already include a query
-     *     string or hash.  Typically, this is only appropriate for <GET>
-     *     requests where the query string will be appended to the url.
-     *     Parameter values that are arrays will be
-     *     concatenated with a comma (note that this goes against form-encoding)
-     *     as is done with <OpenLayers.Util.getParameterString>.
-     * headers - {Object} Object with header:value pairs to be set on
-     *     the request.
-     * data - {String | Document} Optional data to send with the request.
-     *     Typically, this is only used with <POST> and <PUT> requests.
-     *     Make sure to provide the appropriate "Content-Type" header for your
-     *     data.  For <POST> and <PUT> requests, the content type defaults to
-     *     "application-xml".  If your data is a different content type, or
-     *     if you are using a different HTTP method, set the "Content-Type"
-     *     header to match your data type.
-     * callback - {Function} Function to call when request is done.
-     *     To determine if the request failed, check request.status (200
-     *     indicates success).
-     * success - {Function} Optional function to call if request status is in
-     *     the 200s.  This will be called in addition to callback above and
-     *     would typically only be used as an alternative.
-     * failure - {Function} Optional function to call if request status is not
-     *     in the 200s.  This will be called in addition to callback above and
-     *     would typically only be used as an alternative.
-     * scope - {Object} If callback is a public method on some object,
-     *     set the scope to that object.
-     *
      * Returns:
-     * {XMLHttpRequest} Request object.  To abort the request before a response
-     *     is received, call abort() on the request object.
+     * {<OpenLayers.Projection>} A projection object.
      */
-    issue: function(config) {        
-        // apply default config - proxy host may have changed
-        var defaultConfig = OpenLayers.Util.extend(
-            this.DEFAULT_CONFIG,
-            {proxy: OpenLayers.ProxyHost}
-        );
-        config = OpenLayers.Util.applyDefaults(config, defaultConfig);
-
-        // create request, open, and set headers
-        var request = new OpenLayers.Request.XMLHttpRequest();
-        var url = config.url;
-        if(config.params) {
-            var paramString = OpenLayers.Util.getParameterString(config.params);
-            if(paramString.length > 0) {
-                var separator = (url.indexOf('?') > -1) ? '&' : '?';
-                url += separator + paramString;
-            }
+    initialize: function(projCode, options) {
+        OpenLayers.Util.extend(this, options);
+        this.projCode = projCode;
+        if (window.Proj4js) {
+            this.proj = new Proj4js.Proj(projCode);
         }
-        if(config.proxy && (url.indexOf("http") == 0)) {
-            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
-        );
-        for(var header in config.headers) {
-            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.
+     * APIMethod: getCode
+     * Get the string SRS code.
      *
-     * 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) {
-            success = (config.scope) ?
-                OpenLayers.Function.bind(config.success, config.scope) :
-                config.success;
-        }
-
-        // optional failure callback
-        var failure;
-        if(config.failure) {
-            failure = (config.scope) ?
-                OpenLayers.Function.bind(config.failure, config.scope) :
-                config.failure;
-        }
-
-        complete(request);
-
-        if (!request.status || (request.status >= 200 && request.status < 300)) {
-            this.events.triggerEvent("success", options);
-            if(success) {
-                success(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
-     *     documented in the <issue> method, with the method property set
-     *     to GET.
-     *
-     * Parameters:
-     * 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.
+     * {String} The SRS code.
      */
-    GET: function(config) {
-        config = OpenLayers.Util.extend(config, {method: "GET"});
-        return OpenLayers.Request.issue(config);
+    getCode: function() {
+        return this.proj ? this.proj.srsCode : this.projCode;
     },
-    
+   
     /**
-     * APIMethod: POST
-     * Send a POST request.  Additional configuration properties are
-     *     documented in the <issue> method, with the method property set
-     *     to POST and "Content-Type" header set to "application/xml".
+     * APIMethod: getUnits
+     * Get the units string for the projection -- returns null if 
+     *     proj4js is not available.
      *
-     * Parameters:
-     * config - {Object} Object with properties for configuring the request.
-     *     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.
+     * {String} The units abbreviation.
      */
-    POST: function(config) {
-        config = OpenLayers.Util.extend(config, {method: "POST"});
-        // set content type to application/xml if it isn't already set
-        config.headers = config.headers ? config.headers : {};
-        if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
-            config.headers["Content-Type"] = "application/xml";
-        }
-        return OpenLayers.Request.issue(config);
+    getUnits: function() {
+        return this.proj ? this.proj.units : null;
     },
-    
+
     /**
-     * APIMethod: PUT
-     * Send an HTTP PUT request.  Additional configuration properties are
-     *     documented in the <issue> method, with the method property set
-     *     to PUT and "Content-Type" header set to "application/xml".
+     * Method: toString
+     * Convert projection to string (getCode wrapper).
      *
-     * Parameters:
-     * config - {Object} Object with properties for configuring the request.
-     *     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.
+     * {String} The projection code.
      */
-    PUT: function(config) {
-        config = OpenLayers.Util.extend(config, {method: "PUT"});
-        // set content type to application/xml if it isn't already set
-        config.headers = config.headers ? config.headers : {};
-        if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
-            config.headers["Content-Type"] = "application/xml";
-        }
-        return OpenLayers.Request.issue(config);
+    toString: function() {
+        return this.getCode();
     },
-    
-    /**
-     * APIMethod: DELETE
-     * Send an HTTP DELETE request.  Additional configuration properties are
-     *     documented in the <issue> method, with the method property set
-     *     to DELETE.
-     *
-     * Parameters:
-     * 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.
-     */
-    DELETE: function(config) {
-        config = OpenLayers.Util.extend(config, {method: "DELETE"});
-        return OpenLayers.Request.issue(config);
-    },
-  
-    /**
-     * APIMethod: HEAD
-     * Send an HTTP HEAD request.  Additional configuration properties are
-     *     documented in the <issue> method, with the method property set
-     *     to HEAD.
-     *
-     * Parameters:
-     * 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.
-     */
-    HEAD: function(config) {
-        config = OpenLayers.Util.extend(config, {method: "HEAD"});
-        return OpenLayers.Request.issue(config);
-    },
-    
-    /**
-     * APIMethod: OPTIONS
-     * Send an HTTP OPTIONS request.  Additional configuration properties are
-     *     documented in the <issue> method, with the method property set
-     *     to OPTIONS.
-     *
-     * Parameters:
-     * 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.
-     */
-    OPTIONS: function(config) {
-        config = OpenLayers.Util.extend(config, {method: "OPTIONS"});
-        return OpenLayers.Request.issue(config);
-    }
 
-};
-/* ======================================================================
-    OpenLayers/Tile/Image.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/Tile.js
- */
-
-/**
- * Class: OpenLayers.Tile.Image
- * Instances of OpenLayers.Tile.Image are used to manage the image tiles
- * used by various layers.  Create a new image tile with the
- * <OpenLayers.Tile.Image> constructor.
- *
- * Inherits from:
- *  - <OpenLayers.Tile>
- */
-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. 
-     */
-    url: null,
-    
-    /** 
-     * Property: imgDiv
-     * {DOMElement} The div element which wraps the image.
-     */
-    imgDiv: null,
-
     /**
-     * Property: frame
-     * {DOMElement} The image element is appended to the frame.  Any gutter on
-     * 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
-     *     of the back buffer tile resolution to the map resolution.  Compared
-     *     with the current ratio to determine if zooming occurred.
-     */
-    lastRatio: 1,
-
-    /**
-     * Property: isFirstDraw
-     * {Boolean} Is this the first time the tile is being drawn?
-     *     This is used to force resetBackBuffer to synchronize
-     *     the backBufferTile with the foreground tile the first time
-     *     the foreground tile loads so that if the user zooms
-     *     before the layer has fully loaded, the backBufferTile for
-     *     tiles that have been loaded can be used.
-     */
-    isFirstDraw: true,
-        
-    /**
-     * Property: backBufferTile
-     * {<OpenLayers.Tile>} A clone of the tile used to create transition
-     *     effects when the tile is moved or changes resolution.
-     */
-    backBufferTile: null,
-    
-    /**
-     * APIProperty: maxGetUrlLength
-     * {Number} If set, requests that would result in GET urls with more
-     * characters than the number provided will be made using form-encoded
-     * HTTP POST. It is good practice to avoid urls that are longer than 2048
-     * characters.
+     * Method: equals
+     * Test equality of two projection instances.  Determines equality based
+     *     soley on the projection code.
      *
-     * Caution:
-     * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and
-     * Opera < 10.0 do not fully support this option.
-     *
-     * Note:
-     * Do not use this option for layers that have a transitionEffect
-     * configured - IFrame tiles from POST requests can not be resized.
-     */
-    maxGetUrlLength: null,
-    
-    /** 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>}
-     * options - {Object}
-     */   
-    initialize: function(layer, position, bounds, url, size, options) {
-        OpenLayers.Tile.prototype.initialize.apply(this, arguments);
-
-        if (this.maxGetUrlLength != null) {
-            OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame);
-        }
-
-        this.url = url; //deprecated remove me
-        
-        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
-     */
-    destroy: function() {
-        if (this.imgDiv != null)  {
-            this.removeImgDiv();
-        }
-        this.imgDiv = null;
-        if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) { 
-            this.layer.div.removeChild(this.frame); 
-        }
-        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);
-    },
-    
-    /**
-     * Method: clone
-     *
-     * Parameters:
-     * obj - {<OpenLayers.Tile.Image>} The tile to be cloned
-     *
      * Returns:
-     * {<OpenLayers.Tile.Image>} An exact clone of this <OpenLayers.Tile.Image>
+     * {Boolean} The two projections are equivalent.
      */
-    clone: function (obj) {
-        if (obj == null) {
-            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.
-     */
-    draw: function() {
-        if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
-            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) || 
-            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
-                //effects while the tile in the grid is repositioned and redrawn
-                if (!this.backBufferTile) {
-                    this.backBufferTile = this.clone();
-                    this.backBufferTile.hide();
-                    // this is important.  It allows the backBuffer to place itself
-                    // appropriately in the DOM.  The Image subclass needs to put
-                    // 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);
-                }
-                // run any transition effects
-                this.startTransition();
-            } else {
-                // if we aren't going to draw the tile, then the backBuffer should
-                // be hidden too!
-                if (this.backBufferTile) {
-                    this.backBufferTile.clear();
-                }
+    equals: function(projection) {
+        var p = projection, equals = false;
+        if (p) {
+            if (window.Proj4js && this.proj.defData && p.proj.defData) {
+                equals = this.proj.defData.replace(this.titleRegEx, "") ==
+                    p.proj.defData.replace(this.titleRegEx, "");
+            } else if (p.getCode) {
+                var source = this.getCode(), target = p.getCode();
+                equals = source == target ||
+                    !!OpenLayers.Projection.transforms[source] &&
+                    OpenLayers.Projection.transforms[source][target] ===
+                        OpenLayers.Projection.nullTransform;
             }
-        } else {
-            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"); 
-        } else {
-            this.isLoading = true;
-            this.events.triggerEvent("loadstart");
-        }
-        
-        return this.renderTile();
+        return equals;   
     },
-    
-    /** 
-     * 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 
-     *     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 
-     *    foreground tile
-     */
-    resetBackBuffer: function() {
-        this.showTile();
-        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 
-            var maxExtent = this.layer.maxExtent;
-            var withinMaxExtent = (maxExtent &&
-                                   this.bounds.intersectsBounds(maxExtent, false));
-            if (withinMaxExtent) {
-                this.backBufferTile.position = this.position;
-                this.backBufferTile.bounds = this.bounds;
-                this.backBufferTile.size = 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();
-            }
 
-            this.backBufferTile.hide();
-        }
-    },
-    
-    /**
-     * Method: renderTile
-     * Internal function to actually initialize the image tile,
-     *     position it correctly, and set its url.
+    /* Method: destroy
+     * Destroy projection object.
      */
-    renderTile: function() {
-        if (this.layer.async) {
-            this.initImgDiv();
-            // Asyncronous image requests call the asynchronous getURL method
-            // on the layer to fetch an image that covers 'this.bounds', in the scope of
-            // 'this', setting the 'url' property of the layer itself, and running
-            // the callback 'positionFrame' when the image request returns.
-            this.layer.getURLasync(this.bounds, this, "url", this.positionImage);
-        } else {
-            // syncronous image requests get the url and position the frame immediately,
-            // and don't wait for an image request to come back.
-          
-            this.url = this.layer.getURL(this.bounds);
-
-            this.initImgDiv();
-          
-            // position the frame immediately
-            this.positionImage(); 
-        }
-        return true;
+    destroy: function() {
+        delete this.proj;
+        delete this.projCode;
     },
-
-    /**
-     * Method: positionImage
-     * Using the properties currenty set on the layer, position the tile correctly.
-     * This method is used both by the async and non-async versions of the Tile.Image
-     * code.
-     */
-     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) {
-            return;
-        }
-        // position the frame 
-        OpenLayers.Util.modifyDOMElement(this.frame, 
-                                          null, this.position, this.size);   
-
-        var imageSize = this.layer.getImageSize(this.bounds); 
-        if (this.layerAlphaHack) {
-            OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
-                    null, null, imageSize, this.url);
-        } else {
-            OpenLayers.Util.modifyDOMElement(this.imgDiv,
-                    null, null, imageSize) ;
-            this.imgDiv.src = this.url;
-        }
-    },
-
-    /** 
-     * Method: clear
-     *  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) { 
-                this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
-            }    
-        }
-    },
-
-    /**
-     * Method: initImgDiv
-     * Creates the imgDiv property on the tile.
-     */
-    initImgDiv: function() {
-        if (this.imgDiv == null) {
-            var offset = this.layer.imageOffset; 
-            var size = this.layer.getImageSize(this.bounds); 
-
-            if (this.layerAlphaHack) {
-                this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
-                                                               offset,
-                                                               size,
-                                                               null,
-                                                               "relative",
-                                                               null,
-                                                               null,
-                                                               null,
-                                                               true);
-            } else {
-                this.imgDiv = OpenLayers.Util.createImage(null,
-                                                          offset,
-                                                          size,
-                                                          null,
-                                                          "relative",
-                                                          null,
-                                                          null,
-                                                          true);
-            }
-
-            // needed for changing to a different server for onload error
-            if (this.layer.url instanceof Array) {
-                this.imgDiv.urls = this.layer.url.slice();
-            }
-      
-            this.imgDiv.className = 'olTileImage';
-
-            /* checkImgURL used to be used to called as a work around, but it
-               ended up hiding problems instead of solving them and broke things
-               like relative URLs. See discussion on the dev list:
-               http://openlayers.org/pipermail/dev/2007-January/000205.html
-
-            OpenLayers.Event.observe( this.imgDiv, "load",
-                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); 
-
-            if(this.layer.opacity != null) {
-
-                OpenLayers.Util.modifyDOMElement(this.imgDiv, 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 
-            // can register when a tile has finished loading.
-            var onload = function() {
-
-                //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 
-                // a 'loadend' if the msg has already been sent
-                //
-                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)); 
-            } 
-
-
-            // 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() {
-
-                // If we have gone through all image reload attempts, it is time
-                // to realize that we are done with this image. Since
-                // OpenLayers.Util.onImageLoadError already has taken care about
-                // the error, we can continue as if the image was loaded
-                // successfully.
-                if (this.imgDiv._attempts > OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
-                    onload.call(this);
-                }
-            };
-            OpenLayers.Event.observe(this.imgDiv, "error",
-                                     OpenLayers.Function.bind(onerror, this));
-        }
-        
-        this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
-    },
-
-    /**
-     * Method: removeImgDiv
-     * Removes the imgDiv from the DOM and stops listening to events on it.
-     */
-    removeImgDiv: function() {
-        // unregister the "load" and "error" handlers. Only the "error" handler if
-        // this.layerAlphaHack is true.
-        OpenLayers.Event.stopObservingElement(this.imgDiv);
-        
-        if (this.imgDiv.parentNode == this.frame) {
-            this.frame.removeChild(this.imgDiv);
-            this.imgDiv.map = null;
-        }
-        this.imgDiv.urls = null;
-
-        var child = this.imgDiv.firstChild;
-        //check for children (alphaHack img or IFrame)
-        if (child) {
-            OpenLayers.Event.stopObservingElement(child);
-            this.imgDiv.removeChild(child);
-            delete child;
-        } else {
-            // abort any currently loading image
-            this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
-        }
-    },
-
-    /**
-     * Method: checkImgURL
-     * Make sure that the image that just loaded is the one this tile is meant
-     * to display, since panning/zooming might have changed the tile's URL in
-     * the meantime. If the tile URL did change before the image loaded, set
-     * 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 
-     * isEquivilant URL function, this might be neccesary at some point.
-     * 
-     * 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.  
-        if (this.layer) {
-            var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src;
-            if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
-                this.hide();
-            }
-        }
-    },
     
-    /**
-     * Method: startTransition
-     * This method is invoked on tiles that are backBuffers for tiles in the
-     *     grid.  The grid tile is about to be cleared and a new tile source
-     *     loaded.  This is where the transition effect needs to be started
-     *     to provide visual continuity.
-     */
-    startTransition: function() {
-        // backBufferTile has to be valid and ready to use
-        if (!this.backBufferTile || !this.backBufferTile.imgDiv) {
-            return;
-        }
+    CLASS_NAME: "OpenLayers.Projection" 
+});     
 
-        // calculate the ratio of change between the current resolution of the
-        // backBufferTile and the layer.  If several animations happen in a
-        // row, then the backBufferTile will scale itself appropriately for
-        // each request.
-        var ratio = 1;
-        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 
-                // backBufferTile.
-                var upperLeft = new OpenLayers.LonLat(
-                    this.backBufferTile.bounds.left, 
-                    this.backBufferTile.bounds.top
-                );
-                var size = new OpenLayers.Size(
-                    this.backBufferTile.size.w * ratio,
-                    this.backBufferTile.size.h * ratio
-                );
-
-                var px = this.layer.map.getLayerPxFromLonLat(upperLeft);
-                OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame, 
-                                                 null, px, size);
-                var imageSize = this.backBufferTile.imageSize;
-                imageSize = new OpenLayers.Size(imageSize.w * ratio, 
-                                                imageSize.h * ratio);
-                var imageOffset = this.backBufferTile.imageOffset;
-                if(imageOffset) {
-                    imageOffset = new OpenLayers.Pixel(
-                        imageOffset.x * ratio, imageOffset.y * ratio
-                    );
-                }
-
-                OpenLayers.Util.modifyDOMElement(
-                    this.backBufferTile.imgDiv, null, imageOffset, imageSize
-                ) ;
-
-                this.backBufferTile.show();
-            }
-        } else {
-            // default effect is just to leave the existing tile
-            // until the new one loads if this is a singleTile and
-            // there was no change in resolution.  Otherwise we
-            // don't bother to show the backBufferTile at all
-            if (this.layer.singleTile) {
-                this.backBufferTile.show();
-            } else {
-                this.backBufferTile.hide();
-            }
-        }
-        this.lastRatio = ratio;
-
-    },
-    
-    /** 
-     * Method: show
-     * Show the tile by showing its frame.
-     */
-    show: function() {
-        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, 
-                this.layer.transitionEffect) != -1) {
-            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/Control/OverviewMap.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/Control.js
- * @requires OpenLayers/BaseTypes.js
- * @requires OpenLayers/Events.js
- */
-
 /**
- * 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 
- * 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.
+ * Property: transforms
+ * Transforms is an object, with from properties, each of which may
+ * have a to property. This allows you to define projections without 
+ * requiring support for proj4js to be included.
  *
- * Inerits from:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
-
-    /**
-     * Property: element
-     * {DOMElement} The DOM element that contains the overview map
-     */
-    element: null,
-    
-    /**
-     * APIProperty: ovmap
-     * {<OpenLayers.Map>} A reference to the overview map itself.
-     */
-    ovmap: null,
-
-    /**
-     * APIProperty: size
-     * {<OpenLayers.Size>} The overvew map size in pixels.  Note that this is
-     * the size of the map itself - the element that contains the map (default
-     * class name olControlOverviewMapElement) may have padding or other style
-     * attributes added via CSS.
-     */
-    size: new OpenLayers.Size(180, 90),
-
-    /**
-     * APIProperty: layers
-     * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
-     * 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
-     *     rectangle on the overview map.  When the extent rectangle reaches
-     *     this size, it will be replaced depending on the value of the
-     *     <minRectDisplayClass> property.  Default is 15 pixels.
-     */
-    minRectSize: 15,
-    
-    /**
-     * APIProperty: minRectDisplayClass
-     * {String} Replacement style class name for the extent rectangle when
-     *     <minRectSize> is reached.  This string will be suffixed on to the
-     *     displayClass.  Default is "RectReplacement".
-     *
-     * Example CSS declaration:
-     * (code)
-     * .olControlOverviewMapRectReplacement {
-     *     overflow: hidden;
-     *     cursor: move;
-     *     background-image: url("img/overview_replacement.gif");
-     *     background-repeat: no-repeat;
-     *     background-position: center;
-     * }
-     * (end)
-     */
-    minRectDisplayClass: "RectReplacement",
-
-    /**
-     * APIProperty: minRatio
-     * {Float} The ratio of the overview map resolution to the main map
-     *     resolution at which to zoom farther out on the overview map.
-     */
-    minRatio: 8,
-
-    /**
-     * APIProperty: maxRatio
-     * {Float} The ratio of the overview map resolution to the main map
-     *     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
-     *     the overview map's map constructor.  These should include any
-     *     non-default options that the main map was constructed with.
-     */
-    mapOptions: null,
-
-    /**
-     * APIProperty: autoPan
-     * {Boolean} Always pan the overview map, so the extent marker remains in
-     *     the center.  Default is false.  If true, when you drag the extent
-     *     marker, the overview map will update itself so the marker returns
-     *     to the center.
-     */
-    autoPan: false,
-    
-    /**
-     * Property: handlers
-     * {Object}
-     */
-    handlers: null,
-
-    /**
-     * Property: resolutionFactor
-     * {Object}
-     */
-    resolutionFactor: 1,
-
-    /**
-     * APIProperty: maximized
-     * {Boolean} Start as maximized (visible). Defaults to false.
-     */
-    maximized: false,
-
-    /**
-     * Constructor: OpenLayers.Control.OverviewMap
-     * Create a new overview map
-     *
-     * Parameters:
-     * object - {Object} Properties of this object will be set on the overview
-     * map object.  Note, to set options on the map object contained in this
-     * control, set <mapOptions> as one of the options properties.
-     */
-    initialize: function(options) {
-        this.layers = [];
-        this.handlers = {};
-        OpenLayers.Control.prototype.initialize.apply(this, [options]);
-    },
-    
-    /**
-     * APIMethod: destroy
-     * Deconstruct the control
-     */
-    destroy: function() {
-        if (!this.mapDiv) { // we've already been destroyed
-            return;
-        }
-        if (this.handlers.click) {
-            this.handlers.click.destroy();
-        }
-        if (this.handlers.drag) {
-            this.handlers.drag.destroy();
-        }
-
-        this.mapDiv.removeChild(this.extentRectangle);
-        this.extentRectangle = 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;
-
-        this.div.removeChild(this.element);
-        this.element = null;
-
-        if (this.maximizeDiv) {
-            OpenLayers.Event.stopObservingElement(this.maximizeDiv);
-            this.div.removeChild(this.maximizeDiv);
-            this.maximizeDiv = null;
-        }
-        
-        if (this.minimizeDiv) {
-            OpenLayers.Event.stopObservingElement(this.minimizeDiv);
-            this.div.removeChild(this.minimizeDiv);
-            this.minimizeDiv = null;
-        }
-
-        this.map.events.un({
-            "moveend": this.update,
-            "changebaselayer": this.baseLayerDraw,
-            scope: this
-        });
-
-        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)) {
-            if (this.map.baseLayer) {
-                var layer = this.map.baseLayer.clone();
-                this.layers = [layer];
-            } else {
-                this.map.events.register("changebaselayer", this, this.baseLayerDraw);
-                return this.div;
-            }
-        }
-
-        // create overview map DOM elements
-        this.element = document.createElement('div');
-        this.element.className = this.displayClass + 'Element';
-        this.element.style.display = 'none';
-
-        this.mapDiv = document.createElement('div');
-        this.mapDiv.style.width = this.size.w + 'px';
-        this.mapDiv.style.height = this.size.h + 'px';
-        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.div.appendChild(this.element);
-
-        // Optionally add min/max buttons if the control will go in the
-        // map viewport.
-        if(!this.outsideViewport) {
-            this.div.className += " " + this.displayClass + 'Container';
-            var imgLocation = OpenLayers.Util.getImagesLocation();
-            // 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, 
-                                        'absolute');
-            this.maximizeDiv.style.display = 'none';
-            this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
-            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, 
-                                        'absolute');
-            this.minimizeDiv.style.display = 'none';
-            this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
-            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.stop);
-
-                OpenLayers.Event.observe(this.minimizeDiv,
-                                         eventsToStop[i], 
-                                         OpenLayers.Event.stop);
-            }
-            
-            this.minimizeControl();
-        } else {
-            // show the overview map
-            this.element.style.display = '';
-        }
-        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
-     */
-    baseLayerDraw: function() {
-        this.draw();
-        this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
-    },
-
-    /**
-     * Method: rectDrag
-     * Handle extent rectangle drag
-     *
-     * Parameters:
-     * px - {<OpenLayers.Pixel>} The pixel location of the drag.
-     */
-    rectDrag: function(px) {
-        var deltaX = this.handlers.drag.last.x - px.x;
-        var deltaY = this.handlers.drag.last.y - px.y;
-        if(deltaX != 0 || deltaY != 0) {
-            var rectTop = this.rectPxBounds.top;
-            var rectLeft = this.rectPxBounds.left;
-            var rectHeight = Math.abs(this.rectPxBounds.getHeight());
-            var rectWidth = this.rectPxBounds.getWidth();
-            // don't allow dragging off of parent element
-            var newTop = Math.max(0, (rectTop - deltaY));
-            newTop = Math.min(newTop,
-                              this.ovmap.size.h - this.hComp - rectHeight);
-            var newLeft = Math.max(0, (rectLeft - deltaX));
-            newLeft = Math.min(newLeft,
-                               this.ovmap.size.w - this.wComp - rectWidth);
-            this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
-                                                       newTop + rectHeight,
-                                                       newLeft + rectWidth,
-                                                       newTop));
-        }
-    },
-    
-    /**
-     * Method: mapDivClick
-     * Handle browser events
-     *
-     * Parameters:
-     * evt - {<OpenLayers.Event>} evt
-     */
-    mapDivClick: function(evt) {
-        var pxCenter = this.rectPxBounds.getCenterPixel();
-        var deltaX = evt.xy.x - pxCenter.x;
-        var deltaY = evt.xy.y - pxCenter.y;
-        var top = this.rectPxBounds.top;
-        var left = this.rectPxBounds.left;
-        var height = Math.abs(this.rectPxBounds.getHeight());
-        var width = this.rectPxBounds.getWidth();
-        var newTop = Math.max(0, (top + deltaY));
-        newTop = Math.min(newTop, this.ovmap.size.h - height);
-        var newLeft = Math.max(0, (left + deltaX));
-        newLeft = Math.min(newLeft, this.ovmap.size.w - width);
-        this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
-                                                   newTop + height,
-                                                   newLeft + width,
-                                                   newTop));
-        this.updateMapToRect();
-    },
-
-    /**
-     * Method: maximizeControl
-     * Unhide the control.  Called when the control is in the map viewport.
-     *
-     * Parameters:
-     * e - {<OpenLayers.Event>}
-     */
-    maximizeControl: function(e) {
-        this.element.style.display = '';
-        this.showToggle(false);
-        if (e != null) {
-            OpenLayers.Event.stop(e);                                            
-        }
-    },
-
-    /**
-     * Method: minimizeControl
-     * Hide all the contents of the control, shrink the size, 
-     * add the maximize icon
-     * 
-     * Parameters:
-     * e - {<OpenLayers.Event>}
-     */
-    minimizeControl: function(e) {
-        this.element.style.display = 'none';
-        this.showToggle(true);
-        if (e != null) {
-            OpenLayers.Event.stop(e);                                            
-        }
-    },
-
-    /**
-     * Method: showToggle
-     * Hide/Show the toggle depending on whether the control is minimized
-     *
-     * Parameters:
-     * minimize - {Boolean} 
-     */
-    showToggle: function(minimize) {
-        this.maximizeDiv.style.display = minimize ? '' : 'none';
-        this.minimizeDiv.style.display = minimize ? 'none' : '';
-    },
-
-    /**
-     * Method: update
-     * Update the overview map after layers move.
-     */
-    update: function() {
-        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
-     * resolution of the main map.
-     */
-    isSuitableOverview: function() {
-        var mapExtent = this.map.getExtent();
-        var maxExtent = this.map.maxExtent;
-        var testExtent = new OpenLayers.Bounds(
-                                Math.max(mapExtent.left, maxExtent.left),
-                                Math.max(mapExtent.bottom, maxExtent.bottom),
-                                Math.min(mapExtent.right, maxExtent.right),
-                                Math.min(mapExtent.top, maxExtent.top));        
-
-        if (this.ovmap.getProjection() != this.map.getProjection()) {
-            testExtent = testExtent.transform(
-                this.map.getProjectionObject(),
-                this.ovmap.getProjectionObject() );
-        }
-
-        var resRatio = this.ovmap.getResolution() / this.map.getResolution();
-        return ((resRatio > this.minRatio) &&
-                (resRatio <= this.maxRatio) &&
-                (this.ovmap.getExtent().containsBounds(testExtent)));
-    },
-    
-    /**
-     * Method updateOverview
-     * Called by <update> if <isSuitableOverview> returns true
-     */
-    updateOverview: function() {
-        var mapRes = this.map.getResolution();
-        var targetRes = this.ovmap.getResolution();
-        var resRatio = targetRes / mapRes;
-        if(resRatio > this.maxRatio) {
-            // zoom in overview map
-            targetRes = this.minRatio * mapRes;            
-        } else if(resRatio <= this.minRatio) {
-            // zoom out overview map
-            targetRes = this.maxRatio * mapRes;
-        }
-        var center;
-        if (this.ovmap.getProjection() != this.map.getProjection()) {
-            center = this.map.center.clone();
-            center.transform(this.map.getProjectionObject(),
-                this.ovmap.getProjectionObject() );
-        } else {
-            center = this.map.center;
-        }
-        this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(
-            targetRes * this.resolutionFactor));
-        this.updateRectToMap();
-    },
-    
-    /**
-     * Method: createMap
-     * Construct the map that this control contains
-     */
-    createMap: function() {
-        // create the overview map
-        var options = OpenLayers.Util.extend(
-                        {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
-        this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
-                                               'border-left-width')) +
-                     parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
-                                               'border-right-width'));
-        this.wComp = (this.wComp) ? this.wComp : 2;
-        this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
-                                               'border-top-width')) +
-                     parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
-                                               'border-bottom-width'));
-        this.hComp = (this.hComp) ? this.hComp : 2;
-
-        this.handlers.drag = new OpenLayers.Handler.Drag(
-            this, {move: this.rectDrag, done: this.updateMapToRect},
-            {map: this.ovmap}
-        );
-        this.handlers.click = new OpenLayers.Handler.Click(
-            this, {
-                "click": this.mapDivClick
-            },{
-                "single": true, "double": false,
-                "stopSingle": true, "stopDouble": true,
-                "pixelTolerance": 1,
-                map: this.ovmap
-            }
-        );
-        this.handlers.click.activate();
-        
-        this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
-                                                null, true);
-        this.rectEvents.register("mouseover", this, function(e) {
-            if(!this.handlers.drag.active && !this.map.dragging) {
-                this.handlers.drag.activate();
-            }
-        });
-        this.rectEvents.register("mouseout", this, function(e) {
-            if(!this.handlers.drag.dragging) {
-                this.handlers.drag.deactivate();
-            }
-        });
-
-        if (this.ovmap.getProjection() != this.map.getProjection()) {
-            var sourceUnits = this.map.getProjectionObject().getUnits() ||
-                this.map.units || this.map.baseLayer.units;
-            var targetUnits = this.ovmap.getProjectionObject().getUnits() ||
-                this.ovmap.units || this.ovmap.baseLayer.units;
-            this.resolutionFactor = sourceUnits && targetUnits ?
-                OpenLayers.INCHES_PER_UNIT[sourceUnits] /
-                OpenLayers.INCHES_PER_UNIT[targetUnits] : 1;
-        }
-    },
-        
-    /**
-     * Method: updateRectToMap
-     * Updates the extent rectangle position and size to match the map extent
-     */
-    updateRectToMap: function() {
-        // If the projections differ we need to reproject
-        var bounds;
-        if (this.ovmap.getProjection() != this.map.getProjection()) {
-            bounds = this.map.getExtent().transform(
-                this.map.getProjectionObject(), 
-                this.ovmap.getProjectionObject() );
-        } else {
-            bounds = this.map.getExtent();
-        }
-        var pxBounds = this.getRectBoundsFromMapBounds(bounds);
-        if (pxBounds) {
-            this.setRectPxBounds(pxBounds);
-        }
-    },
-    
-    /**
-     * Method: updateMapToRect
-     * Updates the map extent to match the extent rectangle position and size
-     */
-    updateMapToRect: function() {
-        var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds);
-        if (this.ovmap.getProjection() != this.map.getProjection()) {
-            lonLatBounds = lonLatBounds.transform(
-                this.ovmap.getProjectionObject(),
-                this.map.getProjectionObject() );
-        }
-        this.map.panTo(lonLatBounds.getCenterLonLat());
-    },
-
-    /**
-     * Method: setRectPxBounds
-     * Set extent rectangle pixel bounds.
-     *
-     * Parameters:
-     * pxBounds - {<OpenLayers.Bounds>}
-     */
-    setRectPxBounds: function(pxBounds) {
-        var top = Math.max(pxBounds.top, 0);
-        var left = Math.max(pxBounds.left, 0);
-        var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
-                              this.ovmap.size.h - this.hComp);
-        var right = Math.min(pxBounds.left + pxBounds.getWidth(),
-                             this.ovmap.size.w - this.wComp);
-        var width = Math.max(right - left, 0);
-        var height = Math.max(bottom - top, 0);
-        if(width < this.minRectSize || height < this.minRectSize) {
-            this.extentRectangle.className = this.displayClass +
-                                             this.minRectDisplayClass;
-            var rLeft = left + (width / 2) - (this.minRectSize / 2);
-            var rTop = top + (height / 2) - (this.minRectSize / 2);
-            this.extentRectangle.style.top = Math.round(rTop) + 'px';
-            this.extentRectangle.style.left = Math.round(rLeft) + 'px';
-            this.extentRectangle.style.height = this.minRectSize + 'px';
-            this.extentRectangle.style.width = this.minRectSize + 'px';
-        } else {
-            this.extentRectangle.className = this.displayClass +
-                                             'ExtentRectangle';
-            this.extentRectangle.style.top = Math.round(top) + 'px';
-            this.extentRectangle.style.left = Math.round(left) + 'px';
-            this.extentRectangle.style.height = Math.round(height) + 'px';
-            this.extentRectangle.style.width = Math.round(width) + 'px';
-        }
-        this.rectPxBounds = new OpenLayers.Bounds(
-            Math.round(left), Math.round(bottom),
-            Math.round(right), Math.round(top)
-        );
-    },
-
-    /**
-     * Method: getRectBoundsFromMapBounds
-     * Get the rect bounds from the map bounds.
-     *
-     * Parameters:
-     * lonLatBounds - {<OpenLayers.Bounds>}
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
-     * translated into pixel bounds for the overview map
-     */
-    getRectBoundsFromMapBounds: function(lonLatBounds) {
-        var leftBottomLonLat = new OpenLayers.LonLat(lonLatBounds.left,
-                                                     lonLatBounds.bottom);
-        var rightTopLonLat = new OpenLayers.LonLat(lonLatBounds.right,
-                                                   lonLatBounds.top);
-        var leftBottomPx = this.getOverviewPxFromLonLat(leftBottomLonLat);
-        var rightTopPx = this.getOverviewPxFromLonLat(rightTopLonLat);
-        var bounds = null;
-        if (leftBottomPx && rightTopPx) {
-            bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
-                                           rightTopPx.x, rightTopPx.y);
-        }
-        return bounds;
-    },
-
-    /**
-     * Method: getMapBoundsFromRectBounds
-     * Get the map bounds from the rect bounds.
-     *
-     * Parameters:
-     * pxBounds - {<OpenLayers.Bounds>}
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
-     * translated into lon/lat bounds for the overview map
-     */
-    getMapBoundsFromRectBounds: function(pxBounds) {
-        var leftBottomPx = new OpenLayers.Pixel(pxBounds.left,
-                                                pxBounds.bottom);
-        var rightTopPx = new OpenLayers.Pixel(pxBounds.right,
-                                              pxBounds.top);
-        var leftBottomLonLat = this.getLonLatFromOverviewPx(leftBottomPx);
-        var rightTopLonLat = this.getLonLatFromOverviewPx(rightTopPx);
-        return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
-                                     rightTopLonLat.lon, rightTopLonLat.lat);
-    },
-
-    /**
-     * Method: getLonLatFromOverviewPx
-     * Get a map location from a pixel location
-     *
-     * Parameters:
-     * overviewMapPx - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     * {<OpenLayers.LonLat>} Location which is the passed-in overview map
-     * OpenLayers.Pixel, translated into lon/lat by the overview map
-     */
-    getLonLatFromOverviewPx: function(overviewMapPx) {
-        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); 
-    },
-
-    /**
-     * Method: getOverviewPxFromLonLat
-     * Get a pixel location from a map location
-     *
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     *
-     * Returns:
-     * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat, 
-     * translated into overview map pixels
-     */
-    getOverviewPxFromLonLat: function(lonlat) {
-        var res  = this.ovmap.getResolution();
-        var extent = this.ovmap.getExtent();
-        var px = null;
-        if (extent) {
-            px = new OpenLayers.Pixel(
-                        Math.round(1/res * (lonlat.lon - extent.left)),
-                        Math.round(1/res * (extent.top - lonlat.lat)));
-        } 
-        return px;
-    },
-
-    CLASS_NAME: 'OpenLayers.Control.OverviewMap'
-});
-/* ======================================================================
-    OpenLayers/Feature.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/Util.js
- * @requires OpenLayers/Marker.js
- * @requires OpenLayers/Popup/AnchoredBubble.js
- */
-
-/**
- * Class: OpenLayers.Feature
- * Features are combinations of geography and attributes. The OpenLayers.Feature
- *     class specifically combines a marker and a lonlat.
- */
-OpenLayers.Feature = OpenLayers.Class({
-
-    /** 
-     * Property: layer 
-     * {<OpenLayers.Layer>} 
-     */
-    layer: null,
-
-    /** 
-     * Property: id 
-     * {String} 
-     */
-    id: null,
-    
-    /** 
-     * Property: lonlat 
-     * {<OpenLayers.LonLat>} 
-     */
-    lonlat: null,
-
-    /** 
-     * Property: data 
-     * {Object} 
-     */
-    data: null,
-
-    /** 
-     * Property: marker 
-     * {<OpenLayers.Marker>} 
-     */
-    marker: null,
-
-    /**
-     * APIProperty: popupClass
-     * {<OpenLayers.Class>} The class which will be used to instantiate
-     *     a new Popup. Default is <OpenLayers.Popup.AnchoredBubble>.
-     */
-    popupClass: OpenLayers.Popup.AnchoredBubble,
-
-    /** 
-     * Property: popup 
-     * {<OpenLayers.Popup>} 
-     */
-    popup: null,
-
-    /** 
-     * Constructor: OpenLayers.Feature
-     * Constructor for features.
-     *
-     * Parameters:
-     * layer - {<OpenLayers.Layer>} 
-     * lonlat - {<OpenLayers.LonLat>} 
-     * data - {Object} 
-     * 
-     * Returns:
-     * {<OpenLayers.Feature>}
-     */
-    initialize: function(layer, lonlat, data) {
-        this.layer = layer;
-        this.lonlat = lonlat;
-        this.data = (data != null) ? data : {};
-        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); 
-    },
-
-    /** 
-     * Method: destroy
-     * nullify references to prevent circular references and memory leaks
-     */
-    destroy: function() {
-
-        //remove the popup from the map
-        if ((this.layer != null) && (this.layer.map != null)) {
-            if (this.popup != null) {
-                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;
-        this.lonlat = null;
-        this.data = null;
-        if (this.marker != null) {
-            this.destroyMarker(this.marker);
-            this.marker = null;
-        }
-        if (this.popup != null) {
-            this.destroyPopup(this.popup);
-            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: 
-     * {<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() {
-
-        if (this.lonlat != null) {
-            this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);
-        }
-        return this.marker;
-    },
-
-    /**
-     * Method: destroyMarker
-     * Destroys marker.
-     * If user overrides the createMarker() function, s/he should be able
-     *   to also specify an alternative function for destroying it
-     */
-    destroyMarker: function() {
-        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. 
-     *  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: 
-     * 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.lonlat,
-                                                 this.data.popupSize,
-                                                 this.data.popupContentHTML,
-                                                 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 
-     *   should also be able to override the destruction
-     */
-    destroyPopup: function() {
-        if (this.popup) {
-            this.popup.feature = null;
-            this.popup.destroy();
-            this.popup = null;
-        }    
-    },
-
-    CLASS_NAME: "OpenLayers.Feature"
-});
-/* ======================================================================
-    OpenLayers/Format/WFSCapabilities.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/XML.js
- */
-
-/**
- * Class: OpenLayers.Format.WFSCapabilities
- * Read WFS Capabilities.
+ * 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. 
  * 
- * Inherits from:
- *  - <OpenLayers.Format.XML>
- */
-OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML, {
-    
-    /**
-     * APIProperty: defaultVersion
-     * {String} Version number to assume if none found.  Default is "1.1.0".
-     */
-    defaultVersion: "1.1.0",
-    
-    /**
-     * APIProperty: version
-     * {String} Specify a version string if one is known.
-     */
-    version: null,
-
-    /**
-     * Constructor: OpenLayers.Format.WFSCapabilities
-     * Create a new parser for WFS capabilities.
-     *
-     * Parameters:
-     * options - {Object} An optional object whose properties will be set on
-     *     this instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
-        this.options = options;
-    },
-
-    /**
-     * APIMethod: read
-     * Read capabilities data from a string, and return a list of layers. 
-     * 
-     * Parameters: 
-     * data - {String} or {DOMElement} data to read/parse.
-     *
-     * Returns:
-     * {Array} List of named layers.
-     */
-    read: function(data) {
-        if(typeof data == "string") {
-            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
-        }
-        var root = data.documentElement;
-        var version = this.version;
-        if(!version) {
-            version = root.getAttribute("version");
-            if(!version) {
-                version = this.defaultVersion;
-            }
-        }
-        var constr = OpenLayers.Format.WFSCapabilities[
-            "v" + version.replace(/\./g, "_")
-        ];
-        if(!constr) {
-            throw "Can't find a WFS capabilities parser for version " + version;
-        }
-        var parser = new constr(this.options);
-        var capabilities = parser.read(data);
-        capabilities.version = version;
-        return capabilities;
-    },
-    
-    CLASS_NAME: "OpenLayers.Format.WFSCapabilities" 
-
-});
-/* ======================================================================
-    OpenLayers/Format/WFSDescribeFeatureType.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/XML.js
+ * 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
+ * transformed according to the transformation function.
  *
- * Class: OpenLayers.Format.WFSDescribeFeatureType
- * Read WFS DescribeFeatureType response
- * 
- * Inherits from:
- *  - <OpenLayers.Format.XML>
+ * Note - Properties on this object should not be set directly.  To add a
+ *     transform method to this object, use the <addTransform> method.  For an
+ *     example of usage, see the OpenLayers.Layer.SphericalMercator file.
  */
-OpenLayers.Format.WFSDescribeFeatureType = OpenLayers.Class(
-    OpenLayers.Format.XML, {
-    
-    /**
-     * Property: namespaces
-     * {Object} Mapping of namespace aliases to namespace URIs.
-     */
-    namespaces: {
-        xsd: "http://www.w3.org/2001/XMLSchema"
-    },
-    
-    /**
-     * Constructor: OpenLayers.Format.WFSDescribeFeatureType
-     * Create a new parser for WFS DescribeFeatureType responses.
-     *
-     * Parameters:
-     * options - {Object} An optional object whose properties will be set on
-     *     this instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
-    },
-    
-    /**
-     * Property: readers
-     * Contains public functions, grouped by namespace prefix, that will
-     *     be applied when a namespaced node is found matching the function
-     *     name.  The function will be applied in the scope of this parser
-     *     with two arguments: the node being read and a context object passed
-     *     from the parent.
-     */
-    readers: {
-        "xsd": {
-            "schema": function(node, obj) {
-                var complexTypes = [];
-                var customTypes = {};
-                var schema = {
-                    complexTypes: complexTypes,
-                    customTypes: customTypes
-                };
-                
-                this.readChildNodes(node, schema);
+OpenLayers.Projection.transforms = {};
 
-                var attributes = node.attributes;
-                var attr, name;
-                for(var i=0, len=attributes.length; i<len; ++i) {
-                    attr = attributes[i];
-                    name = attr.name;
-                    if(name.indexOf("xmlns") == 0) {
-                        this.setNamespace(name.split(":")[1] || "", attr.value);
-                    } else {
-                        obj[name] = attr.value;
-                    }
-                }
-                obj.featureTypes = complexTypes;                
-                obj.targetPrefix = this.namespaceAlias[obj.targetNamespace];
-                
-                // map complexTypes to names of customTypes
-                var complexType, customType;
-                for(var i=0, len=complexTypes.length; i<len; ++i) {
-                    complexType = complexTypes[i];
-                    customType = customTypes[complexType.typeName];
-                    if(customTypes[complexType.typeName]) {
-                        complexType.typeName = customType.name;
-                    }
-                }
-            },
-            "complexType": function(node, obj) {
-                var complexType = {
-                    // this is a temporary typeName, it will be overwritten by
-                    // the schema reader with the metadata found in the
-                    // customTypes hash
-                    "typeName": node.getAttribute("name")
-                };
-                this.readChildNodes(node, complexType);
-                obj.complexTypes.push(complexType);
-            },
-            "complexContent": function(node, obj) {
-                this.readChildNodes(node, obj);
-            },
-            "extension": function(node, obj) {
-                this.readChildNodes(node, obj);
-            },
-            "sequence": function(node, obj) {
-                var sequence = {
-                    elements: []
-                };
-                this.readChildNodes(node, sequence);
-                obj.properties = sequence.elements;
-            },
-            "element": function(node, obj) {
-                if(obj.elements) {
-                    var element = {};
-                    var attributes = node.attributes;
-                    var attr;
-                    for(var i=0, len=attributes.length; i<len; ++i) {
-                        attr = attributes[i];
-                        element[attr.name] = attr.value;
-                    }
-                    
-                    var type = element.type;
-                    if(!type) {
-                        type = {};
-                        this.readChildNodes(node, type);
-                        element.restriction = type;
-                        element.type = type.base;
-                    }
-                    var fullType = type.base || type;
-                    element.localType = fullType.split(":").pop();
-                    obj.elements.push(element);
-                }
-                
-                if(obj.complexTypes) {
-                    var type = node.getAttribute("type");
-                    var localType = type.split(":").pop();
-                    obj.customTypes[localType] = {
-                        "name": node.getAttribute("name"),
-                        "type": type
-                    };
-                }
-            },
-            "simpleType": function(node, obj) {
-                this.readChildNodes(node, obj);
-            },
-            "restriction": function(node, obj) {
-                obj.base = node.getAttribute("base");
-                this.readRestriction(node, obj);
-            }
-        }
-    },
-    
-    /**
-     * Method: readRestriction
-     * Reads restriction defined in the child nodes of a restriction element
-     * 
-     * Parameters:
-     * node {DOMElement} - the node to parse
-     * obj {Object} - the object that receives the read result
-     */
-    readRestriction: function(node, obj) {
-        var children = node.childNodes;
-        var child, nodeName, value;
-        for(var i=0, len=children.length; i<len; ++i) {
-            child = children[i];
-            if(child.nodeType == 1) {
-                nodeName = child.nodeName.split(":").pop();
-                value = child.getAttribute("value");
-                if(!obj[nodeName]) {
-                    obj[nodeName] = value;
-                } else {
-                    if(typeof obj[nodeName] == "string") {
-                        obj[nodeName] = [obj[nodeName]];
-                    }
-                    obj[nodeName].push(value);
-                }
-            }
-        }
-    },
-    
-    /**
-     * Method: read
-     *
-     * Parameters:
-     * data - {DOMElement|String} A WFS DescribeFeatureType document.
-     *
-     * Returns:
-     * {Object} An object representing the WFS DescribeFeatureType response.
-     */
-    read: function(data) {
-        if(typeof data == "string") { 
-            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
-        }
-        if(data && data.nodeType == 9) {
-            data = data.documentElement;
-        }
-        var schema = {};
-        this.readNode(data, schema);
-        
-        return schema;
-    },
-    
-    CLASS_NAME: "OpenLayers.Format.WFSDescribeFeatureType" 
-
-});
-/* ======================================================================
-    OpenLayers/Format/WFST/v1.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/XML.js
- * @requires OpenLayers/Format/WFST.js
- */
-
-/**
- * Class: OpenLayers.Format.WFST.v1
- * Superclass for WFST parsers.
+ * APIMethod: addTransform
+ * Set a custom transform method between two projections.  Use this method in
+ *     cases where the proj4js lib is not available or where custom projections
+ *     need to be handled.
  *
- * Inherits from:
- *  - <OpenLayers.Format.XML>
+ * Parameters:
+ * from - {String} The code for the source projection
+ * to - {String} the code for the destination projection
+ * method - {Function} A function that takes a point as an argument and
+ *     transforms that point from the source to the destination projection
+ *     in place.  The original point should be modified.
  */
-OpenLayers.Format.WFST.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
-    
-    /**
-     * Property: namespaces
-     * {Object} Mapping of namespace aliases to namespace URIs.
-     */
-    namespaces: {
-        xlink: "http://www.w3.org/1999/xlink",
-        xsi: "http://www.w3.org/2001/XMLSchema-instance",
-        wfs: "http://www.opengis.net/wfs",
-        gml: "http://www.opengis.net/gml",
-        ogc: "http://www.opengis.net/ogc"
-    },
-    
-    /**
-     * Property: defaultPrefix
-     */
-    defaultPrefix: "wfs",
+OpenLayers.Projection.addTransform = function(from, to, method) {
+    if(!OpenLayers.Projection.transforms[from]) {
+        OpenLayers.Projection.transforms[from] = {};
+    }
+    OpenLayers.Projection.transforms[from][to] = method;
+};
 
-    /**
-     * Property: version
-     * {String} WFS version number.
-     */
-    version: null,
-
-    /**
-     * Property: schemaLocation
-     * {String} Schema location for a particular minor version.
-     */
-    schemaLocations: null,
-    
-    /**
-     * APIProperty: srsName
-     * {String} URI for spatial reference system.
-     */
-    srsName: null,
-
-    /**
-     * APIProperty: extractAttributes
-     * {Boolean} Extract attributes from GML.  Default is true.
-     */
-    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,
-
-    /**
-     * Property: stateName
-     * {Object} Maps feature states to node names.
-     */
-    stateName: null,
-
-    /**
-     * Constructor: OpenLayers.Format.WFST.v1
-     * Instances of this class are not created directly.  Use the
-     *     <OpenLayers.Format.WFST.v1_0_0> or <OpenLayers.Format.WFST.v1_1_0>
-     *     constructor instead.
-     *
-     * Parameters:
-     * options - {Object} An optional object whose properties will be set on
-     *     this instance.
-     */
-    initialize: function(options) {
-        // set state name mapping
-        this.stateName = {};
-        this.stateName[OpenLayers.State.INSERT] = "wfs:Insert";
-        this.stateName[OpenLayers.State.UPDATE] = "wfs:Update";
-        this.stateName[OpenLayers.State.DELETE] = "wfs:Delete";
-        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
-    },
-    
-    /**
-     * Method: getSrsName
-     */
-    getSrsName: function(feature, options) {
-        var srsName = options && options.srsName;
-        if(!srsName) {
-            if(feature && feature.layer) {
-                srsName = feature.layer.projection.getCode();
-            } else {
-                srsName = this.srsName;
-            }
-        }
-        return srsName;
-    },
-
-    /**
-     * APIMethod: read
-     * Parse the response from a transaction.  Because WFS is split into
-     *     Transaction requests (create, update, and delete) and GetFeature
-     *     requests (read), this method handles parsing of both types of
-     *     responses.
-     *
-     * Parameters:
-     * data - {String | Document} The WFST document to read
-     * options - {Object} Options for the reader
-     *
-     * Valid options properties:
-     * output - {String} either "features" or "object". The default is
-     *     "features", which means that the method will return an array of
-     *     features. If set to "object", an object with a "features" property
-     *     and other properties read by the parser will be returned.
-     *
-     * Returns:
-     * {Array | Object} Output depending on the output option.
-     */
-    read: function(data, options) {
-        options = options || {};
-        OpenLayers.Util.applyDefaults(options, {
-            output: "features"
-        });
-        
-        if(typeof data == "string") { 
-            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
-        }
-        if(data && data.nodeType == 9) {
-            data = data.documentElement;
-        }
-        var obj = {};
-        if(data) {
-            this.readNode(data, obj);
-        }
-        if(obj.features && options.output === "features") {
-            obj = obj.features;
-        }
-        return obj;
-    },
-    
-    /**
-     * Property: readers
-     * Contains public functions, grouped by namespace prefix, that will
-     *     be applied when a namespaced node is found matching the function
-     *     name.  The function will be applied in the scope of this parser
-     *     with two arguments: the node being read and a context object passed
-     *     from the parent.
-     */
-    readers: {
-        "wfs": {
-            "FeatureCollection": function(node, obj) {
-                obj.features = [];
-                this.readChildNodes(node, obj);
-            }
-        }
-    },
-    
-    /**
-     * Method: write
-     * Given an array of features, write a WFS transaction.  This assumes
-     *     the features have a state property that determines the operation
-     *     type - insert, update, or delete.
-     *
-     * Parameters:
-     * features - {Array(<OpenLayers.Feature.Vector>)} A list of features.
-     *
-     * Returns:
-     * {String} A serialized WFS transaction.
-     */
-    write: function(features) {
-        var node = this.writeNode("wfs:Transaction", features);
-        var value = this.schemaLocationAttr();
-        if(value) {
-            this.setAttributeNS(
-                node, this.namespaces["xsi"], "xsi:schemaLocation",  value
-            )
-        }
-        return OpenLayers.Format.XML.prototype.write.apply(this, [node]);
-    },
-    
-    /**
-     * Property: writers
-     * As a compliment to the readers property, this structure contains public
-     *     writing functions grouped by namespace alias and named like the
-     *     node names they produce.
-     */
-    writers: {
-        "wfs": {
-            "GetFeature": function(options) {
-                var node = this.createElementNSPlus("wfs:GetFeature", {
-                    attributes: {
-                        service: "WFS",
-                        version: this.version,
-                        outputFormat: options && options.outputFormat,
-                        maxFeatures: options && options.maxFeatures,
-                        "xsi:schemaLocation": this.schemaLocationAttr(options)
-                    }
-                });
-                if (typeof this.featureType == "string") {
-                    this.writeNode("Query", options, node);
-                } else {
-                    for (var i=0,len = this.featureType.length; i<len; i++) { 
-                        options.featureType = this.featureType[i]; 
-                        this.writeNode("Query", options, node); 
-                    } 
-                }
-                return node;
-            },
-            "Transaction": function(features) {
-                var node = this.createElementNSPlus("wfs:Transaction", {
-                    attributes: {
-                        service: "WFS",
-                        version: this.version
-                    }
-                });
-                if(features) {
-                    var name, feature;
-                    for(var i=0, len=features.length; i<len; ++i) {
-                        feature = features[i];
-                        name = this.stateName[feature.state];
-                        if(name) {
-                            this.writeNode(name, feature, node);
-                        }
-                    }
-                }
-                return node;
-            },
-            "Insert": function(feature) {
-                var node = this.createElementNSPlus("wfs:Insert");
-                this.srsName = this.getSrsName(feature);
-                this.writeNode("feature:_typeName", feature, node);
-                return node;
-            },
-            "Update": function(feature) {
-                var node = this.createElementNSPlus("wfs:Update", {
-                    attributes: {
-                        typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
-                            this.featureType
-                    }
-                });
-                if(this.featureNS) {
-                    node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
-                }
-                
-                // add in geometry
-                if (this.geometryName !== null) {
-                    this.writeNode(
-                        "Property", {name: this.geometryName, value: feature}, node
-                    );
-                }
-        
-                // add in attributes
-                for(var key in feature.attributes) {
-                    if(feature.attributes[key] !== undefined) {
-                        this.writeNode(
-                            "Property", {name: key, value: feature.attributes[key]}, node
-                        );
-                    }
-                }
-                
-                // add feature id filter
-                this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
-                    fids: [feature.fid]
-                }), node);
-        
-                return node;
-            },
-            "Property": function(obj) {
-                var node = this.createElementNSPlus("wfs:Property");
-                this.writeNode("Name", obj.name, node);
-                if(obj.value !== null) {
-                    this.writeNode("Value", obj.value, node);
-                }
-                return node;
-            },
-            "Name": function(name) {
-                return this.createElementNSPlus("wfs:Name", {value: name});
-            },
-            "Value": function(obj) {
-                var node;
-                if(obj instanceof OpenLayers.Feature.Vector) {
-                    node = this.createElementNSPlus("wfs:Value");
-                    this.srsName = this.getSrsName(obj);
-                    var geom = this.writeNode("feature:_geometry", obj.geometry).firstChild;
-                    node.appendChild(geom);
-                } else {
-                    node = this.createElementNSPlus("wfs:Value", {value: obj});                
-                }
-                return node;
-            },
-            "Delete": function(feature) {
-                var node = this.createElementNSPlus("wfs:Delete", {
-                    attributes: {
-                        typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
-                            this.featureType
-                    }
-                });
-                if(this.featureNS) {
-                    node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
-                }
-                this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
-                    fids: [feature.fid]
-                }), node);
-                return node;
-            }
-        }
-    },
-
-    /**
-     * Method: schemaLocationAttr
-     * Generate the xsi:schemaLocation attribute value.
-     *
-     * Returns:
-     * {String} The xsi:schemaLocation attribute or undefined if none.
-     */
-    schemaLocationAttr: function(options) {
-        options = OpenLayers.Util.extend({
-            featurePrefix: this.featurePrefix,
-            schema: this.schema
-        }, options);
-        var schemaLocations = OpenLayers.Util.extend({}, this.schemaLocations);
-        if(options.schema) {
-            schemaLocations[options.featurePrefix] = options.schema;
-        }
-        var parts = [];
-        var uri;
-        for(var key in schemaLocations) {
-            uri = this.namespaces[key];
-            if(uri) {
-                parts.push(uri + " " + schemaLocations[key]);
-            }
-        }
-        var value = parts.join(" ") || undefined;
-        return value;
-    },
-    
-    /**
-     * Method: setFilterProperty
-     * Set the property of each spatial filter.
-     *
-     * Parameters:
-     * filter - {<OpenLayers.Filter>}
-     */
-    setFilterProperty: function(filter) {
-        if(filter.filters) {
-            for(var i=0, len=filter.filters.length; i<len; ++i) {
-                this.setFilterProperty(filter.filters[i]);
-            }
-        } else {
-            if(filter instanceof OpenLayers.Filter.Spatial) {
-                // got a spatial filter, set its property
-                filter.property = this.geometryName;
-            }
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Format.WFST.v1" 
-
-});
-/* ======================================================================
-    OpenLayers/Handler/Click.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/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Click
- * A handler for mouse clicks.  The intention of this handler is to give
- *     controls more flexibility with handling clicks.  Browsers trigger
- *     click events twice for a double-click.  In addition, the mousedown,
- *     mousemove, mouseup sequence fires a click event.  With this handler,
- *     controls can decide whether to ignore clicks associated with a double
- *     click.  By setting a <pixelTolerance>, controls can also ignore clicks
- *     that include a drag.  Create a new instance with the
- *     <OpenLayers.Handler.Click> constructor.
+ * APIMethod: transform
+ * Transform a point coordinate from one projection to another.  Note that
+ *     the input point is transformed in place.
  * 
- * Inherits from:
- *  - <OpenLayers.Handler> 
- */
-OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
-
-    /**
-     * APIProperty: delay
-     * {Number} Number of milliseconds between clicks before the event is
-     *     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
-     *     event to be considered a click.  Default is 0.  If set to an
-     *     integer value, clicks with a drag greater than the value will be
-     *     ignored.  This property can only be set when the handler is
-     *     constructed.
-     */
-    pixelTolerance: 0,
-    
-    /**
-     * APIProperty: stopSingle
-     * {Boolean} Stop other listeners from being notified of clicks.  Default
-     *     is false.  If true, any click listeners registered before this one
-     *     will not be notified of *any* click event (associated with double
-     *     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
-     *     uniform cross-browser performance.  Since IE triggers one click
-     *     with a dblclick and FF triggers two, if a stopSingle handler is
-     *     activated first, all it gets in IE is a single click when the
-     *     second handler stops propagation on the dblclick.
-     */
-    stopDouble: false,
-
-    /**
-     * Property: timerId
-     * {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 
-     *     <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
-     *     handler's setMap method must be overridden to deal properly with
-     *     the map.
-     * callbacks - {Object} An object with keys corresponding to callbacks
-     *     that will be called by the handler. The callbacks should
-     *     expect to recieve a single argument, the click event.
-     *     Callbacks for 'click' and 'dblclick' are supported.
-     * options - {Object} Optional object whose properties will be set on the
-     *     handler.
-     */
-    initialize: function(control, callbacks, options) {
-        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
-        // optionally register for mouseup and mousedown
-        if(this.pixelTolerance != null) {
-            this.mousedown = function(evt) {
-                this.down = evt.xy;
-                return true;
-            };
-        }
-    },
-    
-    /**
-     * Method: mousedown
-     * Handle mousedown.  Only registered as a listener if pixelTolerance is
-     *     a non-zero value at construction.
-     *
-     * Returns:
-     * {Boolean} Continue propagating this event.
-     */
-    mousedown: null,
-
-    /**
-     * Method: mouseup
-     * Handle mouseup.  Installed to support collection of right mouse events.
-     * 
-     * Returns:
-     * {Boolean} Continue propagating this event.
-     */
-    mouseup:  function (evt) {
-        var propagate = true;
-
-        // 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 && 
-            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 
-     *     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 
-                // a double click
-                this.clearTimer();      
-                this.callback('dblrightclick', [evt]);
-                return !this.stopDouble;
-            } else { 
-                //Set the rightclickTimerId, send evt only if double is 
-                // true else trigger single
-                var clickEvent = this['double'] ?
-                    OpenLayers.Util.extend({}, evt) : 
-                    this.callback('rightclick', [evt]);
-
-                var delayedRightCall = OpenLayers.Function.bind(
-                    this.delayedRightCall, 
-                    this, 
-                    clickEvent
-                );
-                this.rightclickTimerId = window.setTimeout(
-                    delayedRightCall, this.delay
-                );
-            } 
-        }
-        return !this.stopSingle;
-    },
-    
-    /**
-     * Method: delayedRightCall
-     * Sets <rightclickTimerId> to null.  And optionally triggers the 
-     *     rightclick callback if evt is set.
-     */
-    delayedRightCall: function(evt) {
-        this.rightclickTimerId = null;
-        if (evt) {
-           this.callback('rightclick', [evt]);
-        }
-        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.
-     */
-    dblclick: function(evt) {
-        if(this.passesTolerance(evt)) {
-            if(this["double"]) {
-                this.callback('dblclick', [evt]);
-            }
-            this.clearTimer();
-        }
-        return !this.stopDouble;
-    },
-    
-    /**
-     * Method: click
-     * Handle click.
-     *
-     * Returns:
-     * {Boolean} Continue propagating this event.
-     */
-    click: function(evt) {
-        if(this.passesTolerance(evt)) {
-            if(this.timerId != null) {
-                // already received a click
-                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 
-                //be a valid event object in IE in the timer callback
-                var clickEvent = this.single ?
-                    OpenLayers.Util.extend({}, evt) : null;
-                this.timerId = window.setTimeout(
-                    OpenLayers.Function.bind(this.delayedCall, this, clickEvent),
-                    this.delay
-                );
-            }
-        }
-        return !this.stopSingle;
-    },
-    
-    /**
-     * Method: passesTolerance
-     * Determine whether the event is within the optional pixel tolerance.  Note
-     *     that the pixel tolerance check only works if mousedown events get to
-     *     the listeners registered here.  If they are stopped by other elements,
-     *     the <pixelTolerance> will have no effect here (this method will always
-     *     return true).
-     *
-     * Returns:
-     * {Boolean} The click is within the pixel tolerance (if specified).
-     */
-    passesTolerance: function(evt) {
-        var passes = true;
-        if(this.pixelTolerance != null && this.down) {
-            var dpx = Math.sqrt(
-                Math.pow(this.down.x - evt.xy.x, 2) +
-                Math.pow(this.down.y - evt.xy.y, 2)
-            );
-            if(dpx > this.pixelTolerance) {
-                passes = false;
-            }
-        }
-        return passes;
-    },
-
-    /**
-     * Method: clearTimer
-     * Clear the timer and set <timerId> to null.
-     */
-    clearTimer: function() {
-        if(this.timerId != null) {
-            window.clearTimeout(this.timerId);
-            this.timerId = null;
-        }
-        if(this.rightclickTimerId != null) {
-            window.clearTimeout(this.rightclickTimerId);
-            this.rightclickTimerId = null;
-        }
-    },
-    
-    /**
-     * Method: delayedCall
-     * Sets <timerId> to null.  And optionally triggers the click callback if
-     *     evt is set.
-     */
-    delayedCall: function(evt) {
-        this.timerId = null;
-        if(evt) {
-            this.callback('click', [evt]);
-        }
-    },
-
-    /**
-     * APIMethod: deactivate
-     * Deactivate the handler.
-     *
-     * Returns:
-     * {Boolean} The handler was successfully deactivated.
-     */
-    deactivate: function() {
-        var deactivated = false;
-        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
-            this.clearTimer();
-            this.down = null;
-            deactivated = true;
-        }
-        return deactivated;
-    },
-
-    CLASS_NAME: "OpenLayers.Handler.Click"
-});
-/* ======================================================================
-    OpenLayers/Handler/Drag.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/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Drag
- * The drag handler is used to deal with sequences of browser events related
- *     to dragging.  The handler is used by controls that want to know when
- *     a drag sequence begins, when a drag is happening, and when it has
- *     finished.
+ * Parameters:
+ * point - {{OpenLayers.Geometry.Point> | Object} An object with x and y
+ *     properties representing coordinates in those dimensions.
+ * sourceProj - {OpenLayers.Projection} Source map coordinate system
+ * destProj - {OpenLayers.Projection} Destination map coordinate system
  *
- * Controls that use the drag handler typically construct it with callbacks
- *     for 'down', 'move', and 'done'.  Callbacks for these keys are called
- *     when the drag begins, with each move, and when the drag is done.  In
- *     addition, controls can have callbacks keyed to 'up' and 'out' if they
- *     care to differentiate between the types of events that correspond with
- *     the end of a drag sequence.  If no drag actually occurs (no mouse move)
- *     the 'down' and 'up' callbacks will be called, but not the 'done'
- *     callback.
- *
- * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor.
- *
- * Inherits from:
- *  - <OpenLayers.Handler>
+ * Returns:
+ * point - {object} A transformed coordinate.  The original point is modified.
  */
-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. 
-     */
-    started: false,
-    
-    /**
-     * Property: stopDown
-     * {Boolean} Stop propagation of mousedown events from getting to listeners
-     *     on the same element.  Default is true.
-     */
-    stopDown: true,
+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()] && 
+               OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]) {
+        OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point); 
+    }
+    return point;
+};
 
-    /** 
-     * 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.
-     */
-    start: null,
-
-    /**
-     * Property: oldOnselectstart
-     * {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. 
-     */
-    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
-     *     handlers setMap method must be overridden to deal properly with
-     *     the map.
-     * 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 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} 
-     */
-    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.
-     *     Subclasses can do their own processing here.
-     *
-     * Parameters:
-     * evt - {Event} The mouse down event
-     */
-    down: function(evt) {
-    },
-    
-    /**
-     * Method: move
-     * This method is called during the handling of the mouse move event.
-     *     Subclasses can do their own processing here.
-     *
-     * Parameters:
-     * evt - {Event} The mouse move event
-     *
-     */
-    move: function(evt) {
-    },
-
-    /**
-     * Method: up
-     * This method is called during the handling of the mouse up event.
-     *     Subclasses can do their own processing here.
-     *
-     * Parameters:
-     * evt - {Event} The mouse up event
-     */
-    up: function(evt) {
-    },
-
-    /**
-     * Method: out
-     * This method is called during the handling of the mouse out event.
-     *     Subclasses can do their own processing here.
-     *
-     * Parameters:
-     * evt - {Event} The mouse out event
-     */
-    out: function(evt) {
-    },
-
-    /**
-     * The methods below are part of the magic of event handling.  Because
-     *     they are named like browser events, they are registered as listeners
-     *     for the events they represent.
-     */
-
-    /**
-     * Method: mousedown
-     * Handle mousedown events
-     *
-     * Parameters:
-     * evt - {Event} 
-     *
-     * Returns:
-     * {Boolean} Let the event propagate.
-     */
-    mousedown: function (evt) {
-        var propagate = true;
-        this.dragging = false;
-        if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) {
-            this.started = true;
-            this.start = evt.xy;
-            this.last = evt.xy;
-            OpenLayers.Element.addClass(
-                this.map.viewPortDiv, "olDragDown"
-            );
-            this.down(evt);
-            this.callback("down", [evt.xy]);
-            OpenLayers.Event.stop(evt);
-            
-            if(!this.oldOnselectstart) {
-                this.oldOnselectstart = (document.onselectstart) ? document.onselectstart : OpenLayers.Function.True;
-            }
-            document.onselectstart = OpenLayers.Function.False;
-            
-            propagate = !this.stopDown;
-        } else {
-            this.started = false;
-            this.start = null;
-            this.last = null;
-        }
-        return propagate;
-    },
-
-    /**
-     * Method: mousemove
-     * Handle mousemove events
-     *
-     * Parameters:
-     * 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);
-            }
-            this.dragging = true;
-            this.move(evt);
-            this.callback("move", [evt.xy]);
-            if(!this.oldOnselectstart) {
-                this.oldOnselectstart = document.onselectstart;
-                document.onselectstart = OpenLayers.Function.False;
-            }
-            this.last = this.evt.xy;
-        }
-        return true;
-    },
-    
-    /**
-     * Method: removeTimeout
-     * Private. Called by mousemove() to remove the drag timeout.
-     */
-    removeTimeout: function() {
-        this.timeoutId = null;
-    },
-
-    /**
-     * Method: mouseup
-     * Handle mouseup events
-     *
-     * Parameters:
-     * 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;
-            OpenLayers.Element.removeClass(
-                this.map.viewPortDiv, "olDragDown"
-            );
-            this.up(evt);
-            this.callback("up", [evt.xy]);
-            if(dragged) {
-                this.callback("done", [evt.xy]);
-            }
-            document.onselectstart = this.oldOnselectstart;
-        }
-        return true;
-    },
-
-    /**
-     * Method: mouseout
-     * Handle mouseout events
-     *
-     * Parameters:
-     * evt - {Event} 
-     *
-     * Returns:
-     * {Boolean} Let the event propagate.
-     */
-    mouseout: function (evt) {
-        if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
-            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;
-                }
-            }
-        }
-        return true;
-    },
-
-    /**
-     * 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 
-     *     after a drag.
-     * 
-     * Parameters: 
-     * evt - {Event} 
-     * 
-     * Returns:
-     * {Boolean} Let the event propagate.
-     */
-    click: function (evt) {
-        // let the click event propagate only if the mouse moved
-        return (this.start == this.last);
-    },
-
-    /**
-     * Method: activate
-     * Activate the handler.
-     * 
-     * Returns:
-     * {Boolean} The handler was successfully activated.
-     */
-    activate: function() {
-        var activated = false;
-        if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
-            this.dragging = false;
-            activated = true;
-        }
-        return activated;
-    },
-
-    /**
-     * Method: deactivate 
-     * Deactivate the handler.
-     * 
-     * Returns:
-     * {Boolean} The handler was successfully deactivated.
-     */
-    deactivate: function() {
-        var deactivated = false;
-        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
-            this.started = false;
-            this.dragging = false;
-            this.start = null;
-            this.last = null;
-            deactivated = true;
-            OpenLayers.Element.removeClass(
-                this.map.viewPortDiv, "olDragDown"
-            );
-        }
-        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"
-});
-/* ======================================================================
-    OpenLayers/Handler/Feature.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/Handler.js
- */
-
-/**
- * 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.
+ * APIFunction: nullTransform
+ * A null transformation - useful for defining projection aliases when
+ * proj4js is not available:
  *
- * This handler stops event propagation for mousedown and mouseup if those
- *     browser events target features that can be selected.
+ * (code)
+ * OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:3857",
+ *     OpenLayers.Layer.SphericalMercator.projectForward);
+ * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:3857",
+ *     OpenLayers.Layer.SphericalMercator.projectInverse);
+ * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:900913",
+ *     OpenLayers.Projection.nullTransform);
+ * OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:3857",
+ *     OpenLayers.Projection.nullTransform);
+ * (end)
  */
-OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, {
-
-    /**
-     * Property: EVENTMAP
-     * {Object} A object mapping the browser events to objects with callback
-     *     keys for in and out.
-     */
-    EVENTMAP: {
-        'click': {'in': 'click', 'out': 'clickout'},
-        'mousemove': {'in': 'over', 'out': 'out'},
-        'dblclick': {'in': 'dblclick', 'out': null},
-        'mousedown': {'in': null, 'out': null},
-        'mouseup': {'in': null, 'out': null}
-    },
-
-    /**
-     * Property: feature
-     * {<OpenLayers.Feature.Vector>} The last feature that was hovered.
-     */
-    feature: null,
-
-    /**
-     * Property: lastFeature
-     * {<OpenLayers.Feature.Vector>} The last feature that was handled.
-     */
-    lastFeature: null,
-
-    /**
-     * Property: down
-     * {<OpenLayers.Pixel>} The location of the last mousedown.
-     */
-    down: null,
-
-    /**
-     * Property: up
-     * {<OpenLayers.Pixel>} The location of the last mouseup.
-     */
-    up: null,
-    
-    /**
-     * Property: clickTolerance
-     * {Number} The number of pixels the mouse can move between mousedown
-     *     and mouseup for the event to still be considered a click.
-     *     Dragging the map should not trigger the click and clickout callbacks
-     *     unless the map is moved by less than this tolerance. Defaults to 4.
-     */
-    clickTolerance: 4,
-
-    /**
-     * 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,
-
-    /**
-     * Property: stopClick
-     * {Boolean} If stopClick is set to true, handled clicks do not
-     *      propagate to other click listeners. Otherwise, handled clicks
-     *      do propagate. Unhandled clicks always propagate, whatever the
-     *      value of stopClick. Defaults to true.
-     */
-    stopClick: true,
-
-    /**
-     * Property: stopDown
-     * {Boolean} If stopDown is set to true, handled mousedowns do not
-     *      propagate to other mousedown listeners. Otherwise, handled
-     *      mousedowns do propagate. Unhandled mousedowns always propagate,
-     *      whatever the value of stopDown. Defaults to true.
-     */
-    stopDown: true,
-
-    /**
-     * Property: stopUp
-     * {Boolean} If stopUp is set to true, handled mouseups do not
-     *      propagate to other mouseup listeners. Otherwise, handled mouseups
-     *      do propagate. Unhandled mouseups always propagate, whatever the
-     *      value of stopUp. Defaults to false.
-     */
-    stopUp: false,
-    
-    /**
-     * Constructor: OpenLayers.Handler.Feature
-     *
-     * Parameters:
-     * 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 
-     *     callback should expect to recieve a single argument, the feature.
-     * options - {Object} 
-     */
-    initialize: function(control, layer, callbacks, options) {
-        OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]);
-        this.layer = layer;
-    },
-
-
-    /**
-     * Method: mousedown
-     * Handle mouse down.  Stop propagation if a feature is targeted by this
-     *     event (stops map dragging during feature selection).
-     * 
-     * Parameters:
-     * 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} 
-     */
-    mouseup: function(evt) {
-        this.up = evt.xy;
-        return this.handle(evt) ? !this.stopUp : true;
-    },
-
-    /**
-     * 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} 
-     *
-     * Returns:
-     * {Boolean}
-     */
-    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} 
-     *
-     * Returns:
-     * {Boolean}
-     */
-    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} 
-     *
-     * Returns:
-     * {Boolean}
-     */
-    dblclick: function(evt) {
-        return !this.handle(evt);
-    },
-
-    /**
-     * Method: geometryTypeMatches
-     * Return true if the geometry type of the passed feature matches
-     *     one of the geometry types in the geometryTypes array.
-     *
-     * Parameters:
-     * feature - {<OpenLayers.Vector.Feature>}
-     *
-     * Returns:
-     * {Boolean}
-     */
-    geometryTypeMatches: function(feature) {
-        return this.geometryTypes == null ||
-            OpenLayers.Util.indexOf(this.geometryTypes,
-                                    feature.geometry.CLASS_NAME) > -1;
-    },
-
-    /**
-     * Method: handle
-     *
-     * Parameters:
-     * evt - {Event}
-     *
-     * Returns:
-     * {Boolean} The event occurred over a relevant feature.
-     */
-    handle: function(evt) {
-        if(this.feature && !this.feature.layer) {
-            // feature has been destroyed
-            this.feature = null;
-        }
-        var type = evt.type;
-        var handled = false;
-        var previouslyIn = !!(this.feature); // previously in a feature
-        var click = (type == "click" || type == "dblclick");
-        this.feature = this.layer.getFeatureFromEvent(evt);
-        if(this.feature && !this.feature.layer) {
-            // feature has been destroyed
-            this.feature = null;
-        }
-        if(this.lastFeature && !this.lastFeature.layer) {
-            // last feature has been destroyed
-            this.lastFeature = null;
-        }
-        if(this.feature) {
-            var inNew = (this.feature != this.lastFeature);
-            if(this.geometryTypeMatches(this.feature)) {
-                // in to a feature
-                if(previouslyIn && inNew) {
-                    // out of last feature and in to another
-                    if(this.lastFeature) {
-                        this.triggerCallback(type, 'out', [this.lastFeature]);
-                    }
-                    this.triggerCallback(type, 'in', [this.feature]);
-                } else if(!previouslyIn || click) {
-                    // in feature for the first time
-                    this.triggerCallback(type, 'in', [this.feature]);
-                }
-                this.lastFeature = this.feature;
-                handled = true;
-            } else {
-                // not in to a feature
-                if(this.lastFeature && (previouslyIn && inNew || click)) {
-                    // out of last feature for the first time
-                    this.triggerCallback(type, 'out', [this.lastFeature]);
-                }
-                // next time the mouse goes in a feature whose geometry type
-                // doesn't match we don't want to call the 'out' callback
-                // again, so let's set this.feature to null so that
-                // previouslyIn will evaluate to false the next time
-                // we enter handle. Yes, a bit hackish...
-                this.feature = null;
-            }
-        } else {
-            if(this.lastFeature && (previouslyIn || click)) {
-                this.triggerCallback(type, 'out', [this.lastFeature]);
-            }
-        }
-        return handled;
-    },
-    
-    /**
-     * Method: triggerCallback
-     * Call the callback keyed in the event map with the supplied arguments.
-     *     For click and clickout, the <clickTolerance> is checked first.
-     *
-     * Parameters:
-     * type - {String}
-     */
-    triggerCallback: function(type, mode, args) {
-        var key = this.EVENTMAP[type][mode];
-        if(key) {
-            if(type == 'click' && this.up && this.down) {
-                // for click/clickout, only trigger callback if tolerance is met
-                var dpx = Math.sqrt(
-                    Math.pow(this.up.x - this.down.x, 2) +
-                    Math.pow(this.up.y - this.down.y, 2)
-                );
-                if(dpx <= this.clickTolerance) {
-                    this.callback(key, args);
-                }
-            } else {
-                this.callback(key, args);
-            }
-        }
-    },
-
-    /**
-     * Method: activate 
-     * Turn on the handler.  Returns false if the handler was already active.
-     *
-     * Returns:
-     * {Boolean}
-     */
-    activate: function() {
-        var activated = false;
-        if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
-            this.moveLayerToTop();
-            this.map.events.on({
-                "removelayer": this.handleMapEvents,
-                "changelayer": this.handleMapEvents,
-                scope: this
-            });
-            activated = true;
-        }
-        return activated;
-    },
-    
-    /**
-     * Method: deactivate 
-     * Turn off the handler.  Returns false if the handler was already active.
-     *
-     * Returns: 
-     * {Boolean}
-     */
-    deactivate: function() {
-        var deactivated = false;
-        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
-            this.moveLayerBack();
-            this.feature = null;
-            this.lastFeature = null;
-            this.down = null;
-            this.up = null;
-            this.map.events.un({
-                "removelayer": this.handleMapEvents,
-                "changelayer": this.handleMapEvents,
-                scope: this
-            });
-            deactivated = true;
-        }
-        return deactivated;
-    },
-    
-    /**
-     * Method handleMapEvents
-     * 
-     * Parameters:
-     * evt - {Object}
-     */
-    handleMapEvents: function(evt) {
-        if (!evt.property || evt.property == "order") {
-            this.moveLayerToTop();
-        }
-    },
-    
-    /**
-     * Method: moveLayerToTop
-     * Moves the layer for this handler to the top, so mouse events can reach
-     * it.
-     */
-    moveLayerToTop: function() {
-        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
-     * array.
-     */
-    moveLayerBack: function() {
-        var index = this.layer.getZIndex() - 1;
-        if (index >= this.map.Z_INDEX_BASE['Feature']) {
-            this.layer.setZIndex(index);
-        } else {
-            this.map.setLayerZIndex(this.layer,
-                this.map.getLayerIndex(this.layer));
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Handler.Feature"
-});
+OpenLayers.Projection.nullTransform = function(point) {
+    return point;
+};
 /* ======================================================================
-    OpenLayers/Handler/Hover.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/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Hover
- * The hover handler is to be used to emulate mouseovers on objects
- *      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.Hover = OpenLayers.Class(OpenLayers.Handler, {
-
-    /**
-     * APIProperty: delay
-     * {Integer} - Number of milliseconds between mousemoves before
-     *      the event is considered a hover. Default is 500.
-     */
-    delay: 500,
-    
-    /**
-     * APIProperty: pixelTolerance
-     * {Integer} - Maximum number of pixels between mousemoves for
-     *      an event to be considered a hover. Default is null.
-     */
-    pixelTolerance: null,
-
-    /**
-     * APIProperty: stopMove
-     * {Boolean} - Stop other listeners from being notified on mousemoves.
-     *      Default is false.
-     */
-    stopMove: false,
-
-    /**
-     * Property: px
-     * {<OpenLayers.Pixel>} - The location of the last mousemove, expressed
-     *      in pixels.
-     */
-    px: null,
-
-    /**
-     * Property: timerId
-     * {Number} - The id of the timer.
-     */
-    timerId: null,
- 
-    /**
-     * Constructor: OpenLayers.Handler.Hover
-     * Construct a hover handler.
-     *
-     * 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.
-     * callbacks - {Object} An object with keys corresponding to callbacks
-     *     that will be called by the handler. The callbacks should
-     *     expect to receive a single argument, the event. Callbacks for
-     *     'move', the mouse is moving, and 'pause', the mouse is pausing,
-     *     are supported.
-     * options - {Object} An optional object whose properties will be set on
-     *     the handler.
-     */
-    initialize: function(control, callbacks, options) {
-        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
-    },
-
-    /**
-     * Method: mousemove
-     * Called when the mouse moves on the map.
-     *
-     * Parameters:
-     * evt - {<OpenLayers.Event>}
-     *
-     * Returns:
-     * {Boolean} Continue propagating this event.
-     */
-    mousemove: function(evt) {
-        if(this.passesTolerance(evt.xy)) {
-            this.clearTimer();
-            this.callback('move', [evt]);
-            this.px = evt.xy;
-            // clone the evt so original properties can be accessed even
-            // if the browser deletes them during the delay
-            evt = OpenLayers.Util.extend({}, evt);
-            this.timerId = window.setTimeout(
-                OpenLayers.Function.bind(this.delayedCall, this, evt),
-                this.delay
-            );
-        }
-        return !this.stopMove;
-    },
-
-    /**
-     * Method: mouseout
-     * Called when the mouse goes out of the map.
-     *
-     * Parameters:
-     * evt - {<OpenLayers.Event>}
-     *
-     * Returns:
-     * {Boolean} Continue propagating this event.
-     */
-    mouseout: function(evt) {
-        if (OpenLayers.Util.mouseLeft(evt, this.map.div)) {
-            this.clearTimer();
-            this.callback('move', [evt]);
-        }
-        return true;
-    },
-
-    /**
-     * Method: passesTolerance
-     * Determine whether the mouse move is within the optional pixel tolerance.
-     *
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     * {Boolean} The mouse move is within the pixel tolerance.
-     */
-    passesTolerance: function(px) {
-        var passes = true;
-        if(this.pixelTolerance && this.px) {
-            var dpx = Math.sqrt(
-                Math.pow(this.px.x - px.x, 2) +
-                Math.pow(this.px.y - px.y, 2)
-            );
-            if(dpx < this.pixelTolerance) {
-                passes = false;
-            }
-        }
-        return passes;
-    },
-
-    /**
-     * Method: clearTimer
-     * Clear the timer and set <timerId> to null.
-     */
-    clearTimer: function() {
-        if(this.timerId != null) {
-            window.clearTimeout(this.timerId);
-            this.timerId = null;
-        }
-    },
-
-    /**
-     * Method: delayedCall
-     * Triggers pause callback.
-     *
-     * Parameters:
-     * evt - {<OpenLayers.Event>}
-     */
-    delayedCall: function(evt) {
-        this.callback('pause', [evt]);
-    },
-
-    /**
-     * APIMethod: deactivate
-     * Deactivate the handler.
-     *
-     * Returns:
-     * {Boolean} The handler was successfully deactivated.
-     */
-    deactivate: function() {
-        var deactivated = false;
-        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
-            this.clearTimer();
-            deactivated = true;
-        }
-        return deactivated;
-    },
-
-    CLASS_NAME: "OpenLayers.Handler.Hover"
-});
-/* ======================================================================
-    OpenLayers/Handler/MouseWheel.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/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.MouseWheel
- * Handler for wheel up/down events.
- * 
- * Inherits from:
- *  - <OpenLayers.Handler>
- */
-OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
-    /** 
-     * 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
-     * value from the last mousemove.
-     */
-    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>} 
-     * 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} 
-     */
-    initialize: function(control, callbacks, options) {
-        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
-        this.wheelListener = OpenLayers.Function.bindAsEventListener(
-            this.onWheelEvent, this
-        );
-    },
-
-    /**
-     * Method: destroy
-     */    
-    destroy: function() {
-        OpenLayers.Handler.prototype.destroy.apply(this, arguments);
-        this.wheelListener = null;
-    },
-
-    /**
-     *  Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
-     */
-
-    /** 
-     * Method: onWheelEvent
-     * Catch the wheel event and handle it xbrowserly
-     * 
-     * Parameters:
-     * 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: 
-        //   * specifically marked as scrollable
-        //   * one of our layer divs
-        //   * the map div
-        //
-        var overScrollableDiv = false;
-        var overLayerDiv = false;
-        var overMapDiv = false;
-        
-        var elem = OpenLayers.Event.element(e);
-        while((elem != null) && !overMapDiv && !overScrollableDiv) {
-
-            if (!overScrollableDiv) {
-                try {
-                    if (elem.currentStyle) {
-                        overflow = elem.currentStyle["overflow"];
-                    } else {
-                        var style = 
-                            document.defaultView.getComputedStyle(elem, null);
-                        var overflow = style.getPropertyValue("overflow");
-                    }
-                    overScrollableDiv = ( overflow && 
-                        (overflow == "auto") || (overflow == "scroll") );
-                } catch(err) {
-                    //sometimes when scrolling in a popup, this causes 
-                    // obscure browser error
-                }
-            }
-
-            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 
-                    // pane above the layer (layer.pane)
-                    if (elem == this.map.layers[i].div 
-                        || elem == this.map.layers[i].pane) { 
-                        overLayerDiv = true;
-                        break;
-                    }
-                }
-            }
-            overMapDiv = (elem == this.map.div);
-
-            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: 
-        //     * 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 
-        //        layerswitcher or the pan/zoom control)
-        //
-        if (!overScrollableDiv && overMapDiv) {
-            if (overLayerDiv) {
-                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);
-        }
-    },
-
-    /**
-     * 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 = this.delta;
-        this.delta = 0;
-        
-        if (delta) {
-            // 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 
-                // this.map is ensured to be true above.
-                e.xy = this.map.getPixelFromLonLat(
-                    this.map.getCenter()
-                );
-            }
-            if (delta < 0) {
-                this.callback("down", [e, this.cumulative ? delta : -1]);
-            } else {
-                this.callback("up", [e, this.cumulative ? delta : 1]);
-            }
-        }
-    },
-    
-    /**
-     * Method: mousemove
-     * Update the stored mousePosition on every move.
-     * 
-     * Parameters:
-     * evt - {Event} The browser event
-     *
-     * Returns: 
-     * {Boolean} Allow event propagation
-     */
-    mousemove: function (evt) {
-        this.mousePosition = evt.xy;
-    },
-
-    /**
-     * Method: activate 
-     */
-    activate: function (evt) {
-        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
-            //register mousewheel events specifically on the window and document
-            var wheelListener = this.wheelListener;
-            OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
-            OpenLayers.Event.observe(window, "mousewheel", wheelListener);
-            OpenLayers.Event.observe(document, "mousewheel", wheelListener);
-            return true;
-        } else {
-            return false;
-        }
-    },
-
-    /**
-     * Method: deactivate 
-     */
-    deactivate: function (evt) {
-        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
-            // unregister mousewheel events specifically on the window and document
-            var wheelListener = this.wheelListener;
-            OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
-            OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
-            OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
-            return true;
-        } else {
-            return false;
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Handler.MouseWheel"
-});
-/* ======================================================================
     OpenLayers/Layer.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/Class.js
  * @requires OpenLayers/Map.js
  * @requires OpenLayers/Projection.js
  */
@@ -25339,2540 +9796,231 @@
     CLASS_NAME: "OpenLayers.Layer"
 });
 /* ======================================================================
-    OpenLayers/Marker/Box.js
+    OpenLayers/Layer/SphericalMercator.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/Marker.js
+ * @requires OpenLayers/Layer.js
+ * @requires OpenLayers/Projection.js
  */
 
 /**
- * Class: OpenLayers.Marker.Box
+ * Class: OpenLayers.Layer.SphericalMercator
+ * A mixin for layers that wraps up the pieces neccesary to have a coordinate
+ *     conversion for working with commercial APIs which use a spherical
+ *     mercator projection.  Using this layer as a base layer, additional
+ *     layers can be used as overlays if they are in the same projection.
  *
- * Inherits from:
- *  - <OpenLayers.Marker> 
- */
-OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, {
-
-    /** 
-     * Property: bounds 
-     * {<OpenLayers.Bounds>} 
-     */
-    bounds: null,
-
-    /** 
-     * Property: div 
-     * {DOMElement} 
-     */
-    div: null,
-    
-    /** 
-     * Constructor: OpenLayers.Marker.Box
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>} 
-     * borderColor - {String} 
-     * borderWidth - {int} 
-     */
-    initialize: function(bounds, borderColor, borderWidth) {
-        this.bounds = bounds;
-        this.div    = OpenLayers.Util.createDiv();
-        this.div.style.overflow = 'hidden';
-        this.events = new OpenLayers.Events(this, this.div, null);
-        this.setBorder(borderColor, borderWidth);
-    },
-
-    /**
-     * Method: destroy 
-     */    
-    destroy: function() {
-
-        this.bounds = null;
-        this.div = null;
-
-        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
-     */
-    setBorder: function (color, width) {
-        if (!color) {
-            color = "red";
-        }
-        if (!width) {
-            width = 2;
-        }
-        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 
-    *         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.
-     */
-    onScreen:function() {
-        var onScreen = false;
-        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: function(display) {
-        this.div.style.display = (display) ? "" : "none";
-    },
-
-    CLASS_NAME: "OpenLayers.Marker.Box"
-});
-
-/* ======================================================================
-    OpenLayers/Request/XMLHttpRequest.js
-   ====================================================================== */
-
-// 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.
-// 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.
-
-/**
- * @requires OpenLayers/Request.js
- */
-
-(function () {
-
-    // Save reference to earlier defined object implementation (if any)
-    var oXMLHttpRequest    = window.XMLHttpRequest;
-
-    // Define on browser type
-    var bGecko    = !!window.controllers,
-        bIE        = window.document.all && !window.opera,
-        bIE7    = bIE && window.navigator.userAgent.match(/MSIE ([\.0-9]+)/) && RegExp.$1 == 7;
-
-    // Constructor
-    function cXMLHttpRequest() {
-        this._object    = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP");
-        this._listeners    = [];
-    };
-
-    // BUGFIX: Firefox with Firebug installed would break pages if not executed
-    if (bGecko && oXMLHttpRequest.wrapped)
-        cXMLHttpRequest.wrapped    = oXMLHttpRequest.wrapped;
-
-    // Constants
-    cXMLHttpRequest.UNSENT                = 0;
-    cXMLHttpRequest.OPENED                = 1;
-    cXMLHttpRequest.HEADERS_RECEIVED    = 2;
-    cXMLHttpRequest.LOADING                = 3;
-    cXMLHttpRequest.DONE                = 4;
-
-    // Public Properties
-    cXMLHttpRequest.prototype.readyState    = cXMLHttpRequest.UNSENT;
-    cXMLHttpRequest.prototype.responseText    = '';
-    cXMLHttpRequest.prototype.responseXML    = null;
-    cXMLHttpRequest.prototype.status        = 0;
-    cXMLHttpRequest.prototype.statusText    = '';
-
-    // Instance-level Events Handlers
-    cXMLHttpRequest.prototype.onreadystatechange    = null;
-
-    // Class-level Events Handlers
-    cXMLHttpRequest.onreadystatechange    = null;
-    cXMLHttpRequest.onopen                = null;
-    cXMLHttpRequest.onsend                = null;
-    cXMLHttpRequest.onabort                = null;
-
-    // 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,
-            fOnUnload;
-
-        // BUGFIX: IE - memory leak on page unload (inter-page leak)
-        if (bIE && bAsync) {
-            fOnUnload = function() {
-                if (nState != cXMLHttpRequest.DONE) {
-                    fCleanTransport(oRequest);
-                    // Safe to abort here since onreadystatechange handler removed
-                    oRequest.abort();
-                }
-            };
-                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;
-
-            // Synchronize state
-            oRequest.readyState        = oRequest._object.readyState;
-
-            //
-            fSynchronizeValues(oRequest);
-
-            // BUGFIX: Firefox fires unnecessary DONE when aborting
-            if (oRequest._aborted) {
-                // Reset readyState to UNSENT
-                oRequest.readyState    = cXMLHttpRequest.UNSENT;
-
-                // Return now
-                return;
-            }
-
-            if (oRequest.readyState == cXMLHttpRequest.DONE) {
-                //
-                fCleanTransport(oRequest);
-// Uncomment this block if you need a fix for IE cache
-/*
-                // BUGFIX: IE - cache issue
-                if (!oRequest._object.getResponseHeader("Date")) {
-                    // Save object to cache
-                    oRequest._cached    = oRequest._object;
-
-                    // Instantiate a new transport object
-                    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)
-                        for (var sHeader in oRequest._headers)
-                            if (typeof oRequest._headers[sHeader] == "string")    // Some frameworks prototype objects with functions
-                                oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
-
-                    oRequest._object.onreadystatechange    = function() {
-                        // Synchronize state
-                        oRequest.readyState        = oRequest._object.readyState;
-
-                        if (oRequest._aborted) {
-                            //
-                            oRequest.readyState    = cXMLHttpRequest.UNSENT;
-
-                            // Return
-                            return;
-                        }
-
-                        if (oRequest.readyState == cXMLHttpRequest.DONE) {
-                            // Clean Object
-                            fCleanTransport(oRequest);
-
-                            // get cached request
-                            if (oRequest.status == 304)
-                                oRequest._object    = oRequest._cached;
-
-                            //
-                            delete oRequest._cached;
-
-                            //
-                            fSynchronizeValues(oRequest);
-
-                            //
-                            fReadyStateChange(oRequest);
-
-                            // BUGFIX: IE - memory leak in interrupted
-                            if (bIE && bAsync)
-                                window.detachEvent("onunload", fOnUnload);
-                        }
-                    };
-                    oRequest._object.send(null);
-
-                    // Return now - wait until re-sent request is finished
-                    return;
-                };
-*/
-                // BUGFIX: IE - memory leak in interrupted
-                if (bIE && bAsync)
-                    window.detachEvent("onunload", fOnUnload);
-            }
-
-            // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
-            if (nState != oRequest.readyState)
-                fReadyStateChange(oRequest);
-
-            nState    = oRequest.readyState;
-        }
-    };
-    cXMLHttpRequest.prototype.send    = function(vData) {
-        // Add method sniffer
-        if (cXMLHttpRequest.onsend)
-            cXMLHttpRequest.onsend.apply(this, arguments);
-
-        // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
-        // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
-        // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
-        if (vData && vData.nodeType) {
-            vData    = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
-            if (!this._headers["Content-Type"])
-                this._object.setRequestHeader("Content-Type", "application/xml");
-        }
-
-        this._object.send(vData);
-
-        // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
-        if (bGecko && !this._async) {
-            this.readyState    = cXMLHttpRequest.OPENED;
-
-            // Synchronize state
-            fSynchronizeValues(this);
-
-            // Simulate missing states
-            while (this.readyState < cXMLHttpRequest.DONE) {
-                this.readyState++;
-                fReadyStateChange(this);
-                // Check if we are aborted
-                if (this._aborted)
-                    return;
-            }
-        }
-    };
-    cXMLHttpRequest.prototype.abort    = function() {
-        // Add method sniffer
-        if (cXMLHttpRequest.onabort)
-            cXMLHttpRequest.onabort.apply(this, arguments);
-
-        // BUGFIX: Gecko - unnecessary DONE when aborting
-        if (this.readyState > cXMLHttpRequest.UNSENT)
-            this._aborted    = true;
-
-        this._object.abort();
-
-        // BUGFIX: IE - memory leak
-        fCleanTransport(this);
-    };
-    cXMLHttpRequest.prototype.getAllResponseHeaders    = function() {
-        return this._object.getAllResponseHeaders();
-    };
-    cXMLHttpRequest.prototype.getResponseHeader    = function(sName) {
-        return this._object.getResponseHeader(sName);
-    };
-    cXMLHttpRequest.prototype.setRequestHeader    = function(sName, sValue) {
-        // BUGFIX: IE - cache issue
-        if (!this._headers)
-            this._headers    = {};
-        this._headers[sName]    = sValue;
-
-        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) {
-        // 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,
-            sResponse    = oRequest.responseText;
-        // Try parsing 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 && oDocument.documentElement.tagName == "parsererror"))
-                return null;
-        return oDocument;
-    };
-
-    function fSynchronizeValues(oRequest) {
-        try {    oRequest.responseText    = oRequest._object.responseText;    } catch (e) {}
-        try {    oRequest.responseXML    = fGetDocument(oRequest._object);    } catch (e) {}
-        try {    oRequest.status            = oRequest._object.status;            } catch (e) {}
-        try {    oRequest.statusText        = oRequest._object.statusText;        } catch (e) {}
-    };
-
-    function fCleanTransport(oRequest) {
-        // BUGFIX: IE - memory leak (on-page leak)
-        oRequest._object.onreadystatechange    = new window.Function;
-    };
-
-    // Internet Explorer 5.0 (missing apply)
-    if (!window.Function.prototype.apply) {
-        window.Function.prototype.apply    = function(oRequest, oArguments) {
-            if (!oArguments)
-                oArguments    = [];
-            oRequest.__func    = this;
-            oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
-            delete oRequest.__func;
-        };
-    };
-
-    // Register new object with window
-    /**
-     * Class: OpenLayers.Request.XMLHttpRequest
-     * Standard-compliant (W3C) cross-browser implementation of the
-     *     XMLHttpRequest object.  From
-     *     http://code.google.com/p/xmlhttprequest/.
-     */
-    OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;
-})();
-/* ======================================================================
-    OpenLayers/Ajax.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/Request/XMLHttpRequest.js
- * @requires OpenLayers/Console.js
- */
-
-OpenLayers.ProxyHost = "";
-//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";
-
-/**
- * Ajax reader for OpenLayers
+ * A layer is given properties of this object by setting the sphericalMercator
+ *     property to true.
  *
- *  @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 
- *  @failure  the function to be called on failure
- *  
- *   example usage from a caller:
- *  
- *     caps: function(request) {
- *      -blah-  
- *     },
- *  
- *     OpenLayers.loadURL(url,params,this,caps);
+ * More projection information:
+ *  - http://spatialreference.org/ref/user/google-projection/
  *
- * 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 
- * supplied
+ * Proj4 Text:
+ *     +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
  *
+ * 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], 
+ *     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], 
+ *     PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST],
+ *     AXIS["y", NORTH], AUTHORITY["EPSG","900913"]]
  */
+OpenLayers.Layer.SphericalMercator = {
 
-
-/**
- * Function: OpenLayers.nullHandler
- * @param {} request
- */
-OpenLayers.nullHandler = function(request) {
-    OpenLayers.Console.userError(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText}));
-};
-
-/** 
- * APIFunction: OpenLayers.loadURL
- * Background load a document.  For more flexibility in using XMLHttpRequest,
- *     see the <OpenLayers.Request> methods.
- *
- * Parameters:
- * uri - {String} URI of source doc
- * params - {String} or {Object} GET params. Either a string in the form
- *     "?hello=world&foo=bar" (do not forget the leading question mark)
- *     or an object in the form {'hello': 'world', 'foo': 'bar}
- * caller - {Object} object which gets callbacks
- * 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 
- *     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
- *     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 user friendly error message dialog).
- *
- * Returns:
- * {<OpenLayers.Request.XMLHttpRequest>}  The request object. To abort loading,
- *     call request.abort().
- */
-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: OpenLayers.parseXMLString
- * Parse XML into a doc structure
- * 
- * Parameters:
- * text - {String} 
- * 
- * Returns:
- * {?} Parsed AJAX Responsev
- */
-OpenLayers.parseXMLString = function(text) {
-
-    //MS sucks, if the server is bad it dies
-    var index = text.indexOf('<');
-    if (index > 0) {
-        text = text.substring(index);
-    }
-
-    var ajaxResponse = OpenLayers.Util.Try(
-        function() {
-            var xmldom = new ActiveXObject('Microsoft.XMLDOM');
-            xmldom.loadXML(text);
-            return xmldom;
-        },
-        function() {
-            return new DOMParser().parseFromString(text, 'text/xml');
-        },
-        function() {
-            var req = new XMLHttpRequest();
-            req.open("GET", "data:" + "text/xml" +
-                     ";charset=utf-8," + encodeURIComponent(text), false);
-            if (req.overrideMimeType) {
-                req.overrideMimeType("text/xml");
-            }
-            req.send(null);
-            return req.responseXML;
-        }
-    );
-
-    return ajaxResponse;
-};
-
-
-/**
- * Namespace: OpenLayers.Ajax
- */
-OpenLayers.Ajax = {
-
     /**
-     * Method: emptyFunction
-     */
-    emptyFunction: function () {},
-
-    /**
-     * Method: getTransport
-     * 
-     * Returns: 
-     * {Object} Transport mechanism for whichever browser we're in, or false if
-     *          none available.
-     */
-    getTransport: function() {
-        return OpenLayers.Util.Try(
-            function() {return new XMLHttpRequest();},
-            function() {return new ActiveXObject('Msxml2.XMLHTTP');},
-            function() {return new ActiveXObject('Microsoft.XMLHTTP');}
-        ) || false;
-    },
-
-    /**
-     * Property: activeRequestCount
-     * {Integer}
-     */
-    activeRequestCount: 0
-};
-
-/**
- * Namespace: OpenLayers.Ajax.Responders
- * {Object}
- */
-OpenLayers.Ajax.Responders = {
-  
-    /**
-     * Property: responders
-     * {Array}
-     */
-    responders: [],
-
-    /**
-     * Method: register
-     *  
-     * Parameters:
-     * responderToAdd - {?}
-     */
-    register: function(responderToAdd) {
-        for (var i = 0; i < this.responders.length; i++){
-            if (responderToAdd == this.responders[i]){
-                return;
-            }
-        }
-        this.responders.push(responderToAdd);
-    },
-
-    /**
-     * Method: unregister
-     *  
-     * Parameters:
-     * responderToRemove - {?}
-     */
-    unregister: function(responderToRemove) {
-        OpenLayers.Util.removeItem(this.reponders, responderToRemove);
-    },
-
-    /**
-     * Method: dispatch
-     * 
-     * Parameters:
-     * callback - {?}
-     * request - {?}
-     * transport - {?}
-     */
-    dispatch: function(callback, request, transport) {
-        var responder;
-        for (var i = 0; i < this.responders.length; i++) {
-            responder = this.responders[i];
-     
-            if (responder[callback] && 
-                typeof responder[callback] == 'function') {
-                try {
-                    responder[callback].apply(responder, 
-                                              [request, transport]);
-                } catch (e) {}
-            }
-        }
-    }
-};
-
-OpenLayers.Ajax.Responders.register({
-    /** 
-     * Function: onCreate
-     */
-    onCreate: function() {
-        OpenLayers.Ajax.activeRequestCount++;
-    },
-
-    /**
-     * Function: onComplete
-     */
-     onComplete: function() {
-         OpenLayers.Ajax.activeRequestCount--;
-     }
-});
-
-/**
- * Class: OpenLayers.Ajax.Base
- */
-OpenLayers.Ajax.Base = OpenLayers.Class({
-      
-    /**
-     * Constructor: OpenLayers.Ajax.Base
-     * 
-     * Parameters: 
-     * options - {Object}
-     */
-    initialize: function(options) {
-        this.options = {
-            method:       'post',
-            asynchronous: true,
-            contentType:  'application/xml',
-            parameters:   ''
-        };
-        OpenLayers.Util.extend(this.options, options || {});
-        
-        this.options.method = this.options.method.toLowerCase();
-        
-        if (typeof this.options.parameters == 'string') {
-            this.options.parameters = 
-                OpenLayers.Util.getParameters(this.options.parameters);
-        }
-    }
-});
-
-/**
- * Class: OpenLayers.Ajax.Request
- * *Deprecated*.  Use <OpenLayers.Request> method instead.
- *
- * Inherit:
- *  - <OpenLayers.Ajax.Base>
- */
-OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
-
-    /**
-     * Property: _complete
+     * Method: getExtent
+     * Get the map's extent.
      *
-     * {Boolean}
+     * Returns:
+     * {<OpenLayers.Bounds>} The map extent.
      */
-    _complete: false,
-      
-    /**
-     * Constructor: OpenLayers.Ajax.Request
-     * 
-     * 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);
+    getExtent: function() {
+        var extent = null;
+        if (this.sphericalMercator) {
+            extent = this.map.calculateBounds();
+        } else {
+            extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);
         }
-        
-        this.transport = OpenLayers.Ajax.getTransport();
-        this.request(url);
+        return extent;
     },
 
     /**
-     * Method: request
+     * Method: getLonLatFromViewPortPx
+     * Get a map location from a pixel location
      * 
      * Parameters:
-     * url - {String}
-     */
-    request: function(url) {
-        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;        
-        
-        if (params = OpenLayers.Util.getParameterString(params)) {
-            // when GET, append parameters to URL
-            if (this.method == 'get') {
-                this.url += ((this.url.indexOf('?') > -1) ? '&' : '?') + params;
-            } else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
-                params += '&_=';
-            }
-        }
-        try {
-            var response = new OpenLayers.Ajax.Response(this);
-            if (this.options.onCreate) {
-                this.options.onCreate(response);
-            }
-            
-            OpenLayers.Ajax.Responders.dispatch('onCreate', 
-                                                this, 
-                                                response);
-    
-            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.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 && 
-                this.transport.overrideMimeType) {
-                this.onStateChange();
-            }
-        } catch (e) {
-            this.dispatchException(e);
-        }
-    },
-
-    /**
-     * Method: onStateChange
-     */
-    onStateChange: function() {
-        var readyState = this.transport.readyState;
-        if (readyState > 1 && !((readyState == 4) && this._complete)) {
-            this.respondToReadyState(this.transport.readyState);
-        }
-    },
-     
-    /**
-     * Method: setRequestHeaders
-     */
-    setRequestHeaders: function() {
-        var headers = {
-            'X-Requested-With': 'XMLHttpRequest',
-            'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
-            'OpenLayers': true
-        };
-
-        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.
-             */
-            if (this.transport.overrideMimeType &&
-                (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) {
-                headers['Connection'] = 'close';
-            }
-        }
-        // user-defined headers
-        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];
-                }
-            } else {
-                for (var i in extras) {
-                    headers[i] = extras[i];
-                }
-            }
-        }
-        
-        for (var name in headers) {
-            this.transport.setRequestHeader(name, headers[name]);
-        }
-    },
-    
-    /**
-     * Method: success
+     * viewPortPx - {<OpenLayers.Pixel>}
      *
      * Returns:
-     * {Boolean} - 
+     *  {<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
      */
-    success: function() {
-        var status = this.getStatus();
-        return !status || (status >=200 && status < 300);
+    getLonLatFromViewPortPx: function (viewPortPx) {
+        return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments);
     },
     
     /**
-     * Method: getStatus
+     * Method: getViewPortPxFromLonLat
+     * Get a pixel location from a map location
      *
-     * Returns:
-     * {Integer} - Status
-     */
-    getStatus: function() {
-        try {
-            return this.transport.status || 0;
-        } catch (e) {
-            return 0;
-        }
-    },
-
-    /**
-     * Method: respondToReadyState
-     *
      * Parameters:
-     * readyState - {?}
-     */
-    respondToReadyState: function(readyState) {
-        var state = OpenLayers.Ajax.Request.Events[readyState];
-        var response = new OpenLayers.Ajax.Response(this);
-    
-        if (state == 'Complete') {
-            try {
-                this._complete = true;
-                (this.options['on' + response.status] ||
-                    this.options['on' + (this.success() ? 'Success' : 'Failure')] ||
-                    OpenLayers.Ajax.emptyFunction)(response);
-            } catch (e) {
-                this.dispatchException(e);
-            }
-    
-            var contentType = response.getHeader('Content-type');
-        }
-    
-        try {
-            (this.options['on' + state] || 
-             OpenLayers.Ajax.emptyFunction)(response);
-             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
+     * lonlat - {<OpenLayers.LonLat>}
      *
      * Returns:
-     * {?} - response header for the given name
+     * {<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
      */
-    getHeader: function(name) {
-        try {
-            return this.transport.getResponseHeader(name);
-        } catch (e) {
-            return null;
-        }
+    getViewPortPxFromLonLat: function (lonlat) {
+        return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments);
     },
 
-    /**
-     * Method: dispatchException
-     * 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
-     * for the onException call.  To make sure that something
-     * gets done with this exception, only dispatch the call if there
-     * are listeners.
-     *
-     * If you explicitly want to swallow exceptions, set
-     * request.options.onException to an empty function (function(){})
-     * or register an empty function with <OpenLayers.Ajax.Responders>
-     * for onException.
-     * 
-     * Parameters:
-     * exception - {?}
+    /** 
+     * Method: initMercatorParameters 
+     * Set up the mercator parameters on the layer: resolutions,
+     *     projection, units.
      */
-    dispatchException: function(exception) {
-        var handler = this.options.onException;
-        if(handler) {
-            // call options.onException and alert any other listeners
-            handler(this, exception);
-            OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
-        } else {
-            // check if there are any other listeners
-            var listener = false;
-            var responders = OpenLayers.Ajax.Responders.responders;
-            for (var i = 0; i < responders.length; i++) {
-                if(responders[i].onException) {
-                    listener = true;
-                    break;
-                }
-            }
-            if(listener) {
-                // call all listeners
-                OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
-            } else {
-                // let the exception through
-                throw exception;
-            }
+    initMercatorParameters: function() {
+        // set up properties for Mercator - assume EPSG:900913
+        this.RESOLUTIONS = [];
+        var maxResolution = 156543.0339;
+        for(var zoom=0; zoom<=this.MAX_ZOOM_LEVEL; ++zoom) {
+            this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom);
         }
-    }
-});
-
-/** 
- * Property: Events
- * {Array(String)}
- */
-OpenLayers.Ajax.Request.Events =
-  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-/**
- * Class: OpenLayers.Ajax.Response
- */
-OpenLayers.Ajax.Response = OpenLayers.Class({
-
-    /**
-     * Property: status
-     *
-     * {Integer}
-     */
-    status: 0,
-    
-
-    /**
-     * Property: statusText
-     *
-     * {String}
-     */
-    statusText: '',
-      
-    /**
-     * Constructor: OpenLayers.Ajax.Response
-     * 
-     * 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) {
-            this.status       = this.getStatus();
-            this.statusText   = this.getStatusText();
-            this.responseText = transport.responseText == null ?
-                '' : String(transport.responseText);
-        }
-        
-        if(readyState == 4) {
-            var xml = transport.responseXML;
-            this.responseXML  = xml === undefined ? null : xml;
-        }
+        this.units = "m";
+        this.projection = this.projection || "EPSG:900913";
     },
-    
-    /**
-     * Method: getStatus
-     */
-    getStatus: OpenLayers.Ajax.Request.prototype.getStatus,
-    
-    /**
-     * Method: getStatustext
-     *
-     * Returns:
-     * {String} - statusText
-     */
-    getStatusText: function() {
-        try {
-            return this.transport.statusText || '';
-        } catch (e) {
-            return '';
-        }
-    },
-    
-    /**
-     * Method: getHeader
-     */
-    getHeader: OpenLayers.Ajax.Request.prototype.getHeader,
-    
-    /** 
-     * Method: getResponseHeader
-     *
-     * Returns:
-     * {?} - response header for given name
-     */
-    getResponseHeader: function(name) {
-        return this.transport.getResponseHeader(name);
-    }
-});
 
-
-/**
- * Function: getElementsByTagNameNS
- * 
- * Parameters:
- * parentnode - {?}
- * nsuri - {?}
- * nsprefix - {?}
- * tagname - {?}
- * 
- * Returns:
- * {?}
- */
-OpenLayers.Ajax.getElementsByTagNameNS  = function(parentnode, nsuri, 
-                                                   nsprefix, tagname) {
-    var elem = null;
-    if (parentnode.getElementsByTagNameNS) {
-        elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
-    } else {
-        elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
-    }
-    return elem;
-};
-
-
-/**
- * Function: serializeXMLToString
- * Wrapper function around XMLSerializer, which doesn't exist/work in
- *     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: 
- * xmldom {XMLNode} xml dom to serialize
- * 
- * Returns:
- * {?}
- */
-OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
-    var serializer = new XMLSerializer();
-    var data = serializer.serializeToString(xmldom);
-    return data;
-};
-/* ======================================================================
-    OpenLayers/Control/DragPan.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/Control.js
- * @requires OpenLayers/Handler/Drag.js
- */
-
-/**
- * Class: OpenLayers.Control.DragPan
- * The DragPan control pans the map with a drag of the mouse.
- *
- * Inherits from:
- *  - <OpenLayers.Control>
- */
-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
-     *     panning the map again. Set this to increase dragging performance.
-     *     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,
-                documentDrag: this.documentDrag
-            }
-        );
-    },
-
-    /**
-    * Method: panMap
-    *
-    * Parameters:
-    * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
-    */
-    panMap: function(xy) {
-        this.panned = true;
-        this.map.pan(
-            this.handler.last.x - xy.x,
-            this.handler.last.y - xy.y,
-            {dragging: this.handler.dragging, animate: false}
-        );
-    },
-    
-    /**
-     * Method: panMapDone
-     * Finish the panning operation.  Only call setCenter (through <panMap>)
-     *     if the map has actually been moved.
+     * APIMethod: forwardMercator
+     * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator.
      *
      * Parameters:
-     * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
-     */
-    panMapDone: function(xy) {
-        if(this.panned) {
-            this.panMap(xy);
-            this.panned = false;
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Control.DragPan"
-});
-/* ======================================================================
-    OpenLayers/Feature/Vector.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. */
-
-// TRASH THIS
-OpenLayers.State = {
-    /** states */
-    UNKNOWN: 'Unknown',
-    INSERT: 'Insert',
-    UPDATE: 'Update',
-    DELETE: 'Delete'
-};
-
-/**
- * @requires OpenLayers/Feature.js
- * @requires OpenLayers/Util.js
- */
-
-/**
- * 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 
- * <OpenLayers.Feature.Vector.style> objects.
- * 
- * Inherits from:
- *  - <OpenLayers.Feature>
- */
-OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {
-
-    /** 
-     * Property: fid 
-     * {String} 
-     */
-    fid: null,
-    
-    /** 
-     * APIProperty: geometry 
-     * {<OpenLayers.Geometry>} 
-     */
-    geometry: null,
-
-    /** 
-     * APIProperty: attributes 
-     * {Object} This object holds arbitrary, serializable properties that
-     *     describe the feature.
-     */
-    attributes: null,
-
-    /**
-     * Property: bounds
-     * {<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. 
-     */
-    bounds: null,
-
-    /** 
-     * Property: state 
-     * {String} 
-     */
-    state: null,
-    
-    /** 
-     * 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. 
+     * lon - {float} 
+     * lat - {float}
      * 
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>} The geometry that this feature
-     *     represents.
-     * attributes - {Object} An optional object that will be mapped to the
-     *     <attributes> property. 
-     * style - {Object} An optional style object.
-     */
-    initialize: function(geometry, attributes, style) {
-        OpenLayers.Feature.prototype.initialize.apply(this,
-                                                      [null, null, attributes]);
-        this.lonlat = null;
-        this.geometry = geometry ? geometry : null;
-        this.state = null;
-        this.attributes = {};
-        if (attributes) {
-            this.attributes = OpenLayers.Util.extend(this.attributes,
-                                                     attributes);
-        }
-        this.style = style ? style : null; 
-    },
-    
-    /** 
-     * Method: destroy
-     * nullify references to prevent circular references and memory leaks
-     */
-    destroy: function() {
-        if (this.layer) {
-            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
-     *     properties.
-     *
      * Returns:
-     * {<OpenLayers.Feature.Vector>} An exact clone of this vector feature.
+     * {<OpenLayers.LonLat>} The coordinates transformed to Mercator.
      */
-    clone: function () {
-        return new OpenLayers.Feature.Vector(
-            this.geometry ? this.geometry.clone() : null,
-            this.attributes,
-            this.style);
+    forwardMercator: function(lon, lat) {
+        var x = lon * 20037508.34 / 180;
+        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);
     },
 
     /**
-     * Method: onScreen
-     * Determine whether the feature is within the map viewport.  This method
-     *     tests for an intersection between the geometry and the viewport
-     *     bounds.  If a more effecient but less precise geometry bounds
-     *     intersection is desired, call the method with the boundsOnly
-     *     parameter true.
+     * APIMethod: inverseMercator
+     * Given a x,y in Spherical Mercator, return a point in EPSG:4326.
      *
      * Parameters:
-     * 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.
+     * x - {float} A map x in Spherical Mercator.
+     * y - {float} A map y in Spherical Mercator.
      * 
      * Returns:
-     * {Boolean} The feature is currently visible on screen (optionally
-     *     based on its bounds if boundsOnly is true).
+     * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326.
      */
-    onScreen:function(boundsOnly) {
-        var onScreen = false;
-        if(this.layer && this.layer.map) {
-            var screenBounds = this.layer.map.getExtent();
-            if(boundsOnly) {
-                var featureBounds = this.geometry.getBounds();
-                onScreen = screenBounds.intersectsBounds(featureBounds);
-            } else {
-                var screenPoly = screenBounds.toGeometry();
-                onScreen = screenPoly.intersects(this.geometry);
-            }
-        }    
-        return onScreen;
-    },
+    inverseMercator: function(x, y) {
 
-    /**
-     * 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
-     */
-    createMarker: function() {
-        return null;
-    },
+        var lon = (x / 20037508.34) * 180;
+        var lat = (y / 20037508.34) * 180;
 
-    /**
-     * 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
-     */
-    destroyMarker: function() {
-        // pass
-    },
-
-    /**
-     * 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
-     */
-    createPopup: function() {
-        return null;
-    },
-
-    /**
-     * Method: atPoint
-     * Determins whether the feature intersects with the specified location.
-     * 
-     * 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, 
-                                                    toleranceLat);
-        }
-        return atPoint;
-    },
-
-    /**
-     * Method: destroyPopup
-     * HACK - we need to decide if all vector features should be able to
-     * delete popups
-     */
-    destroyPopup: function() {
-        // pass
-    },
-
-    /**
-     * Method: move
-     * Moves the feature and redraws it at its new location
-     *
-     * Parameters:
-     * state - {OpenLayers.LonLat or OpenLayers.Pixel} the
-     *         location to which to move the feature.
-     */
-    move: function(location) {
-
-        if(!this.layer || !this.geometry.move){
-            //do nothing if no layer or immoveable geometry
-            return;
-        }
-
-        var pixel;
-        if (location.CLASS_NAME == "OpenLayers.LonLat") {
-            pixel = this.layer.getViewPortPxFromLonLat(location);
-        } else {
-            pixel = location;
-        }
+        lat = 180/Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
         
-        var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());
-        var res = this.layer.map.getResolution();
-        this.geometry.move(res * (pixel.x - lastPixel.x),
-                           res * (lastPixel.y - pixel.y));
-        this.layer.drawFeature(this);
-        return lastPixel;
+        return new OpenLayers.LonLat(lon, lat);
     },
-    
-    /**
-     * Method: toState
-     * Sets the new state
-     *
-     * Parameters:
-     * state - {String} 
-     */
-    toState: function(state) {
-        if (state == OpenLayers.State.UPDATE) {
-            switch (this.state) {
-                case OpenLayers.State.UNKNOWN:
-                case OpenLayers.State.DELETE:
-                    this.state = state;
-                    break;
-                case OpenLayers.State.UPDATE:
-                case OpenLayers.State.INSERT:
-                    break;
-            }
-        } else if (state == OpenLayers.State.INSERT) {
-            switch (this.state) {
-                case OpenLayers.State.UNKNOWN:
-                    break;
-                default:
-                    this.state = state;
-                    break;
-            }
-        } else if (state == OpenLayers.State.DELETE) {
-            switch (this.state) {
-                case OpenLayers.State.INSERT:
-                    // the feature should be destroyed
-                    break;
-                case OpenLayers.State.DELETE:
-                    break;
-                case OpenLayers.State.UNKNOWN:
-                case OpenLayers.State.UPDATE:
-                    this.state = state;
-                    break;
-            }
-        } else if (state == OpenLayers.State.UNKNOWN) {
-            this.state = state;
-        }
-    },
-    
-    CLASS_NAME: "OpenLayers.Feature.Vector"
-});
 
-
-/**
- * Constant: OpenLayers.Feature.Vector.style
- * 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. 
- *     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 
- * 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.
- * strokeWidth - {Number} Pixel stroke width.  Default is 1.
- * strokeLinecap - {String} Stroke cap type.  Default is "round".  [butt | round | square]
- * strokeDashstyle - {String} Stroke dash style.  Default is "solid". [dot | dash | dashdot | longdash | longdashdot | solid]
- * graphic - {Boolean} Set to false if no graphic is desired.
- * pointRadius - {Number} Pixel point radius.  Default is 6.
- * pointerEvents - {String}  Default is "visiblePainted".
- * cursor - {String} Default is "".
- * externalGraphic - {String} Url to an external graphic that will be used for rendering points.
- * graphicWidth - {Number} Pixel width for sizing an external graphic.
- * graphicHeight - {Number} Pixel height for sizing an external graphic.
- * 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".
- * graphicTitle - {String} Tooltip for an external graphic. Only supported in Firefox and Internet Explorer.
- * backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic.
- * backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic.
- * backgroundXOffset - {Number} The x offset (in pixels) for the background graphic.
- * backgroundYOffset - {Number} The y offset (in pixels) for the background graphic.
- * backgroundHeight - {Number} The height of the background graphic.  If not provided, the graphicHeight will be used.
- * backgroundWidth - {Number} The width of the background width.  If not provided, the graphicWidth will be used.
- * label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either
- *     fillText or mozDrawText to be available.
- * labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string
- *     composed of two characters. The first character is for the horizontal alignment, the second for the vertical
- *     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, 
-        hoverFillColor: "white",
-        hoverFillOpacity: 0.8,
-        strokeColor: "#ee9900",
-        strokeOpacity: 1,
-        strokeWidth: 1,
-        strokeLinecap: "round",
-        strokeDashstyle: "solid",
-        hoverStrokeColor: "red",
-        hoverStrokeOpacity: 1,
-        hoverStrokeWidth: 0.2,
-        pointRadius: 6,
-        hoverPointRadius: 1,
-        hoverPointUnit: "%",
-        pointerEvents: "visiblePainted",
-        cursor: "inherit"
-    },
-    'select': {
-        fillColor: "blue",
-        fillOpacity: 0.4, 
-        hoverFillColor: "white",
-        hoverFillOpacity: 0.8,
-        strokeColor: "blue",
-        strokeOpacity: 1,
-        strokeWidth: 2,
-        strokeLinecap: "round",
-        strokeDashstyle: "solid",
-        hoverStrokeColor: "red",
-        hoverStrokeOpacity: 1,
-        hoverStrokeWidth: 0.2,
-        pointRadius: 6,
-        hoverPointRadius: 1,
-        hoverPointUnit: "%",
-        pointerEvents: "visiblePainted",
-        cursor: "pointer"
-    },
-    'temporary': {
-        fillColor: "#66cccc",
-        fillOpacity: 0.2, 
-        hoverFillColor: "white",
-        hoverFillOpacity: 0.8,
-        strokeColor: "#66cccc",
-        strokeOpacity: 1,
-        strokeLinecap: "round",
-        strokeWidth: 2,
-        strokeDashstyle: "solid",
-        hoverStrokeColor: "red",
-        hoverStrokeOpacity: 1,
-        hoverStrokeWidth: 0.2,
-        pointRadius: 6,
-        hoverPointRadius: 1,
-        hoverPointUnit: "%",
-        pointerEvents: "visiblePainted",
-        cursor: "inherit"
-    },
-    'delete': {
-        display: "none"
-    }
-};    
-/* ======================================================================
-    OpenLayers/Format/WFSCapabilities/v1.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/WFSCapabilities.js
- */
-
-/**
- * Class: OpenLayers.Format.WFSCapabilities.v1
- * Abstract class not to be instantiated directly.
- * 
- * Inherits from:
- *  - <OpenLayers.Format.XML>
- */
-OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class(
-    OpenLayers.Format.WFSCapabilities, {
-    
     /**
-     * Constructor: OpenLayers.Format.WFSCapabilities.v1_1
-     * Create an instance of one of the subclasses.
+     * 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:
-     * options - {Object} An optional object whose properties will be set on
-     *     this instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
-        this.options = options;
-    },
-
-    /**
-     * APIMethod: read
-     * Read capabilities data from a string, and return a list of layers. 
+     * point - {Object} An object with x and y properties. 
      * 
-     * Parameters: 
-     * data - {String} or {DOMElement} data to read/parse.
-     *
      * Returns:
-     * {Array} List of named layers.
+     * {Object} The point, with the x and y properties transformed to spherical
+     * mercator.
      */
-    read: function(data) {
-        if(typeof data == "string") {
-            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
-        }
-        var capabilities = {};
-        var root = data.documentElement;
-        this.runChildNodes(capabilities, root);
-        return capabilities;
+    projectForward: function(point) {
+        var lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(point.x, point.y);
+        point.x = lonlat.lon;
+        point.y = lonlat.lat;
+        return point;
     },
     
     /**
-     * Method: runChildNodes
-     */
-    runChildNodes: function(obj, node) {
-        var children = node.childNodes;
-        var childNode, processor;
-        for(var i=0; i<children.length; ++i) {
-            childNode = children[i];
-            if(childNode.nodeType == 1) {
-                processor = this["read_cap_" + childNode.nodeName];
-                if(processor) {
-                    processor.apply(this, [obj, childNode]);
-                }
-            }
-        }
-    },
-    
-    /**
-     * Method: read_cap_FeatureTypeList
-     */
-    read_cap_FeatureTypeList: function(request, node) {
-        var featureTypeList = {
-            featureTypes: []
-        };
-        this.runChildNodes(featureTypeList, node);
-        request.featureTypeList = featureTypeList;
-    },
-    
-    /**
-     * Method: read_cap_FeatureType
-     */
-    read_cap_FeatureType: function(featureTypeList, node, parentLayer) {
-        var featureType = {};
-        this.runChildNodes(featureType, node);
-        featureTypeList.featureTypes.push(featureType);
-    },
-    
-    /**
-     * Method: read_cap_Name
-     */
-    read_cap_Name: function(obj, node) {
-        var name = this.getChildValue(node);
-        if(name) {
-            var parts = name.split(":");
-            obj.name = parts.pop();
-            if(parts.length > 0) {
-                obj.featureNS = this.lookupNamespaceURI(node, parts[0]);
-            }
-        }
-    },
-
-    /**
-     * Method: read_cap_Title
-     */
-    read_cap_Title: function(obj, node) {
-        var title = this.getChildValue(node);
-        if(title) {
-            obj.title = title;
-        }
-    },
-
-    /**
-     * Method: read_cap_Abstract
-     */
-    read_cap_Abstract: function(obj, node) {
-        var abst = this.getChildValue(node);
-        if(abst) {
-            obj["abstract"] = abst;
-        }
-    },
-    
-    CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1" 
-
-});
-/* ======================================================================
-    OpenLayers/Handler/Box.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/Handler.js
- * @requires OpenLayers/Handler/Drag.js
- */
-
-/**
- * Class: OpenLayers.Handler.Box
- * 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.Box = OpenLayers.Class(OpenLayers.Handler, {
-
-    /** 
-     * Property: dragHandler 
-     * {<OpenLayers.Handler.Drag>} 
-     */
-    dragHandler: null,
-
-    /**
-     * APIProperty: boxDivClassName
-     * {String} The CSS class to use for drawing the box. Default is
-     *     olHandlerBoxZoomBox
-     */
-    boxDivClassName: 'olHandlerBoxZoomBox',
-    
-    /**
-     * Property: boxCharacteristics
-     * {Object} Caches some box characteristics from css. This is used
-     *     by the getBoxCharacteristics method.
-     */
-    boxCharacteristics: null,
-
-    /**
-     * Constructor: OpenLayers.Handler.Box
+     * 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:
-     * 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} 
-     */
-    initialize: function(control, callbacks, options) {
-        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
-        var callbacks = {
-            "down": this.startBox, 
-            "move": this.moveBox, 
-            "out":  this.removeBox,
-            "up":   this.endBox
-        };
-        this.dragHandler = new OpenLayers.Handler.Drag(
-                                this, callbacks, {keyMask: this.keyMask});
-    },
-
-    /**
-     * 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) {
-        OpenLayers.Handler.prototype.setMap.apply(this, arguments);
-        if (this.dragHandler) {
-            this.dragHandler.setMap(map);
-        }
-    },
-
-    /**
-    * Method: startBox
-    *
-    * Parameters:
-    * evt - {Event} 
-    */
-    startBox: function (xy) {
-        this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
-                                                 this.dragHandler.start);
-        this.zoomBox.className = this.boxDivClassName;                                         
-        this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
-        this.map.viewPortDiv.appendChild(this.zoomBox);
-
-        OpenLayers.Element.addClass(
-            this.map.viewPortDiv, "olDrawBox"
-        );
-    },
-
-    /**
-    * Method: moveBox
-    */
-    moveBox: function (xy) {
-        var startX = this.dragHandler.start.x;
-        var startY = this.dragHandler.start.y;
-        var deltaX = Math.abs(startX - xy.x);
-        var deltaY = Math.abs(startY - xy.y);
-        this.zoomBox.style.width = Math.max(1, deltaX) + "px";
-        this.zoomBox.style.height = Math.max(1, deltaY) + "px";
-        this.zoomBox.style.left = xy.x < startX ? xy.x+"px" : startX+"px";
-        this.zoomBox.style.top = xy.y < startY ? xy.y+"px" : startY+"px";
-
-        // depending on the box model, modify width and height to take borders
-        // of the box into account
-        var box = this.getBoxCharacteristics();
-        if (box.newBoxModel) {
-            if (xy.x > startX) {
-                this.zoomBox.style.width =
-                    Math.max(1, deltaX - box.xOffset) + "px";
-            }
-            if (xy.y > startY) {
-                this.zoomBox.style.height =
-                    Math.max(1, deltaY - box.yOffset) + "px";
-            }
-        }
-    },
-
-    /**
-    * Method: endBox
-    */
-    endBox: function(end) {
-        var result;
-        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);
-            var left = Math.min(start.x, end.x);
-            var right = Math.max(start.x, end.x);
-            result = new OpenLayers.Bounds(left, bottom, right, top);
-        } else {
-            result = this.dragHandler.start.clone(); // i.e. OL.Pixel
-        } 
-        this.removeBox();
-
-        this.callback("done", [result]);
-    },
-
-    /**
-     * Method: removeBox
-     * Remove the zoombox from the screen and nullify our reference to it.
-     */
-    removeBox: function() {
-        this.map.viewPortDiv.removeChild(this.zoomBox);
-        this.zoomBox = null;
-        this.boxCharacteristics = null;
-        OpenLayers.Element.removeClass(
-            this.map.viewPortDiv, "olDrawBox"
-        );
-
-    },
-
-    /**
-     * Method: activate
-     */
-    activate: function () {
-        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
-            this.dragHandler.activate();
-            return true;
-        } else {
-            return false;
-        }
-    },
-
-    /**
-     * Method: deactivate
-     */
-    deactivate: function () {
-        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
-            this.dragHandler.deactivate();
-            return true;
-        } else {
-            return false;
-        }
-    },
-    
-    /**
-     * Method: getCharacteristics
-     * Determines offset and box model for a box.
+     * point - {Object} An object with x and y properties. 
      * 
      * Returns:
-     * {Object} a hash with the following properties:
-     *     - xOffset - Corner offset in x-direction
-     *     - yOffset - Corner offset in y-direction
-     *     - newBoxModel - true for all browsers except IE in quirks mode
+     * {Object} The point, with the x and y properties transformed from
+     * spherical mercator to unprojected coordinates..
      */
-    getBoxCharacteristics: function() {
-        if (!this.boxCharacteristics) {
-            var xOffset = parseInt(OpenLayers.Element.getStyle(this.zoomBox,
-                "border-left-width")) + parseInt(OpenLayers.Element.getStyle(
-                this.zoomBox, "border-right-width")) + 1;
-            var yOffset = parseInt(OpenLayers.Element.getStyle(this.zoomBox,
-                "border-top-width")) + parseInt(OpenLayers.Element.getStyle(
-                this.zoomBox, "border-bottom-width")) + 1;
-            // all browsers use the new box model, except IE in quirks mode
-            var newBoxModel = OpenLayers.Util.getBrowserName() == "msie" ?
-                document.compatMode != "BackCompat" : true;
-            this.boxCharacteristics = {
-                xOffset: !isNaN(xOffset) ? xOffset: 0,
-                yOffset: !isNaN(yOffset) ? yOffset: 0,
-                newBoxModel: newBoxModel
-            };
-        }
-        return this.boxCharacteristics;
-    },
+    projectInverse: function(point) {
+        var lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(point.x, point.y);
+        point.x = lonlat.lon;
+        point.y = lonlat.lat;
+        return point;
+    }
 
-    CLASS_NAME: "OpenLayers.Handler.Box"
-});
-/* ======================================================================
-    OpenLayers/Handler/RegularPolygon.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/Handler/Drag.js
+ * Note: Transforms for web mercator <-> EPSG:4326
+ * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.
+ * OpenLayers originally started referring to EPSG:900913 as web mercator.
+ * The EPSG has declared EPSG:3857 to be web mercator.  
+ * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as 
+ * equivalent.  See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084
  */
-
-/**
- * Class: OpenLayers.Handler.RegularPolygon
- * Handler to draw a regular polygon on the map.  Polygon is displayed on mouse
- *     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, {
+(function() {
     
-    /**
-     * APIProperty: sides
-     * {Integer} Number of sides for the regular polygon.  Needs to be greater
-     *     than 2.  Defaults to 4.
-     */
-    sides: 4,
-
-    /**
-     * APIProperty: radius
-     * {Float} Optional radius in map units of the regular polygon.  If this is
-     *     set to some non-zero value, a polygon with a fixed radius will be
-     *     drawn and dragged with mose movements.  If this property is not
-     *     set, dragging changes the radius of the polygon.  Set to null by
-     *     default.
-     */
-    radius: null,
+    // list of equivalent codes for web mercator
+    var codes = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"];
     
-    /**
-     * 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.  
-     */
-    snapAngle: null,
+    var add = OpenLayers.Projection.addTransform;
+    var merc = OpenLayers.Layer.SphericalMercator;
+    var same = OpenLayers.Projection.nullTransform;
     
-    /**
-     * APIProperty: snapToggle
-     * {String} If set, snapToggle is checked on mouse events and will set
-     *     the snap mode to the opposite of what it currently is.  To disallow
-     *     toggling between snap and non-snap mode, set freehandToggle to
-     *     null.  Acceptable toggle values are 'shiftKey', 'ctrlKey', and
-     *     'altKey'. Snap mode is only possible if this.snapAngle is set to a
-     *     non-zero value.
-     */
-    snapToggle: 'shiftKey',
-    
-    /**
-     * Property: layerOptions
-     * {Object} Any optional properties to be set on the sketch layer.
-     */
-    layerOptions: null,
-
-    /**
-     * APIProperty: persist
-     * {Boolean} Leave the feature rendered until clear is called.  Default
-     *     is false.  If set to true, the feature remains rendered until
-     *     clear is called, typically by deactivating the handler or starting
-     *     another drawing.
-     */
-    persist: false,
-
-    /**
-     * APIProperty: irregular
-     * {Boolean} Draw an irregular polygon instead of a regular polygon.
-     *     Default is false.  If true, the initial mouse down will represent
-     *     one corner of the polygon bounds and with each mouse movement, the
-     *     polygon will be stretched so the opposite corner of its bounds
-     *     follows the mouse position.  This property takes precedence over
-     *     the radius property.  If set to true, the radius property will
-     *     be ignored.
-     */
-    irregular: false,
-
-    /**
-     * Property: angle
-     * {Float} The angle from the origin (mouse down) to the current mouse
-     *     position, in radians.  This is measured counterclockwise from the
-     *     positive x-axis.
-     */
-    angle: null,
-
-    /**
-     * Property: fixedRadius
-     * {Boolean} The polygon has a fixed radius.  True if a radius is set before
-     *     drawing begins.  False otherwise.
-     */
-    fixedRadius: false,
-
-    /**
-     * Property: feature
-     * {<OpenLayers.Feature.Vector>} The currently drawn polygon feature
-     */
-    feature: null,
-
-    /**
-     * Property: layer
-     * {<OpenLayers.Layer.Vector>} The temporary drawing layer
-     */
-    layer: null,
-
-    /**
-     * Property: origin
-     * {<OpenLayers.Geometry.Point>} Location of the first mouse down
-     */
-    origin: null,
-
-    /**
-     * Constructor: OpenLayers.Handler.RegularPolygon
-     * Create a new regular polygon handler.
-     *
-     * Parameters:
-     * control - {<OpenLayers.Control>} The control that owns this handler
-     * callbacks - {Object} An object with a properties whose values are
-     *     functions.  Various callbacks described below.
-     * options - {Object} An object with properties to be set on the handler.
-     *     If the options.sides property is not specified, the number of sides
-     *     will default to 4.
-     *
-     * Named callbacks:
-     * create - Called when a sketch is first created.  Callback called with
-     *     the creation point geometry and sketch feature.
-     * done - Called when the sketch drawing is finished.  The callback will
-     *     recieve a single argument, the sketch geometry.
-     * cancel - Called when the handler is deactivated while drawing.  The
-     *     cancel callback will receive a geometry.
-     */
-    initialize: function(control, callbacks, options) {
-        if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
-            this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
+    var i, len, code, other, j;
+    for (i=0, len=codes.length; i<len; ++i) {
+        code = codes[i];
+        add("EPSG:4326", code, merc.projectForward);
+        add(code, "EPSG:4326", merc.projectInverse);
+        for (j=i+1; j<len; ++j) {
+            other = codes[j];
+            add(code, other, same);
+            add(other, code, same);
         }
-
-        OpenLayers.Handler.prototype.initialize.apply(this,
-                                                [control, callbacks, options]);
-        this.options = (options) ? options : {};
-    },
+    }
     
-    /**
-     * APIMethod: setOptions
-     * 
-     * Parameters:
-     * newOptions - {Object} 
-     */
-    setOptions: function (newOptions) {
-        OpenLayers.Util.extend(this.options, newOptions);
-        OpenLayers.Util.extend(this, newOptions);
-    },
-    
-    /**
-     * APIMethod: activate
-     * Turn on the handler.
-     *
-     * Return:
-     * {Boolean} The handler was successfully activated
-     */
-    activate: function() {
-        var activated = false;
-        if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
-            // create temporary vector layer for rendering geometry sketch
-            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: OpenLayers.Function.True
-            }, this.layerOptions);
-            this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
-            this.map.addLayer(this.layer);
-            activated = true;
-        }
-        return activated;
-    },
-
-    /**
-     * APIMethod: deactivate
-     * Turn off the handler.
-     *
-     * Return:
-     * {Boolean} The handler was successfully deactivated
-     */
-    deactivate: function() {
-        var deactivated = false;
-        if(OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) {
-            // call the cancel callback if mid-drawing
-            if(this.dragging) {
-                this.cancel();
-            }
-            // If a layer's map property is set to null, it means that that
-            // layer isn't added to the map. Since we ourself added the layer
-            // to the map in activate(), we can assume that if this.layer.map
-            // is null it means that the layer has been destroyed (as a result
-            // of map.destroy() for example.
-            if (this.layer.map != null) {
-                this.layer.destroy(false);
-                if (this.feature) {
-                    this.feature.destroy();
-                }
-            }
-            this.layer = null;
-            this.feature = null;
-            deactivated = true;
-        }
-        return deactivated;
-    },
-    
-    /**
-     * Method: down
-     * Start drawing a new feature
-     *
-     * Parameters:
-     * evt - {Event} The drag start event
-     */
-    down: function(evt) {
-        this.fixedRadius = !!(this.radius);
-        var maploc = this.map.getLonLatFromPixel(evt.xy);
-        this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat);
-        // create the new polygon
-        if(!this.fixedRadius || this.irregular) {
-            // smallest radius should not be less one pixel in map units
-            // VML doesn't behave well with smaller
-            this.radius = this.map.getResolution();
-        }
-        if(this.persist) {
-            this.clear();
-        }
-        this.feature = new OpenLayers.Feature.Vector();
-        this.createGeometry();
-        this.callback("create", [this.origin, this.feature]);
-        this.layer.addFeatures([this.feature], {silent: true});
-        this.layer.drawFeature(this.feature, this.style);
-    },
-    
-    /**
-     * Method: move
-     * Respond to drag move events
-     *
-     * Parameters:
-     * evt - {Evt} The move event
-     */
-    move: function(evt) {
-        var maploc = this.map.getLonLatFromPixel(evt.xy);
-        var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat);
-        if(this.irregular) {
-            var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2;
-            this.radius = Math.max(this.map.getResolution() / 2, ry);
-        } else if(this.fixedRadius) {
-            this.origin = point;
-        } else {
-            this.calculateAngle(point, evt);
-            this.radius = Math.max(this.map.getResolution() / 2,
-                                   point.distanceTo(this.origin));
-        }
-        this.modifyGeometry();
-        if(this.irregular) {
-            var dx = point.x - this.origin.x;
-            var dy = point.y - this.origin.y;
-            var ratio;
-            if(dy == 0) {
-                ratio = dx / (this.radius * Math.sqrt(2));
-            } else {
-                ratio = dx / dy;
-            }
-            this.feature.geometry.resize(1, this.origin, ratio);
-            this.feature.geometry.move(dx / 2, dy / 2);
-        }
-        this.layer.drawFeature(this.feature, this.style);
-    },
-
-    /**
-     * Method: up
-     * Finish drawing the feature
-     *
-     * Parameters:
-     * evt - {Event} The mouse up event
-     */
-    up: function(evt) {
-        this.finalize();
-        // the mouseup method of superclass doesn't call the
-        // "done" callback if there's been no move between
-        // down and up
-        if (this.start == this.last) {
-            this.callback("done", [evt.xy]);
-        }
-    },
-
-    /**
-     * Method: out
-     * Finish drawing the feature.
-     *
-     * Parameters:
-     * evt - {Event} The mouse out event
-     */
-    out: function(evt) {
-        this.finalize();
-    },
-
-    /**
-     * Method: createGeometry
-     * Create the new polygon geometry.  This is called at the start of the
-     *     drag and at any point during the drag if the number of sides
-     *     changes.
-     */
-    createGeometry: function() {
-        this.angle = Math.PI * ((1/this.sides) - (1/2));
-        if(this.snapAngle) {
-            this.angle += this.snapAngle * (Math.PI / 180);
-        }
-        this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon(
-            this.origin, this.radius, this.sides, this.snapAngle
-        );
-    },
-    
-    /**
-     * Method: modifyGeometry
-     * Modify the polygon geometry in place.
-     */
-    modifyGeometry: function() {
-        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)) {
-            this.createGeometry();
-            ring = this.feature.geometry.components[0];
-        }
-        for(var i=0; i<this.sides; ++i) {
-            point = ring.components[i];
-            angle = this.angle + (i * 2 * Math.PI / this.sides);
-            point.x = this.origin.x + (this.radius * Math.cos(angle));
-            point.y = this.origin.y + (this.radius * Math.sin(angle));
-            point.clearBounds();
-        }
-    },
-    
-    /**
-     * Method: calculateAngle
-     * Calculate the angle based on settings.
-     *
-     * Parameters:
-     * point - {<OpenLayers.Geometry.Point>}
-     * evt - {Event}
-     */
-    calculateAngle: function(point, evt) {
-        var alpha = Math.atan2(point.y - this.origin.y,
-                               point.x - this.origin.x);
-        if(this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) {
-            var snapAngleRad = (Math.PI / 180) * this.snapAngle;
-            this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad;
-        } else {
-            this.angle = alpha;
-        }
-    },
-
-    /**
-     * APIMethod: cancel
-     * Finish the geometry and call the "cancel" callback.
-     */
-    cancel: function() {
-        // the polygon geometry gets cloned in the callback method
-        this.callback("cancel", null);
-        this.finalize();
-    },
-
-    /**
-     * Method: finalize
-     * Finish the geometry and call the "done" callback.
-     */
-    finalize: function() {
-        this.origin = null;
-        this.radius = this.options.radius;
-    },
-
-    /**
-     * APIMethod: clear
-     * Clear any rendered features on the temporary layer.  This is called
-     *     when the handler is deactivated, canceled, or done (unless persist
-     *     is true).
-     */
-    clear: function() {
-        if (this.layer) {
-            this.layer.renderer.clear();
-            this.layer.destroyFeatures();
-        }
-    },
-    
-    /**
-     * Method: callback
-     * Trigger the control's named callback with the given arguments
-     *
-     * 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 with which to call the callback
-     *     (defined by the control).
-     */
-    callback: function (name, args) {
-        // override the callback method to always send the polygon geometry
-        if (this.callbacks[name]) {
-            this.callbacks[name].apply(this.control,
-                                       [this.feature.geometry.clone()]);
-        }
-        // since sketch features are added to the temporary layer
-        // they must be cleared here if done or cancel
-        if(!this.persist && (name == "done" || name == "cancel")) {
-            this.clear();
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Handler.RegularPolygon"
-});
+})();
 /* ======================================================================
     OpenLayers/Layer/EventPane.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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. */
@@ -27976,7 +10124,7 @@
         this.pane.style.display = this.div.style.display;
         this.pane.style.width="100%";
         this.pane.style.height="100%";
-        if (OpenLayers.Util.getBrowserName() == "msie") {
+        if (OpenLayers.BROWSER_NAME == "msie") {
             this.pane.style.background = 
                 "url(" + OpenLayers.Util.getImagesLocation() + "blank.gif)";
         }
@@ -28294,7 +10442,7 @@
     OpenLayers/Layer/FixedZoomLevels.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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. */
@@ -28610,1777 +10758,383 @@
 });
 
 /* ======================================================================
-    OpenLayers/Layer/HTTPRequest.js
+    OpenLayers/Layer/VirtualEarth.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/Layer/SphericalMercator.js
+ * @requires OpenLayers/Layer/EventPane.js
+ * @requires OpenLayers/Layer/FixedZoomLevels.js
+ * @requires OpenLayers/Lang.js
  */
 
 /**
- * Class: OpenLayers.Layer.HTTPRequest
+ * Class: OpenLayers.Layer.VirtualEarth
  * 
- * Inherits from: 
- *  - <OpenLayers.Layer>
+ * Inherits from:
+ *  - <OpenLayers.Layer.EventPane>
+ *  - <OpenLayers.Layer.FixedZoomLevels>
  */
-OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
-
+OpenLayers.Layer.VirtualEarth = OpenLayers.Class(
+    OpenLayers.Layer.EventPane,
+    OpenLayers.Layer.FixedZoomLevels, {
+    
     /** 
-     * 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.
+     * Constant: MIN_ZOOM_LEVEL
+     * {Integer} 1 
      */
-    URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
-
+    MIN_ZOOM_LEVEL: 1,
+    
     /** 
-     * Property: url
-     * {Array(String) or String} This is either an array of url strings or 
-     *                           a single url string. 
+     * Constant: MAX_ZOOM_LEVEL
+     * {Integer} 19
      */
-    url: null,
+    MAX_ZOOM_LEVEL: 19,
 
     /** 
-     * Property: params
-     * {Object} Hashtable of key/value parameters
+     * Constant: RESOLUTIONS
+     * {Array(Float)} Hardcode these resolutions so that they are more closely
+     *                tied with the standard wms projection
      */
-    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 
-     *           which can create non-square geographic pixels can, like WMS.
-     *           
-     */
-    reproject: false,
+    RESOLUTIONS: [
+        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.00004291534423828125,
+        0.00002145767211914062, 
+        0.00001072883605957031,
+        0.00000536441802978515
+    ],
 
     /**
-     * Constructor: OpenLayers.Layer.HTTPRequest
-     * 
-     * Parameters:
-     * name - {String}
-     * url - {Array(String) or String}
-     * params - {Object}
-     * options - {Object} Hashtable of extra options to tag onto the layer
+     * APIProperty: type
+     * {VEMapType}
      */
-    initialize: function(name, url, params, options) {
-        var newArguments = arguments;
-        newArguments = [name, options];
-        OpenLayers.Layer.prototype.initialize.apply(this, newArguments);
-        this.url = url;
-        this.params = OpenLayers.Util.extend( {}, params);
-    },
+    type: null,
 
     /**
-     * APIMethod: destroy
+     * APIProperty: wrapDateLine
+     * {Boolean} Allow user to pan forever east/west.  Default is true.  
+     *     Setting this to false only restricts panning if 
+     *     <sphericalMercator> is true. 
      */
-    destroy: function() {
-        this.url = null;
-        this.params = null;
-        OpenLayers.Layer.prototype.destroy.apply(this, arguments); 
-    },
-    
-    /**
-     * APIMethod: clone
-     * 
-     * Parameters:
-     * obj - {Object}
-     * 
-     * Returns:
-     * {<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.getOptions());
-        }
-        
-        //get all additions from superclasses
-        obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
+    wrapDateLine: true,
 
-        // copy/set any non-init, non-simple values here
-        
-        return obj;
-    },
-
-    /** 
-     * APIMethod: setUrl
-     * 
-     * Parameters:
-     * newUrl - {String}
-     */
-    setUrl: function(newUrl) {
-        this.url = newUrl;
-    },
-
     /**
-     * APIMethod: mergeNewParams
-     * 
-     * Parameters:
-     * newParams - {Object}
-     *
-     * Returns:
-     * redrawn: {Boolean} whether the layer was actually redrawn.
+     * 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. 
      */
-    mergeNewParams:function(newParams) {
-        this.params = OpenLayers.Util.extend(this.params, newParams);
-        var ret = this.redraw();
-        if(this.map != null) {
-            this.map.events.triggerEvent("changelayer", {
-                layer: this,
-                property: "params"
-            });
-        }
-        return ret;
-    },
-
-    /**
-     * APIMethod: redraw
-     * Redraws the layer.  Returns true if the layer was redrawn, false if not.
-     *
-     * Parameters:
-     * force - {Boolean} Force redraw by adding random parameter.
-     *
-     * Returns:
-     * {Boolean} The layer was redrawn.
-     */
-    redraw: function(force) { 
-        if (force) {
-            return this.mergeNewParams({"_olSalt": Math.random()});
-        } else {
-            return OpenLayers.Layer.prototype.redraw.apply(this, []);
-        }
-    },
+    sphericalMercator: false,
     
     /**
-     * Method: selectUrl
-     * selectUrl() implements the standard floating-point multiplicative
-     *     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.
-     *
-     * Parameters:
-     * paramString - {String}
-     * urls - {Array(String)}
-     * 
-     * Returns:
-     * {String} An entry from the urls array, deterministically selected based
-     *          on the paramString.
+     * 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.
      */
-    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); 
-        }
-        return urls[Math.floor(product * urls.length)];
-    },
+    animationEnabled: true, 
 
     /** 
-     * Method: getFullRequestString
-     * 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. 
-     *
-     *    return in formatted string like this:
-     *        "server?key1=value1&key2=value2&key3=value3"
+     * Constructor: OpenLayers.Layer.VirtualEarth
      * 
-     * 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: 
-     * {String}
+     * name - {String}
+     * options - {Object}
      */
-    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 
-        // 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 
-        // 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));
-        for(var key in allParams) {
-            if(key.toUpperCase() in urlParams) {
-                delete allParams[key];
-            }
+    initialize: function(name, options) {
+        OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
+        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, 
+                                                                    arguments);
+        if(this.sphericalMercator) {
+            OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
+            this.initMercatorParameters();
         }
-        paramsString = OpenLayers.Util.getParameterString(allParams);
-        
-        return OpenLayers.Util.urlAppend(url, paramsString);
     },
-
-    CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
-});
-/* ======================================================================
-    OpenLayers/Layer/Markers.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
- */
-
-/**
- * Class: OpenLayers.Layer.Markers
- * 
- * Inherits from:
- *  - <OpenLayers.Layer> 
- */
-OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, {
     
-    /** 
-     * APIProperty: isBaseLayer 
-     * {Boolean} Markers layer is never a base layer.  
+    /**
+     * Method: loadMapObject
      */
-    isBaseLayer: false,
-    
-    /** 
-     * APIProperty: markers 
-     * {Array(<OpenLayers.Marker>)} internal marker list 
-     */
-    markers: null,
+    loadMapObject:function() {
 
+        // create div and set to same size as map
+        var veDiv = OpenLayers.Util.createDiv(this.name);
+        var sz = this.map.getSize();
+        veDiv.style.width = sz.w + "px";
+        veDiv.style.height = sz.h + "px";
+        this.div.appendChild(veDiv);
 
-    /** 
-     * 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 
-     * Create a Markers layer.
-     *
-     * Parameters:
-     * 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 
-     */
-    destroy: function() {
-        this.clearMarkers();
-        this.markers = null;
-        OpenLayers.Layer.prototype.destroy.apply(this, arguments);
-    },
+        try { // crash prevention
+            this.mapObject = new VEMap(this.name);
+        } catch (e) { }
 
-    /**
-     * APIMethod: setOpacity
-     * Sets the opacity for all the markers.
-     * 
-     * Parameter:
-     * opacity - {Float}
-     */
-    setOpacity: function(opacity) {
-        if (opacity != this.opacity) {
-            this.opacity = opacity;
-            for (var i=0, len=this.markers.length; i<len; i++) {
-                this.markers[i].setOpacity(this.opacity);
-            }
-        }
-    },
+        if (this.mapObject != null) {
+            try { // this is to catch a Mozilla bug without falling apart
 
-    /** 
-     * Method: moveTo
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>} 
-     * zoomChanged - {Boolean} 
-     * dragging - {Boolean} 
-     */
-    moveTo:function(bounds, zoomChanged, dragging) {
-        OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
+                // 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", OpenLayers.Function.True);
 
-        if (zoomChanged || !this.drawn) {
-            for(var i=0, len=this.markers.length; i<len; i++) {
-                this.drawMarker(this.markers[i]);
+            } catch (e) { }
+            this.mapObject.HideDashboard();
+            if(typeof this.mapObject.SetAnimationEnabled == "function") {
+                this.mapObject.SetAnimationEnabled(this.animationEnabled);
             }
-            this.drawn = true;
         }
-    },
 
-    /**
-     * APIMethod: addMarker
-     *
-     * Parameters:
-     * marker - {<OpenLayers.Marker>} 
-     */
-    addMarker: function(marker) {
-        this.markers.push(marker);
+        //can we do smooth panning? this is an unpublished method, so we need 
+        // to be careful
+        if ( !this.mapObject ||
+             !this.mapObject.vemapcontrol ||
+             !this.mapObject.vemapcontrol.PanMap ||
+             (typeof this.mapObject.vemapcontrol.PanMap != "function")) {
 
-        if (this.opacity != null) {
-            marker.setOpacity(this.opacity);
+            this.dragPanMapObject = null;
         }
 
-        if (this.map && this.map.getExtent()) {
-            marker.map = this.map;
-            this.drawMarker(marker);
-        }
     },
 
     /**
-     * APIMethod: removeMarker
-     *
-     * Parameters:
-     * marker - {<OpenLayers.Marker>} 
+     * Method: onMapResize
      */
-    removeMarker: function(marker) {
-        if (this.markers && this.markers.length) {
-            OpenLayers.Util.removeItem(this.markers, marker);
-            marker.erase();
-        }
+    onMapResize: function() {
+        this.mapObject.Resize(this.map.size.w, this.map.size.h);
     },
 
-    /**
-     * Method: clearMarkers
-     * This method removes all markers from a layer. The markers are not
-     * destroyed by this function, but are removed from the list of markers.
-     */
-    clearMarkers: function() {
-        if (this.markers != null) {
-            while(this.markers.length > 0) {
-                this.removeMarker(this.markers[0]);
-            }
-        }
-    },
-
     /** 
-     * Method: drawMarker
-     * Calculate the pixel location for the marker, create it, and 
-     *    add it to the layer's div
-     *
-     * Parameters:
-     * marker - {<OpenLayers.Marker>} 
-     */
-    drawMarker: function(marker) {
-        var px = this.map.getLayerPxFromLonLat(marker.lonlat);
-        if (px == null) {
-            marker.display(false);
-        } else {
-            if (!marker.isDrawn()) {
-                var markerImg = marker.draw(px);
-                this.div.appendChild(markerImg);
-            } else if(marker.icon) {
-                marker.icon.moveTo(px);
-            }
-        }
-    },
-    
-    /** 
-     * APIMethod: getDataExtent
-     * Calculates the max extent which includes all of the markers.
+     * APIMethod: getWarningHTML
      * 
-     * Returns:
-     * {<OpenLayers.Bounds>}
+     * Returns: 
+     * {String} String with information on why layer is broken, how to get
+     *          it working.
      */
-    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++) {
-                var marker = this.markers[i];
-                maxExtent.extend(marker.lonlat);
-            }
-        }
-
-        return maxExtent;
+    getWarningHTML:function() {
+        return OpenLayers.i18n(
+            "getLayerWarning", {'layerType':'VE', 'layerLib':'VirtualEarth'}
+        );
     },
 
-    CLASS_NAME: "OpenLayers.Layer.Markers"
-});
-/* ======================================================================
-    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
- */
+    /************************************
+     *                                  *
+     *   MapObject Interface Controls   *
+     *                                  *
+     ************************************/
 
-/**
- * Class: OpenLayers.Layer.SphericalMercator
- * A mixin for layers that wraps up the pieces neccesary to have a coordinate
- *     conversion for working with commercial APIs which use a spherical
- *     mercator projection.  Using this layer as a base layer, additional
- *     layers can be used as overlays if they are in the same projection.
- *
- * A layer is given properties of this object by setting the sphericalMercator
- *     property to true.
- *
- * More projection information:
- *  - http://spatialreference.org/ref/user/google-projection/
- *
- * Proj4 Text:
- *     +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
- *
- * 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], 
- *     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], 
- *     PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST],
- *     AXIS["y", NORTH], AUTHORITY["EPSG","900913"]]
- */
-OpenLayers.Layer.SphericalMercator = {
 
-    /**
-     * Method: getExtent
-     * Get the map's extent.
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>} The map extent.
+  // 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
      */
-    getExtent: function() {
-        var extent = null;
-        if (this.sphericalMercator) {
-            extent = this.map.calculateBounds();
-        } else {
-            extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);
-        }
-        return extent;
+    setMapObjectCenter: function(center, zoom) {
+        this.mapObject.SetCenterAndZoom(center, zoom); 
     },
-
+   
     /**
-     * Method: getLonLatFromViewPortPx
-     * Get a map location from a pixel location
+     * APIMethod: getMapObjectCenter
      * 
-     * 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
+     * Returns: 
+     * {Object} The mapObject's current center in Map Object format
      */
-    getLonLatFromViewPortPx: function (viewPortPx) {
-        return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments);
+    getMapObjectCenter: function() {
+        return this.mapObject.GetCenter();
     },
-    
+
     /**
-     * Method: getViewPortPxFromLonLat
-     * Get a pixel location from a map location
-     *
+     * APIMethod: dragPanMapObject
+     * 
      * 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
+     * dX - {Integer}
+     * dY - {Integer}
      */
-    getViewPortPxFromLonLat: function (lonlat) {
-        return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments);
+    dragPanMapObject: function(dX, dY) {
+        this.mapObject.vemapcontrol.PanMap(dX, -dY);
     },
 
     /** 
-     * Method: initMercatorParameters 
-     * Set up the mercator parameters on the layer: resolutions,
-     *     projection, units.
-     */
-    initMercatorParameters: function() {
-        // set up properties for Mercator - assume EPSG:900913
-        this.RESOLUTIONS = [];
-        var maxResolution = 156543.0339;
-        for(var zoom=0; zoom<=this.MAX_ZOOM_LEVEL; ++zoom) {
-            this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom);
-        }
-        this.units = "m";
-        this.projection = this.projection || "EPSG:900913";
-    },
-
-    /**
-     * APIMethod: forwardMercator
-     * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator.
-     *
-     * Parameters:
-     * lon - {float} 
-     * lat - {float}
+     * APIMethod: getMapObjectZoom
      * 
      * Returns:
-     * {<OpenLayers.LonLat>} The coordinates transformed to Mercator.
+     * {Integer} The mapObject's current zoom, in Map Object format
      */
-    forwardMercator: function(lon, lat) {
-        var x = lon * 20037508.34 / 180;
-        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);
+    getMapObjectZoom: function() {
+        return this.mapObject.GetZoomLevel();
     },
 
+
+  // LonLat - Pixel Translation
+  
     /**
-     * APIMethod: inverseMercator
-     * Given a x,y in Spherical Mercator, return a point in EPSG:4326.
-     *
+     * APIMethod: getMapObjectLonLatFromMapObjectPixel
+     * 
      * Parameters:
-     * x - {float} A map x in Spherical Mercator.
-     * y - {float} A map y in Spherical Mercator.
+     * moPixel - {Object} MapObject Pixel format
      * 
      * Returns:
-     * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326.
+     * {Object} MapObject LonLat translated from MapObject Pixel
      */
-    inverseMercator: function(x, y) {
-
-        var lon = (x / 20037508.34) * 180;
-        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);
+    getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
+        //the conditional here is to test if we are running the v6 of VE
+        return (typeof VEPixel != 'undefined') 
+            ? this.mapObject.PixelToLatLong(moPixel)
+            : this.mapObject.PixelToLatLong(moPixel.x, moPixel.y);
     },
 
     /**
-     * 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.
-     *
+     * APIMethod: getMapObjectPixelFromMapObjectLonLat
+     * 
      * Parameters:
-     * point - {Object} An object with x and y properties. 
+     * moLonLat - {Object} MapObject LonLat format
      * 
      * Returns:
-     * {Object} The point, with the x and y properties transformed to spherical
-     * mercator.
+     * {Object} MapObject Pixel transtlated from MapObject LonLat
      */
-    projectForward: function(point) {
-        var lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(point.x, point.y);
-        point.x = lonlat.lon;
-        point.y = lonlat.lat;
-        return point;
+    getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
+        return this.mapObject.LatLongToPixel(moLonLat);
     },
-    
-    /**
-     * 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. 
-     * 
-     * Returns:
-     * {Object} The point, with the x and y properties transformed from
-     * spherical mercator to unprojected coordinates..
-     */
-    projectInverse: function(point) {
-        var lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(point.x, point.y);
-        point.x = lonlat.lon;
-        point.y = lonlat.lat;
-        return point;
-    }
 
-};
 
-/**
- * Note: Two transforms declared
- * Transforms from EPSG:4326 to EPSG:900913 and from EPSG:900913 to EPSG:4326
- *     are set by this class.
- */
-OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:900913",
-    OpenLayers.Layer.SphericalMercator.projectForward);
-OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:4326",
-    OpenLayers.Layer.SphericalMercator.projectInverse);
-/* ======================================================================
-    OpenLayers/Control/DrawFeature.js
-   ====================================================================== */
+    /************************************
+     *                                  *
+     *       MapObject Primitives       *
+     *                                  *
+     ************************************/
 
-/* 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/Feature/Vector.js
- */
-
-/**
- * Class: OpenLayers.Control.DrawFeature
- * The DrawFeature control draws point, line or polygon features on a vector
- * layer when active.
- *
- * Inherits from:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, {
+  // LonLat
     
     /**
-     * Property: layer
-     * {<OpenLayers.Layer.Vector>}
-     */
-    layer: null,
-
-    /**
-     * Property: callbacks
-     * {Object} The functions that are sent to the handler for callback
-     */
-    callbacks: null,
-    
-    /**
-     * Constant: EVENT_TYPES
-     *
-     * Supported event types:
-     * 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
-     * {Function} Called after each feature is added
-     */
-    featureAdded: function() {},
-
-    /**
-     * APIProperty: handlerOptions
-     * {Object} Used to set non-default properties on the control's handler
-     */
-    handlerOptions: null,
-    
-    /**
-     * Constructor: OpenLayers.Control.DrawFeature
+     * APIMethod: getLongitudeFromMapObjectLonLat
      * 
      * Parameters:
-     * layer - {<OpenLayers.Layer.Vector>} 
-     * handler - {<OpenLayers.Handler>} 
-     * options - {Object} 
+     * moLonLat - {Object} MapObject LonLat format
+     * 
+     * Returns:
+     * {Float} Longitude of the given MapObject LonLat
      */
-    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(
-            {
-                done: this.drawFeature,
-                modify: function(vertex, feature) {
-                    this.layer.events.triggerEvent(
-                        "sketchmodified", {vertex: vertex, feature: feature}
-                    );
-                },
-                create: function(vertex, feature) {
-                    this.layer.events.triggerEvent(
-                        "sketchstarted", {vertex: vertex, feature: feature}
-                    );
-                }
-            },
-            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.layerOptions = OpenLayers.Util.applyDefaults(
-                this.handlerOptions.layerOptions,
-                {styleMap: new OpenLayers.StyleMap({"default": sketchStyle})}
-            );
-        }
-        this.handler = new handler(this, this.callbacks, this.handlerOptions);
+    getLongitudeFromMapObjectLonLat: function(moLonLat) {
+        return this.sphericalMercator ? 
+            this.forwardMercator(moLonLat.Longitude, moLonLat.Latitude).lon :
+            moLonLat.Longitude;
     },
 
     /**
-     * Method: drawFeature
-     */
-    drawFeature: function(geometry) {
-        var feature = new OpenLayers.Feature.Vector(geometry);
-        var proceed = this.layer.events.triggerEvent(
-            "sketchcomplete", {feature: feature}
-        );
-        if(proceed !== false) {
-            feature.state = OpenLayers.State.INSERT;
-            this.layer.addFeatures([feature]);
-            this.featureAdded(feature);
-            this.events.triggerEvent("featureadded",{feature : feature});
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Control.DrawFeature"
-});
-/* ======================================================================
-    OpenLayers/Control/Measure.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/Control.js
- * @requires OpenLayers/Feature/Vector.js
- */
-
-/**
- * Class: OpenLayers.Control.Measure
- * Allows for drawing of features for measurements.
- *
- * Inherits from:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, {
-
-    /**
-     * Constant: EVENT_TYPES
-     * {Array(String)} Supported application event types.  Register a listener
-     *     for a particular event with the following syntax:
-     * (code)
-     * control.events.register(type, obj, listener);
-     * (end)
-     *
-     * Listeners will be called with a reference to an event object.  The
-     *     properties of this event depends on exactly what happened.
-     *
-     * Supported control event types (in addition to those from <OpenLayers.Control>):
-     * measure - Triggered when a measurement sketch is complete.  Listeners
-     *      will receive an event with measure, units, order, and geometry
-     *      properties.
-     * measurepartial - Triggered when a new point is added to the
-     *      measurement sketch.  Listeners receive an event with measure,
-     *      units, order, and geometry.
-     */
-    EVENT_TYPES: ['measure', 'measurepartial'],
-
-    /**
-     * APIProperty: handlerOptions
-     * {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,
-    
-    /**
-     * APIProperty: displaySystem
-     * {String} Display system for output measurements.  Supported values
-     *     are 'english', 'metric', and 'geographic'.  Default is 'metric'.
-     */
-    displaySystem: 'metric',
-    
-    /**
-     * APIProperty: geodesic
-     * {Boolean} Calculate geodesic metrics instead of planar metrics.  This
-     *     requires that geometries can be transformed into Geographic/WGS84
-     *     (if that is not already the map projection).  Default is false.
-     */
-    geodesic: false,
-    
-    /**
-     * APIProperty: displaySystemUnits
-     * {Object} Units for various measurement systems.  Values are arrays
-     *     of unit abbreviations (from OpenLayers.INCHES_PER_UNIT) in decreasing
-     *     order of length.
-     */
-    displaySystemUnits: {
-        geographic: ['dd'],
-        english: ['mi', 'ft', 'in'],
-        metric: ['km', 'm']
-    },
-
-    /**
-     * Property: delay
-     * {Number} Number of milliseconds between clicks before the event is
-     *     considered a double-click.  The "measurepartial" event will not
-     *     be triggered if the sketch is completed within this time.  This
-     *     is required for IE where creating a browser reflow (if a listener
-     *     is modifying the DOM by displaying the measurement values) messes
-     *     with the dblclick listener in the sketch handler.
-     */
-    partialDelay: 300,
-
-    /**
-     * Property: delayedTrigger
-     * {Number} Timeout id of trigger for measurepartial.
-     */
-    delayedTrigger: null,
-
-    /**
-     * APIProperty: persist
-     * {Boolean} Keep the temporary measurement sketch drawn after the
-     *     measurement is complete.  The geometry will persist until a new
-     *     measurement is started, the control is deactivated, or <cancel> is
-     *     called.
-     */
-    persist: false,
-
-    /**
-     * Constructor: OpenLayers.Control.Measure
+     * APIMethod: getLatitudeFromMapObjectLonLat
      * 
      * Parameters:
-     * handler - {<OpenLayers.Handler>} 
-     * options - {Object} 
-     */
-    initialize: function(handler, options) {
-        // concatenate events specific to measure with those from the base
-        this.EVENT_TYPES =
-            OpenLayers.Control.Measure.prototype.EVENT_TYPES.concat(
-            OpenLayers.Control.prototype.EVENT_TYPES
-        );
-        OpenLayers.Control.prototype.initialize.apply(this, [options]);
-        this.callbacks = OpenLayers.Util.extend(
-            {done: this.measureComplete, point: this.measurePartial},
-            this.callbacks
-        );
-
-        // 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: deactivate
-     */
-    deactivate: function() {
-        this.cancelDelay();
-        return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
-    },
-
-    /**
-     * APIMethod: cancel
-     * Stop the control from measuring.  If <persist> is true, the temporary
-     *     sketch will be erased.
-     */
-    cancel: function() {
-        this.cancelDelay();
-        this.handler.cancel();
-    },
-    
-    /**
-     * Method: updateHandler
-     *
-     * Parameters:
-     * handler - {Function} One of the sketch handler constructors.
-     * options - {Object} Options for the handler.
-     */
-    updateHandler: function(handler, options) {
-        var active = this.active;
-        if(active) {
-            this.deactivate();
-        }
-        this.handler = new handler(this, this.callbacks, options);
-        if(active) {
-            this.activate();
-        }
-    },
-
-    /**
-     * Method: measureComplete
-     * Called when the measurement sketch is done.
-     *
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     */
-    measureComplete: function(geometry) {
-        this.cancelDelay();
-        this.measure(geometry, "measure");
-    },
-    
-    /**
-     * Method: measurePartial
-     * Called each time a new point is added to the measurement sketch.
-     *
-     * Parameters:
-     * point - {<OpenLayers.Geometry.Point>} The last point added.
-     * geometry - {<OpenLayers.Geometry>} The sketch geometry.
-     */
-    measurePartial: function(point, geometry) {
-        this.cancelDelay();
-        geometry = geometry.clone();
-        // when we're wating for a dblclick, we have to trigger measurepartial
-        // after some delay to deal with reflow issues in IE
-        if (this.handler.freehandMode(this.handler.evt)) {
-            // no dblclick in freehand mode
-            this.measure(geometry, "measurepartial");
-        } else {
-            this.delayedTrigger = window.setTimeout(
-                OpenLayers.Function.bind(function() {
-                    this.delayedTrigger = null;
-                    this.measure(geometry, "measurepartial");
-                }, this),
-                this.partialDelay
-            );
-        }
-    },
-
-    /**
-     * Method: cancelDelay
-     * Cancels the delay measurement that measurePartial began.
-     */
-    cancelDelay: function() {
-        if (this.delayedTrigger !== null) {
-            window.clearTimeout(this.delayedTrigger);
-            this.delayedTrigger = null;
-        }
-    },
-
-    /**
-     * Method: measure
-     *
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * eventType - {String}
-     */
-    measure: function(geometry, eventType) {
-        var stat, order;
-        if(geometry.CLASS_NAME.indexOf('LineString') > -1) {
-            stat = this.getBestLength(geometry);
-            order = 1;
-        } else {
-            stat = this.getBestArea(geometry);
-            order = 2;
-        }
-        this.events.triggerEvent(eventType, {
-            measure: stat[0],
-            units: stat[1],
-            order: order,
-            geometry: geometry
-        });
-    },
-    
-    /**
-     * Method: getBestArea
-     * Based on the <displaySystem> returns the area of a geometry.
-     *
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     *
+     * moLonLat - {Object} MapObject LonLat format
+     * 
      * Returns:
-     * {Array([Float, String])}  Returns a two item array containing the
-     *     area and the units abbreviation.
+     * {Float} Latitude of the given MapObject LonLat
      */
-    getBestArea: function(geometry) {
-        var units = this.displaySystemUnits[this.displaySystem];
-        var unit, area;
-        for(var i=0, len=units.length; i<len; ++i) {
-            unit = units[i];
-            area = this.getArea(geometry, unit);
-            if(area > 1) {
-                break;
-            }
-        }
-        return [area, unit];
+    getLatitudeFromMapObjectLonLat: function(moLonLat) {
+        return this.sphericalMercator ? 
+            this.forwardMercator(moLonLat.Longitude, moLonLat.Latitude).lat :
+            moLonLat.Latitude;
     },
-    
-    /**
-     * Method: getArea
-     *
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * units - {String} Unit abbreviation
-     *
-     * Returns:
-     * {Float} The geometry area in the given units.
-     */
-    getArea: function(geometry, units) {
-        var area, geomUnits;
-        if(this.geodesic) {
-            area = geometry.getGeodesicArea(this.map.getProjectionObject());
-            geomUnits = "m";
-        } else {
-            area = geometry.getArea();
-            geomUnits = this.map.getUnits();
-        }
-        var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
-        if(inPerDisplayUnit) {
-            var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
-            area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2);
-        }
-        return area;
-    },
-    
-    /**
-     * Method: getBestLength
-     * Based on the <displaySystem> returns the length of a geometry.
-     *
-     * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     *
-     * Returns:
-     * {Array([Float, String])}  Returns a two item array containing the
-     *     length and the units abbreviation.
-     */
-    getBestLength: function(geometry) {
-        var units = this.displaySystemUnits[this.displaySystem];
-        var unit, length;
-        for(var i=0, len=units.length; i<len; ++i) {
-            unit = units[i];
-            length = this.getLength(geometry, unit);
-            if(length > 1) {
-                break;
-            }
-        }
-        return [length, unit];
-    },
 
     /**
-     * Method: getLength
-     *
+     * APIMethod: getMapObjectLonLatFromLonLat
+     * 
      * Parameters:
-     * geometry - {<OpenLayers.Geometry>}
-     * units - {String} Unit abbreviation
-     *
+     * lon - {Float}
+     * lat - {Float}
+     * 
      * Returns:
-     * {Float} The geometry length in the given units.
+     * {Object} MapObject LonLat built from lon and lat params
      */
-    getLength: function(geometry, units) {
-        var length, geomUnits;
-        if(this.geodesic) {
-            length = geometry.getGeodesicLength(this.map.getProjectionObject());
-            geomUnits = "m";
+    getMapObjectLonLatFromLonLat: function(lon, lat) {
+        var veLatLong;
+        if(this.sphericalMercator) {
+            var lonlat = this.inverseMercator(lon, lat);
+            veLatLong = new VELatLong(lonlat.lat, lonlat.lon);
         } else {
-            length = geometry.getLength();
-            geomUnits = this.map.getUnits();
+            veLatLong = new VELatLong(lat, lon);
         }
-        var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
-        if(inPerDisplayUnit) {
-            var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
-            length *= (inPerMapUnit / inPerDisplayUnit);
-        }
-        return length;
+        return veLatLong;
     },
 
-    CLASS_NAME: "OpenLayers.Control.Measure"
-});
-/* ======================================================================
-    OpenLayers/Control/ZoomBox.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/Control.js
- * @requires OpenLayers/Handler/Box.js
- */
-
-/**
- * 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 mouse.
- *
- * Inherits from:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, {
-    /**
-     * Property: type
-     * {OpenLayers.Control.TYPE}
-     */
-    type: OpenLayers.Control.TYPE_TOOL,
-
-    /**
-     * Property: out
-     * {Boolean} Should the control be used for zooming out?
-     */
-    out: false,
-
-    /**
-     * Property: alwaysZoom
-     * {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} );
-    },
-
-    /**
-     * Method: zoomBox
-     *
-     * Parameters:
-     * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
-     */
-    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));
-                bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat,
-                                               maxXY.lon, maxXY.lat);
-            } else {
-                var pixWidth = Math.abs(position.right-position.left);
-                var pixHeight = Math.abs(position.top-position.bottom);
-                var zoomFactor = Math.min((this.map.size.h / pixHeight),
-                    (this.map.size.w / pixWidth));
-                var extent = this.map.getExtent();
-                var center = this.map.getLonLatFromPixel(
-                    position.getCenterPixel());
-                var xmin = center.lon - (extent.getWidth()/2)*zoomFactor;
-                var xmax = center.lon + (extent.getWidth()/2)*zoomFactor;
-                var ymin = center.lat - (extent.getHeight()/2)*zoomFactor;
-                var ymax = center.lat + (extent.getHeight()/2)*zoomFactor;
-                bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax);
-            }
-            // 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)); 
-            }
-        } else { // it's a pixel
-            if (!this.out) {
-                this.map.setCenter(this.map.getLonLatFromPixel(position),
-                               this.map.getZoom() + 1);
-            } else {
-                this.map.setCenter(this.map.getLonLatFromPixel(position),
-                               this.map.getZoom() - 1);
-            }
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Control.ZoomBox"
-});
-/* ======================================================================
-    OpenLayers/Format/WFSCapabilities/v1_0_0.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/WFSCapabilities/v1.js
- */
-
-/**
- * Class: OpenLayers.Format.WFSCapabilities/v1_0_0
- * Read WMS Capabilities version 1.0.0.
- * 
- * Inherits from:
- *  - <OpenLayers.Format.WFSCapabilities>
- */
-OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class(
-    OpenLayers.Format.WFSCapabilities.v1, {
+  // Pixel
     
     /**
-     * Constructor: OpenLayers.Format.WFSCapabilities.v1_0_0
-     * Create a new parser for WFS capabilities version 1.0.0.
-     *
+     * APIMethod: getXFromMapObjectPixel
+     * 
      * Parameters:
-     * options - {Object} An optional object whose properties will be set on
-     *     this instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Format.WFSCapabilities.v1.prototype.initialize.apply(
-            this, [options]
-        );
-    },
-    
-    /**
-     * Method: read_cap_Service
-     */
-    read_cap_Service: function(capabilities, node) {
-        var service = {};
-        this.runChildNodes(service, node);
-        capabilities.service = service;
-    },
-
-    /**
-     * Method: read_cap_Fees
-     */
-    read_cap_Fees: function(service, node) {
-        var fees = this.getChildValue(node);
-        if (fees && fees.toLowerCase() != "none") {
-            service.fees = fees;
-        }
-    },
-
-    /**
-     * Method: read_cap_AccessConstraints
-     */
-    read_cap_AccessConstraints: function(service, node) {
-        var constraints = this.getChildValue(node);
-        if (constraints && constraints.toLowerCase() != "none") {
-            service.accessConstraints = constraints;
-        }
-    },
-    
-    /**
-     * Method: read_cap_OnlineResource
-     */
-    read_cap_OnlineResource: function(service, node) {
-        var onlineResource = this.getChildValue(node);
-        if (onlineResource && onlineResource.toLowerCase() != "none") {
-            service.onlineResource = onlineResource;
-        }
-    },
-    
-    /**
-     * Method: read_cap_Keywords
-     */
-    read_cap_Keywords: function(service, node) {
-        var keywords = this.getChildValue(node);
-        if (keywords && keywords.toLowerCase() != "none") {
-            service.keywords = keywords.split(', ');
-        }
-    },
-    
-    /**
-     * Method: read_cap_Capability
-     */
-    read_cap_Capability: function(capabilities, node) {
-        var capability = {};
-        this.runChildNodes(capability, node);
-        capabilities.capability = capability;
-    },
-    
-    /**
-     * Method: read_cap_Request
-     */
-    read_cap_Request: function(obj, node) {
-        var request = {};
-        this.runChildNodes(request, node);
-        obj.request = request;
-    },
-    
-    /**
-     * Method: read_cap_GetFeature
-     */
-    read_cap_GetFeature: function(request, node) {
-        var getfeature = {
-            href: {}, // DCPType
-            formats: [] // ResultFormat
-        };
-        this.runChildNodes(getfeature, node);
-        request.getfeature = getfeature;
-    },
-    
-    /**
-     * Method: read_cap_ResultFormat
-     */
-    read_cap_ResultFormat: function(obj, node) {
-        var children = node.childNodes;
-        var childNode;
-        for(var i=0; i<children.length; i++) {
-            childNode = children[i];
-            if(childNode.nodeType == 1) {
-                obj.formats.push(childNode.nodeName);
-            }
-        }
-    },
-    
-    /**
-     * Method: read_cap_DCPType
-     */
-    read_cap_DCPType: function(obj, node) {
-        this.runChildNodes(obj, node);
-    },
-    
-    /**
-     * Method: read_cap_HTTP
-     */
-    read_cap_HTTP: function(obj, node) {
-        this.runChildNodes(obj.href, node);
-    },
-    
-    /**
-     * Method: read_cap_Get
-     */
-    read_cap_Get: function(obj, node) {
-        obj.get = node.getAttribute("onlineResource");
-    },
-    
-    /**
-     * Method: read_cap_Post
-     */
-    read_cap_Post: function(obj, node) {
-        obj.post = node.getAttribute("onlineResource");
-    },
-    
-    CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" 
-
-});
-/* ======================================================================
-    OpenLayers/Format/WFSCapabilities/v1_1_0.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/WFSCapabilities/v1.js
- */
-
-/**
- * Class: OpenLayers.Format.WFSCapabilities/v1_1_0
- * Read WFS Capabilities version 1.1.0.
- * 
- * Inherits from:
- *  - <OpenLayers.Format.WFSCapabilities>
- */
-OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class(
-    OpenLayers.Format.WFSCapabilities.v1, {
-    
-    /**
-     * Constructor: OpenLayers.Format.WFSCapabilities.v1_1_0
-     * Create a new parser for WFS capabilities version 1.1.0.
-     *
-     * Parameters:
-     * options - {Object} An optional object whose properties will be set on
-     *     this instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Format.WFSCapabilities.v1.prototype.initialize.apply(
-            this, [options]
-        );
-    },
-
-    CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" 
-
-});
-/* ======================================================================
-    OpenLayers/Format/WKT.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.js
- * @requires OpenLayers/Feature/Vector.js
- */
-
-/**
- * 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
-     *
-     * Parameters:
-     * options - {Object} An optional object whose properties will be set on
-     *           this instance
-     *
+     * moPixel - {Object} MapObject Pixel format
+     * 
      * Returns:
-     * {<OpenLayers.Format.WKT>} A new WKT parser.
+     * {Integer} X value of the MapObject Pixel
      */
-    initialize: function(options) {
-        this.regExes = {
-            'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,
-            'spaces': /\s+/,
-            'parenComma': /\)\s*,\s*\(/,
-            'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/,  // can't use {2} here
-            'trimParens': /^\s*\(?(.*?)\)?\s*$/
-        };
-        OpenLayers.Format.prototype.initialize.apply(this, [options]);
+    getXFromMapObjectPixel: function(moPixel) {
+        return moPixel.x;
     },
 
     /**
-     * Method: read
-     * Deserialize a WKT string and return a vector feature or an
-     * array of vector features.  Supports WKT for POINT, MULTIPOINT,
-     * LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and
-     * GEOMETRYCOLLECTION.
-     *
+     * APIMethod: getYFromMapObjectPixel
+     * 
      * Parameters:
-     * wkt - {String} A WKT string
-     *
+     * moPixel - {Object} MapObject Pixel format
+     * 
      * Returns:
-     * {<OpenLayers.Feature.Vector>|Array} A feature or array of features for
-     * GEOMETRYCOLLECTION WKT.
+     * {Integer} Y value of the MapObject Pixel
      */
-    read: function(wkt) {
-        var features, type, str;
-        var matches = this.regExes.typeStr.exec(wkt);
-        if(matches) {
-            type = matches[1].toLowerCase();
-            str = matches[2];
-            if(this.parse[type]) {
-                features = this.parse[type].apply(this, [str]);
-            }
-            if (this.internalProjection && this.externalProjection) {
-                if (features && 
-                    features.CLASS_NAME == "OpenLayers.Feature.Vector") {
-                    features.geometry.transform(this.externalProjection,
-                                                this.internalProjection);
-                } else if (features &&
-                           type != "geometrycollection" &&
-                           typeof features == "object") {
-                    for (var i=0, len=features.length; i<len; i++) {
-                        var component = features[i];
-                        component.geometry.transform(this.externalProjection,
-                                                     this.internalProjection);
-                    }
-                }
-            }
-        }    
-        return features;
+    getYFromMapObjectPixel: function(moPixel) {
+        return moPixel.y;
     },
 
     /**
-     * Method: write
-     * Serialize a feature or array of features into a WKT string.
-     *
+     * APIMethod: getMapObjectPixelFromXY
+     * 
      * Parameters:
-     * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of
-     *            features
-     *
+     * x - {Integer}
+     * y - {Integer}
+     * 
      * Returns:
-     * {String} The WKT string representation of the input geometries
+     * {Object} MapObject Pixel from x and y parameters
      */
-    write: function(features) {
-        var collection, geometry, type, data, isCollection;
-        if(features.constructor == Array) {
-            collection = features;
-            isCollection = true;
-        } else {
-            collection = [features];
-            isCollection = false;
-        }
-        var pieces = [];
-        if(isCollection) {
-            pieces.push('GEOMETRYCOLLECTION(');
-        }
-        for(var i=0, len=collection.length; i<len; ++i) {
-            if(isCollection && i>0) {
-                pieces.push(',');
-            }
-            geometry = collection[i].geometry;
-            type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
-            if(!this.extract[type]) {
-                return null;
-            }
-            if (this.internalProjection && this.externalProjection) {
-                geometry = geometry.clone();
-                geometry.transform(this.internalProjection, 
-                                   this.externalProjection);
-            }                       
-            data = this.extract[type].apply(this, [geometry]);
-            pieces.push(type.toUpperCase() + '(' + data + ')');
-        }
-        if(isCollection) {
-            pieces.push(')');
-        }
-        return pieces.join('');
+    getMapObjectPixelFromXY: function(x, y) {
+        //the conditional here is to test if we are running the v6 of VE
+        return (typeof VEPixel != 'undefined') ? new VEPixel(x, y)
+                         : new Msn.VE.Pixel(x, y);
     },
-    
-    /**
-     * Object with properties corresponding to the geometry types.
-     * Property values are functions that do the actual data extraction.
-     */
-    extract: {
-        /**
-         * Return a space delimited string of point coordinates.
-         * @param {<OpenLayers.Geometry.Point>} point
-         * @returns {String} A string of coordinates representing the point
-         */
-        'point': function(point) {
-            return point.x + ' ' + point.y;
-        },
 
-        /**
-         * Return a comma delimited string of point coordinates from a multipoint.
-         * @param {<OpenLayers.Geometry.MultiPoint>} multipoint
-         * @returns {String} A string of point coordinate strings representing
-         *                  the multipoint
-         */
-        '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]]) +
-                           ')');
-            }
-            return array.join(',');
-        },
-        
-        /**
-         * Return a comma delimited string of point coordinates from a line.
-         * @param {<OpenLayers.Geometry.LineString>} linestring
-         * @returns {String} A string of point coordinate strings representing
-         *                  the linestring
-         */
-        'linestring': function(linestring) {
-            var array = [];
-            for(var i=0, len=linestring.components.length; i<len; ++i) {
-                array.push(this.extract.point.apply(this, [linestring.components[i]]));
-            }
-            return array.join(',');
-        },
-
-        /**
-         * Return a comma delimited string of linestring strings from a multilinestring.
-         * @param {<OpenLayers.Geometry.MultiLineString>} multilinestring
-         * @returns {String} A string of of linestring strings representing
-         *                  the multilinestring
-         */
-        'multilinestring': function(multilinestring) {
-            var array = [];
-            for(var i=0, len=multilinestring.components.length; i<len; ++i) {
-                array.push('(' +
-                           this.extract.linestring.apply(this, [multilinestring.components[i]]) +
-                           ')');
-            }
-            return array.join(',');
-        },
-        
-        /**
-         * Return a comma delimited string of linear ring arrays from a polygon.
-         * @param {<OpenLayers.Geometry.Polygon>} polygon
-         * @returns {String} An array of linear ring arrays representing the polygon
-         */
-        'polygon': function(polygon) {
-            var array = [];
-            for(var i=0, len=polygon.components.length; i<len; ++i) {
-                array.push('(' +
-                           this.extract.linestring.apply(this, [polygon.components[i]]) +
-                           ')');
-            }
-            return array.join(',');
-        },
-
-        /**
-         * Return an array of polygon arrays from a multipolygon.
-         * @param {<OpenLayers.Geometry.MultiPolygon>} multipolygon
-         * @returns {Array} An array of polygon arrays representing
-         *                  the multipolygon
-         */
-        'multipolygon': function(multipolygon) {
-            var array = [];
-            for(var i=0, len=multipolygon.components.length; i<len; ++i) {
-                array.push('(' +
-                           this.extract.polygon.apply(this, [multipolygon.components[i]]) +
-                           ')');
-            }
-            return array.join(',');
-        }
-
-    },
-
-    /**
-     * Object with properties corresponding to the geometry types.
-     * Property values are functions that do the actual parsing.
-     */
-    parse: {
-        /**
-         * Return point feature given a point WKT fragment.
-         * @param {String} str A WKT fragment representing the point
-         * @returns {<OpenLayers.Feature.Vector>} A point feature
-         * @private
-         */
-        'point': function(str) {
-            var coords = OpenLayers.String.trim(str).split(this.regExes.spaces);
-            return new OpenLayers.Feature.Vector(
-                new OpenLayers.Geometry.Point(coords[0], coords[1])
-            );
-        },
-
-        /**
-         * Return a multipoint feature given a multipoint WKT fragment.
-         * @param {String} A WKT fragment representing the multipoint
-         * @returns {<OpenLayers.Feature.Vector>} A multipoint feature
-         * @private
-         */
-        'multipoint': function(str) {
-            var point;
-            var points = OpenLayers.String.trim(str).split(this.regExes.parenComma);
-            var components = [];
-            for(var i=0, len=points.length; i<len; ++i) {
-                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
-         * @returns {<OpenLayers.Feature.Vector>} A linestring feature
-         * @private
-         */
-        'linestring': function(str) {
-            var points = OpenLayers.String.trim(str).split(',');
-            var components = [];
-            for(var i=0, len=points.length; i<len; ++i) {
-                components.push(this.parse.point.apply(this, [points[i]]).geometry);
-            }
-            return new OpenLayers.Feature.Vector(
-                new OpenLayers.Geometry.LineString(components)
-            );
-        },
-
-        /**
-         * Return a multilinestring feature given a multilinestring WKT fragment.
-         * @param {String} A WKT fragment representing the multilinestring
-         * @returns {<OpenLayers.Feature.Vector>} A multilinestring feature
-         * @private
-         */
-        'multilinestring': function(str) {
-            var line;
-            var lines = OpenLayers.String.trim(str).split(this.regExes.parenComma);
-            var components = [];
-            for(var i=0, len=lines.length; i<len; ++i) {
-                line = lines[i].replace(this.regExes.trimParens, '$1');
-                components.push(this.parse.linestring.apply(this, [line]).geometry);
-            }
-            return new OpenLayers.Feature.Vector(
-                new OpenLayers.Geometry.MultiLineString(components)
-            );
-        },
-        
-        /**
-         * Return a polygon feature given a polygon WKT fragment.
-         * @param {String} A WKT fragment representing the polygon
-         * @returns {<OpenLayers.Feature.Vector>} A polygon feature
-         * @private
-         */
-        'polygon': function(str) {
-            var ring, linestring, linearring;
-            var rings = OpenLayers.String.trim(str).split(this.regExes.parenComma);
-            var components = [];
-            for(var i=0, len=rings.length; i<len; ++i) {
-                ring = rings[i].replace(this.regExes.trimParens, '$1');
-                linestring = this.parse.linestring.apply(this, [ring]).geometry;
-                linearring = new OpenLayers.Geometry.LinearRing(linestring.components);
-                components.push(linearring);
-            }
-            return new OpenLayers.Feature.Vector(
-                new OpenLayers.Geometry.Polygon(components)
-            );
-        },
-
-        /**
-         * Return a multipolygon feature given a multipolygon WKT fragment.
-         * @param {String} A WKT fragment representing the multipolygon
-         * @returns {<OpenLayers.Feature.Vector>} A multipolygon feature
-         * @private
-         */
-        'multipolygon': function(str) {
-            var polygon;
-            var polygons = OpenLayers.String.trim(str).split(this.regExes.doubleParenComma);
-            var components = [];
-            for(var i=0, len=polygons.length; i<len; ++i) {
-                polygon = polygons[i].replace(this.regExes.trimParens, '$1');
-                components.push(this.parse.polygon.apply(this, [polygon]).geometry);
-            }
-            return new OpenLayers.Feature.Vector(
-                new OpenLayers.Geometry.MultiPolygon(components)
-            );
-        },
-
-        /**
-         * Return an array of features given a geometrycollection WKT fragment.
-         * @param {String} A WKT fragment representing the geometrycollection
-         * @returns {Array} An array of OpenLayers.Feature.Vector
-         * @private
-         */
-        'geometrycollection': function(str) {
-            // separate components of the collection with |
-            str = str.replace(/,\s*([A-Za-z])/g, '|$1');
-            var wktArray = OpenLayers.String.trim(str).split('|');
-            var components = [];
-            for(var i=0, len=wktArray.length; i<len; ++i) {
-                components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]]));
-            }
-            return components;
-        }
-
-    },
-
-    CLASS_NAME: "OpenLayers.Format.WKT" 
-});     
+    CLASS_NAME: "OpenLayers.Layer.VirtualEarth"
+});
 /* ======================================================================
     OpenLayers/Layer/Google.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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. */
@@ -30390,6 +11144,7 @@
  * @requires OpenLayers/Layer/SphericalMercator.js
  * @requires OpenLayers/Layer/EventPane.js
  * @requires OpenLayers/Layer/FixedZoomLevels.js
+ * @requires OpenLayers/Lang.js
  */
 
 /**
@@ -31176,1587 +11931,4663 @@
     
 };
 /* ======================================================================
-    OpenLayers/Layer/Grid.js
+    OpenLayers/Format.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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/HTTPRequest.js
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Util.js
  * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
  */
 
 /**
- * Class: OpenLayers.Layer.Grid
- * Base class for layers that use a lattice of tiles.  Create a new grid
- * layer with the <OpenLayers.Layer.Grid> constructor.
- *
- * Inherits from:
- *  - <OpenLayers.Layer.HTTPRequest>
+ * Class: OpenLayers.Format
+ * Base class for format reading/writing a variety of formats.  Subclasses
+ *     of OpenLayers.Format are expected to have read and write methods.
  */
-OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
+OpenLayers.Format = OpenLayers.Class({
     
     /**
-     * APIProperty: tileSize
-     * {<OpenLayers.Size>}
+     * Property: options
+     * {Object} A reference to options passed to the constructor.
      */
-    tileSize: null,
+    options: null,
     
-    /** APIProperty: tileOptions
-     *  {Object} optional configuration options for <OpenLayers.Tile> instances
-     *  created by this Layer, if supported by the tile class.
-     */
-    tileOptions: null,
-    
     /**
-     * Property: grid
-     * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is 
-     *     an array of tiles.
+     * APIProperty: externalProjection
+     * {<OpenLayers.Projection>} When passed a externalProjection and
+     *     internalProjection, the format will reproject the geometries it
+     *     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 
+     *     provided via proj4js or via a custom transformation function. See
+     *     {<OpenLayers.Projection.addTransform>} for more information on
+     *     custom transformations.
      */
-    grid: null,
+    externalProjection: null,
 
     /**
-     * APIProperty: singleTile
-     * {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 
-     *     entire viewport, it is reloaded.
+     * APIProperty: internalProjection
+     * {<OpenLayers.Projection>} When passed a externalProjection and
+     *     internalProjection, the format will reproject the geometries it
+     *     reads or writes. The internalProjection is the projection used by
+     *     the geometries which are returned by read or which are passed into
+     *     write.  In order to reproject, a projection transformation function
+     *     for the 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.
      */
-    singleTile: false,
+    internalProjection: null,
 
-    /** APIProperty: ratio
-     *  {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.
+    /**
+     * APIProperty: data
+     * {Object} When <keepData> is true, this is the parsed string sent to
+     *     <read>.
      */
-    ratio: 1.5,
+    data: null,
 
     /**
-     * APIProperty: buffer
-     * {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.
+     * APIProperty: keepData
+     * {Object} Maintain a reference (<data>) to the most recently read data.
+     *     Default is false.
      */
-    buffer: 2,
+    keepData: false,
 
     /**
-     * APIProperty: numLoadingTiles
-     * {Integer} How many tiles are still loading?
+     * Constructor: OpenLayers.Format
+     * Instances of this class are not useful.  See one of the subclasses.
+     *
+     * Parameters:
+     * options - {Object} An optional object with properties to set on the
+     *           format
+     *
+     * Valid options:
+     * keepData - {Boolean} If true, upon <read>, the data property will be
+     *     set to the parsed object (e.g. the json or xml object).
+     *
+     * Returns:
+     * An instance of OpenLayers.Format
      */
-    numLoadingTiles: 0,
+    initialize: function(options) {
+        OpenLayers.Util.extend(this, options);
+        this.options = options;
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Clean up.
+     */
+    destroy: function() {
+    },
 
     /**
-     * Constructor: OpenLayers.Layer.Grid
-     * Create a new grid layer
+     * Method: read
+     * Read data from a string, and return an object whose type depends on the
+     * subclass. 
+     * 
+     * Parameters:
+     * data - {string} Data to read/parse.
      *
+     * Returns:
+     * Depends on the subclass
+     */
+    read: function(data) {
+        OpenLayers.Console.userError(OpenLayers.i18n("readNotImplemented"));
+    },
+    
+    /**
+     * Method: write
+     * Accept an object, and return a string. 
+     *
      * Parameters:
-     * name - {String}
-     * url - {String}
-     * params - {Object}
-     * options - {Object} Hashtable of extra options to tag onto the layer
+     * object - {Object} Object to be serialized
+     *
+     * Returns:
+     * {String} A string representation of the object.
      */
-    initialize: function(name, url, params, options) {
-        OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this, 
-                                                                arguments);
-        
-        //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
-        //
-        this.events.addEventType("tileloaded");
-
-        this.grid = [];
+    write: function(object) {
+        OpenLayers.Console.userError(OpenLayers.i18n("writeNotImplemented"));
     },
 
+    CLASS_NAME: "OpenLayers.Format"
+});     
+/* ======================================================================
+    OpenLayers/Format/XML.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2011 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.js
+ */
+
+/**
+ * Class: OpenLayers.Format.XML
+ * Read and write XML.  For cross-browser XML generation, use methods on an
+ *     instance of the XML format class instead of on <code>document<end>.
+ *     The DOM creation and traversing methods exposed here all mimic the
+ *     W3C XML DOM methods.  Create a new parser with the
+ *     <OpenLayers.Format.XML> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format>
+ */
+OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
+    
     /**
+     * Property: namespaces
+     * {Object} Mapping of namespace aliases to namespace URIs.  Properties
+     *     of this object should not be set individually.  Read-only.  All
+     *     XML subclasses should have their own namespaces object.  Use
+     *     <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
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
+     */
+    readers: {},
+    
+    /**
+     * Property: writers
+     * As a compliment to the <readers> property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: {},
+
+    /**
+     * Property: xmldom
+     * {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
+     *     object.  It is not intended to be a browser sniffing property.
+     *     Instead, the xmldom property is used instead of <code>document<end>
+     *     where namespaced node creation methods are not supported. In all
+     *     other browsers, this remains null.
+     */
+    xmldom: null,
+
+    /**
+     * Constructor: OpenLayers.Format.XML
+     * Construct an XML parser.  The parser is used to read and write XML.
+     *     Reading XML from a string returns a DOM element.  Writing XML from
+     *     a DOM element returns a string.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on
+     *     the object.
+     */
+    initialize: function(options) {
+        if(window.ActiveXObject) {
+            this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
+        }
+        OpenLayers.Format.prototype.initialize.apply(this, [options]);
+        // clone the namespace object and set all namespace aliases
+        this.namespaces = OpenLayers.Util.extend({}, this.namespaces);
+        this.namespaceAlias = {};
+        for(var alias in this.namespaces) {
+            this.namespaceAlias[this.namespaces[alias]] = alias;
+        }
+    },
+    
+    /**
      * APIMethod: destroy
-     * Deconstruct the layer and clear the grid.
+     * Clean up.
      */
     destroy: function() {
-        this.clearGrid();
-        this.grid = null;
-        this.tileSize = null;
-        OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); 
+        this.xmldom = null;
+        OpenLayers.Format.prototype.destroy.apply(this, arguments);
     },
+    
+    /**
+     * Method: setNamespace
+     * Set a namespace alias and URI for the format.
+     *
+     * Parameters:
+     * alias - {String} The namespace alias (prefix).
+     * uri - {String} The namespace URI.
+     */
+    setNamespace: function(alias, uri) {
+        this.namespaces[alias] = uri;
+        this.namespaceAlias[uri] = alias;
+    },
 
     /**
-     * Method: clearGrid
-     * Go through and remove all tiles from the grid, calling
-     *    destroy() on each of them to kill circular references
+     * APIMethod: read
+     * Deserialize a XML string and return a DOM node.
+     *
+     * Parameters:
+     * text - {String} A XML string
+     
+     * Returns:
+     * {DOMElement} A DOM node
      */
-    clearGrid:function() {
-        if (this.grid) {
-            for(var iRow=0, len=this.grid.length; iRow<len; iRow++) {
-                var row = this.grid[iRow];
-                for(var iCol=0, clen=row.length; iCol<clen; iCol++) {
-                    var tile = row[iCol];
-                    this.removeTileMonitoringHooks(tile);
-                    tile.destroy();
+    read: function(text) {
+        var index = text.indexOf('<');
+        if(index > 0) {
+            text = text.substring(index);
+        }
+        var node = OpenLayers.Util.Try(
+            OpenLayers.Function.bind((
+                function() {
+                    var xmldom;
+                    /**
+                     * Since we want to be able to call this method on the prototype
+                     * itself, this.xmldom may not exist even if in IE.
+                     */
+                    if(window.ActiveXObject && !this.xmldom) {
+                        xmldom = new ActiveXObject("Microsoft.XMLDOM");
+                    } else {
+                        xmldom = this.xmldom;
+                        
+                    }
+                    xmldom.loadXML(text);
+                    return xmldom;
                 }
+            ), this),
+            function() {
+                return new DOMParser().parseFromString(text, 'text/xml');
+            },
+            function() {
+                var req = new XMLHttpRequest();
+                req.open("GET", "data:" + "text/xml" +
+                         ";charset=utf-8," + encodeURIComponent(text), false);
+                if(req.overrideMimeType) {
+                    req.overrideMimeType("text/xml");
+                }
+                req.send(null);
+                return req.responseXML;
             }
-            this.grid = [];
+        );
+
+        if(this.keepData) {
+            this.data = node;
         }
+
+        return node;
     },
 
     /**
-     * APIMethod: clone
-     * Create a clone of this layer
+     * APIMethod: write
+     * Serialize a DOM node into a XML string.
+     * 
+     * Parameters:
+     * node - {DOMElement} A DOM node.
      *
+     * Returns:
+     * {String} The XML string representation of the input node.
+     */
+    write: function(node) {
+        var data;
+        if(this.xmldom) {
+            data = node.xml;
+        } else {
+            var serializer = new XMLSerializer();
+            if (node.nodeType == 1) {
+                // Add nodes to a document before serializing. Everything else
+                // is serialized as is. This may need more work. See #1218 .
+                var doc = document.implementation.createDocument("", "", null);
+                if (doc.importNode) {
+                    node = doc.importNode(node, true);
+                }
+                doc.appendChild(node);
+                data = serializer.serializeToString(doc);
+            } else {
+                data = serializer.serializeToString(node);
+            }
+        }
+        return data;
+    },
+
+    /**
+     * APIMethod: createElementNS
+     * Create a new element with namespace.  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.createElementNS.
+     *
      * Parameters:
-     * obj - {Object} Is this ever used?
+     * uri - {String} Namespace URI for the element.
+     * name - {String} The qualified name of the element (prefix:localname).
      * 
      * Returns:
-     * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
+     * {Element} A DOM element with namespace.
      */
-    clone: function (obj) {
-        
-        if (obj == null) {
-            obj = new OpenLayers.Layer.Grid(this.name,
-                                            this.url,
-                                            this.params,
-                                            this.getOptions());
+    createElementNS: function(uri, name) {
+        var element;
+        if(this.xmldom) {
+            if(typeof uri == "string") {
+                element = this.xmldom.createNode(1, name, uri);
+            } else {
+                element = this.xmldom.createNode(1, name, "");
+            }
+        } else {
+            element = document.createElementNS(uri, name);
         }
+        return element;
+    },
 
-        //get all additions from superclasses
-        obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);
-
-        // copy/set any non-init, non-simple values here
-        if (this.tileSize != null) {
-            obj.tileSize = this.tileSize.clone();
+    /**
+     * APIMethod: createTextNode
+     * 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: 
+     * {DOMElement} A DOM text node.
+     */
+    createTextNode: function(text) {
+        var node;
+        if (typeof text !== "string") {
+            text = String(text);
         }
-        
-        // we do not want to copy reference to grid, so we make a new array
-        obj.grid = [];
+        if(this.xmldom) {
+            node = this.xmldom.createTextNode(text);
+        } else {
+            node = document.createTextNode(text);
+        }
+        return node;
+    },
 
-        return obj;
-    },    
-
     /**
-     * Method: moveTo
-     * This function is called whenever the map is moved. All the moving
-     * of actual 'tiles' is done by the map, but moveTo's role is to accept
-     * a bounds and make sure the data that that bounds requires is pre-loaded.
-     *
+     * APIMethod: getElementsByTagNameNS
+     * Get a list of elements on a node given the namespace URI and local name.
+     *     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:
-     * bounds - {<OpenLayers.Bounds>}
-     * zoomChanged - {Boolean}
-     * dragging - {Boolean}
+     * 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.
      */
-    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();            
-      
-            if (this.singleTile) {
-                
-                // 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 || 
-                     (!dragging && !tilesBounds.containsBounds(bounds))) {
-                    this.initSingleTile(bounds);
+    getElementsByTagNameNS: function(node, uri, name) {
+        var elements = [];
+        if(node.getElementsByTagNameNS) {
+            elements = node.getElementsByTagNameNS(uri, name);
+        } else {
+            // brute force method
+            var allNodes = node.getElementsByTagName("*");
+            var potentialNode, fullName;
+            for(var i=0, len=allNodes.length; i<len; ++i) {
+                potentialNode = allNodes[i];
+                fullName = (potentialNode.prefix) ?
+                           (potentialNode.prefix + ":" + name) : name;
+                if((name == "*") || (fullName == potentialNode.nodeName)) {
+                    if((uri == "*") || (uri == potentialNode.namespaceURI)) {
+                        elements.push(potentialNode);
+                    }
                 }
-            } 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 (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
-                    this.initGriddedTiles(bounds);
-                } else {
-                    //we might have to shift our buffer tiles
-                    this.moveGriddedTiles(bounds);
-                }
             }
         }
+        return elements;
     },
-    
+
     /**
-     * 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).
+     * APIMethod: getAttributeNodeNS
+     * Get an attribute node given the namespace URI and local name.
      * 
      * Parameters:
-     * size - {<OpenLayers.Size>}
+     * 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.
      */
-    setTileSize: function(size) { 
-        if (this.singleTile) {
-            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]);
+    getAttributeNodeNS: function(node, uri, name) {
+        var attributeNode = null;
+        if(node.getAttributeNodeNS) {
+            attributeNode = node.getAttributeNodeNS(uri, name);
+        } else {
+            var attributes = node.attributes;
+            var potentialNode, fullName;
+            for(var i=0, len=attributes.length; i<len; ++i) {
+                potentialNode = attributes[i];
+                if(potentialNode.namespaceURI == uri) {
+                    fullName = (potentialNode.prefix) ?
+                               (potentialNode.prefix + ":" + name) : name;
+                    if(fullName == potentialNode.nodeName) {
+                        attributeNode = potentialNode;
+                        break;
+                    }
+                }
+            }
+        }
+        return attributeNode;
     },
-        
+
     /**
-     * Method: getGridBounds
-     * Deprecated. This function will be removed in 3.0. Please use 
-     *     getTilesBounds() instead.
+     * 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:
-     * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
-     * currently loaded tiles (including those partially or not at all seen 
-     * onscreen)
+     * {String} An attribute value or and empty string if none found.
      */
-    getGridBounds: function() {
-        var msg = "The getGridBounds() function is deprecated. It will be " +
-                  "removed in 3.0. Please use getTilesBounds() instead.";
-        OpenLayers.Console.warn(msg);
-        return this.getTilesBounds();
+    getAttributeNS: function(node, uri, name) {
+        var attributeValue = "";
+        if(node.getAttributeNS) {
+            attributeValue = node.getAttributeNS(uri, name) || "";
+        } else {
+            var attributeNode = this.getAttributeNodeNS(node, uri, name);
+            if(attributeNode) {
+                attributeValue = attributeNode.nodeValue;
+            }
+        }
+        return attributeValue;
     },
+    
+    /**
+     * APIMethod: getChildValue
+     * Get the textual value of the node if it exists, or return an
+     *     optional default string.  Returns an empty string if no first child
+     *     exists and no default value is supplied.
+     *
+     * Parameters:
+     * node - {DOMElement} The element used to look for a first child value.
+     * def - {String} Optional string to return in the event that no
+     *     first child value exists.
+     *
+     * Returns:
+     * {String} The value of the first child of the given node.
+     */
+    getChildValue: function(node, def) {
+        var value = def || "";
+        if(node) {
+            for(var child=node.firstChild; child; child=child.nextSibling) {
+                switch(child.nodeType) {
+                    case 3: // text node
+                    case 4: // cdata section
+                        value += child.nodeValue;
+                }
+            }
+        }
+        return value;
+    },
 
     /**
-     * APIMethod: getTilesBounds
-     * Return the bounds of the tile grid.
+     * APIMethod: concatChildValues
+     * *Deprecated*. Use <getChildValue> instead.
      *
+     * Concatenate the value of all child nodes if any exist, or return an
+     *     optional default string.  Returns an empty string if no children
+     *     exist and no default value is supplied.  Not optimized for large
+     *     numbers of child nodes.
+     *
+     * Parameters:
+     * node - {DOMElement} The element used to look for child values.
+     * def - {String} Optional string to return in the event that no
+     *     child exist.
+     *
      * Returns:
-     * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
-     *     currently loaded tiles (including those partially or not at all seen 
-     *     onscreen).
+     * {String} The concatenated value of all child nodes of the given node.
      */
-    getTilesBounds: function() {    
-        var bounds = null; 
-        
-        if (this.grid.length) {
-            var bottom = this.grid.length - 1;
-            var bottomLeftTile = this.grid[bottom][0];
+    concatChildValues: function(node, def) {
+        var value = "";
+        var child = node.firstChild;
+        var childValue;
+        while(child) {
+            childValue = child.nodeValue;
+            if(childValue) {
+                value += childValue;
+            }
+            child = child.nextSibling;
+        }
+        if(value == "" && def != undefined) {
+            value = def;
+        }
+        return value;
+    },
     
-            var right = this.grid[0].length - 1; 
-            var topRightTile = this.grid[0][right];
+    /**
+     * APIMethod: isSimpleContent
+     * Test if the given node has only simple content (i.e. no child element
+     *     nodes).
+     *
+     * Parameters:
+     * node - {DOMElement} An element node.
+     *
+     * Returns:
+     * {Boolean} The node has no child element nodes (nodes of type 1). 
+     */
+    isSimpleContent: function(node) {
+        var simple = true;
+        for(var child=node.firstChild; child; child=child.nextSibling) {
+            if(child.nodeType === 1) {
+                simple = false;
+                break;
+            }
+        }
+        return simple;
+    },
     
-            bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left, 
-                                           bottomLeftTile.bounds.bottom,
-                                           topRightTile.bounds.right, 
-                                           topRightTile.bounds.top);
+    /**
+     * APIMethod: contentType
+     * Determine the content type for a given node.
+     *
+     * Parameters:
+     * node - {DOMElement}
+     *
+     * Returns:
+     * {Integer} One of OpenLayers.Format.XML.CONTENT_TYPE.{EMPTY,SIMPLE,COMPLEX,MIXED}
+     *     if the node has no, simple, complex, or mixed content.
+     */
+    contentType: function(node) {
+        var simple = false,
+            complex = false;
             
-        }   
-        return bounds;
+        var type = OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;
+
+        for(var child=node.firstChild; child; child=child.nextSibling) {
+            switch(child.nodeType) {
+                case 1: // element
+                    complex = true;
+                    break;
+                case 8: // comment
+                    break;
+                default:
+                    simple = true;
+            }
+            if(complex && simple) {
+                break;
+            }
+        }
+        
+        if(complex && simple) {
+            type = OpenLayers.Format.XML.CONTENT_TYPE.MIXED;
+        } else if(complex) {
+            return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;
+        } else if(simple) {
+            return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE;
+        }
+        return type;
     },
 
     /**
-     * Method: initSingleTile
+     * APIMethod: hasAttributeNS
+     * Determine whether a node has a particular attribute matching the given
+     *     name and namespace.
      * 
-     * Parameters: 
-     * bounds - {<OpenLayers.Bounds>}
+     * 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.
      */
-    initSingleTile: function(bounds) {
-
-        //determine new tile bounds
-        var center = bounds.getCenterLonLat();
-        var tileWidth = bounds.getWidth() * this.ratio;
-        var tileHeight = bounds.getHeight() * this.ratio;
-                                       
-        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);
-
-        if (!this.grid.length) {
-            this.grid[0] = [];
+    hasAttributeNS: function(node, uri, name) {
+        var found = false;
+        if(node.hasAttributeNS) {
+            found = node.hasAttributeNS(uri, name);
+        } else {
+            found = !!this.getAttributeNodeNS(node, uri, name);
         }
-
-        var tile = this.grid[0][0];
-        if (!tile) {
-            tile = this.addTile(tileBounds, px);
-            
-            this.addTileMonitoringHooks(tile);
-            tile.draw();
-            this.grid[0][0] = tile;
+        return found;
+    },
+    
+    /**
+     * APIMethod: setAttributeNS
+     * Adds a new attribute or changes the value of an attribute with the given
+     *     namespace and name.
+     *
+     * Parameters:
+     * node - {Element} Element node on which to set the attribute.
+     * uri - {String} Namespace URI for the attribute.
+     * name - {String} Qualified name (prefix:localname) for the attribute.
+     * value - {String} Attribute value.
+     */
+    setAttributeNS: function(node, uri, name, value) {
+        if(node.setAttributeNS) {
+            node.setAttributeNS(uri, name, value);
         } else {
-            tile.moveTo(tileBounds, px);
-        }           
-        
-        //remove all but our single tile
-        this.removeExcessTiles(1,1);
+            if(this.xmldom) {
+                if(uri) {
+                    var attribute = node.ownerDocument.createNode(
+                        2, name, uri
+                    );
+                    attribute.nodeValue = value;
+                    node.setAttributeNode(attribute);
+                } else {
+                    node.setAttribute(name, value);
+                }
+            } else {
+                throw "setAttributeNS not implemented";
+            }
+        }
     },
 
-    /** 
-     * Method: calculateGridLayout
-     * Generate parameters for the grid layout. This  
+    /**
+     * Method: createElementNSPlus
+     * Shorthand for creating namespaced elements with optional attributes and
+     *     child text nodes.
      *
      * Parameters:
-     * bounds - {<OpenLayers.Bound>}
-     * extent - {<OpenLayers.Bounds>}
-     * resolution - {Number}
+     * name - {String} The qualified node name.
+     * options - {Object} Optional object for node configuration.
      *
+     * Valid options:
+     * uri - {String} Optional namespace uri for the element - supply a prefix
+     *     instead if the namespace uri is a property of the format's namespace
+     *     object.
+     * attributes - {Object} Optional attributes to be set using the
+     *     <setAttributes> method.
+     * value - {String} Optional text to be appended as a text node.
+     *
      * Returns:
-     * Object containing properties tilelon, tilelat, tileoffsetlat,
-     * tileoffsetlat, tileoffsetx, tileoffsety
+     * {Element} An element node.
      */
-    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 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 { 
-          tilelon: tilelon, tilelat: tilelat,
-          tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
-          tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
-        };
+    createElementNSPlus: function(name, options) {
+        options = options || {};
+        // order of prefix preference
+        // 1. in the uri option
+        // 2. in the prefix option
+        // 3. in the qualified name
+        // 4. from the defaultPrefix
+        var uri = options.uri || this.namespaces[options.prefix];
+        if(!uri) {
+            var loc = name.indexOf(":");
+            uri = this.namespaces[name.substring(0, loc)];
+        }
+        if(!uri) {
+            uri = this.namespaces[this.defaultPrefix];
+        }
+        var node = this.createElementNS(uri, name);
+        if(options.attributes) {
+            this.setAttributes(node, options.attributes);
+        }
+        var value = options.value;
+        if(value != null) {
+            node.appendChild(this.createTextNode(value));
+        }
+        return node;
+    },
+    
+    /**
+     * Method: setAttributes
+     * Set multiple attributes given key value pairs from an object.
+     *
+     * Parameters:
+     * node - {Element} An element node.
+     * obj - {Object || Array} An object whose properties represent attribute
+     *     names and values represent attribute values.  If an attribute name
+     *     is a qualified name ("prefix:local"), the prefix will be looked up
+     *     in the parsers {namespaces} object.  If the prefix is found,
+     *     setAttributeNS will be used instead of setAttribute.
+     */
+    setAttributes: function(node, obj) {
+        var value, uri;
+        for(var name in obj) {
+            if(obj[name] != null && obj[name].toString) {
+                value = obj[name].toString();
+                // check for qualified attribute name ("prefix:local")
+                uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null;
+                this.setAttributeNS(node, uri, name, value);
+            }
+        }
+    },
 
+    /**
+     * Method: readNode
+     * Shorthand for applying one of the named readers given the node
+     *     namespace and local name.  Readers take two args (node, obj) and
+     *     generally extend or modify the second.
+     *
+     * Parameters:
+     * node - {DOMElement} The node to be read (required).
+     * obj - {Object} The object to be modified (optional).
+     *
+     * Returns:
+     * {Object} The input object, modified (or a new one if none was provided).
+     */
+    readNode: function(node, obj) {
+        if(!obj) {
+            obj = {};
+        }
+        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["*"];
+            if(reader) {
+                reader.apply(this, [node, obj]);
+            }
+        }
+        return obj;
     },
 
     /**
-     * Method: initGriddedTiles
-     * 
+     * Method: readChildNodes
+     * Shorthand for applying the named readers to all children of a node.
+     *     For each child of type 1 (element), <readSelf> is called.
+     *
      * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
+     * node - {DOMElement} The node to be read (required).
+     * obj - {Object} The object to be modified (optional).
+     *
+     * Returns:
+     * {Object} The input object, modified.
      */
-    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
+    readChildNodes: function(node, obj) {
+        if(!obj) {
+            obj = {};
+        }
+        var children = node.childNodes;
+        var child;
+        for(var i=0, len=children.length; i<len; ++i) {
+            child = children[i];
+            if(child.nodeType == 1) {
+                this.readNode(child, obj);
+            }
+        }
+        return obj;
+    },
 
-        var viewSize = this.map.getSize();
-        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.getMaxExtent();
-        var resolution = this.map.getResolution();
-        
-        var tileLayout = this.calculateGridLayout(bounds, extent, resolution);
+    /**
+     * Method: writeNode
+     * Shorthand for applying one of the named writers and appending the
+     *     results to a node.  If a qualified name is not provided for the
+     *     second argument (and a local name is used instead), the namespace
+     *     of the parent node will be assumed.
+     *
+     * Parameters:
+     * name - {String} The name of a node to generate.  If a qualified name
+     *     (e.g. "pre:Name") is used, the namespace prefix is assumed to be
+     *     in the <writers> group.  If a local name is used (e.g. "Name") then
+     *     the namespace of the parent is assumed.  If a local name is used
+     *     and no parent is supplied, then the default namespace is assumed.
+     * obj - {Object} Structure containing data for the writer.
+     * parent - {DOMElement} Result will be appended to this node.  If no parent
+     *     is supplied, the node will not be appended to anything.
+     *
+     * Returns:
+     * {DOMElement} The child node.
+     */
+    writeNode: function(name, obj, parent) {
+        var prefix, local;
+        var split = name.indexOf(":");
+        if(split > 0) {
+            prefix = name.substring(0, split);
+            local = name.substring(split + 1);
+        } else {
+            if(parent) {
+                prefix = this.namespaceAlias[parent.namespaceURI];
+            } else {
+                prefix = this.defaultPrefix;
+            }
+            local = name;
+        }
+        var child = this.writers[prefix][local].apply(this, [obj]);
+        if(parent) {
+            parent.appendChild(child);
+        }
+        return child;
+    },
 
-        var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us
-        var tileoffsety = Math.round(tileLayout.tileoffsety);
+    /**
+     * APIMethod: getChildEl
+     * Get the first child element.  Optionally only return the first child
+     *     if it matches the given name and namespace URI.
+     *
+     * Parameters:
+     * node - {DOMElement} The parent node.
+     * name - {String} Optional node name (local) to search for.
+     * uri - {String} Optional namespace URI to search for.
+     *
+     * Returns:
+     * {DOMElement} The first child.  Returns null if no element is found, if
+     *     something significant besides an element is found, or if the element
+     *     found does not match the optional name and uri.
+     */
+    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
+     *     if it matches the given local name and namespace URI.
+     *
+     * Parameters:
+     * node - {DOMElement} The node.
+     * name - {String} Optional local name of the sibling to search for.
+     * uri - {String} Optional namespace URI of the sibling to search for.
+     *
+     * Returns:
+     * {DOMElement} The next sibling element.  Returns null if no element is
+     *     found, something significant besides an element is found, or the
+     *     found element does not match the optional name and uri.
+     */
+    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
+     *     sibling with the given local name or namespace URI.
+     *
+     * Parameters:
+     * node - {DOMElement} The node.
+     * name - {String} Optional local name of the sibling to search for.
+     * uri - {String} Optional namespace URI of the sibling to search for.
+     *
+     * Returns:
+     * {DOMElement} The next sibling element.  Returns null if no element is
+     *     found, something significant besides an element is found, or the
+     *     found element does not match the query.
+     */
+    getThisOrNextEl: function(node, name, uri) {
+        outer: for(var sibling=node; sibling; sibling=sibling.nextSibling) {
+            switch(sibling.nodeType) {
+                case 1: // Element
+                    if((!name || name === (sibling.localName || sibling.nodeName.split(":").pop())) &&
+                       (!uri || uri === sibling.namespaceURI)) {
+                        // matches
+                        break outer;
+                    }
+                    sibling = null;
+                    break outer;
+                case 3: // Text
+                    if(/^\s*$/.test(sibling.nodeValue)) {
+                        break;
+                    }
+                case 4: // CDATA
+                case 6: // ENTITY_NODE
+                case 12: // NOTATION_NODE
+                case 10: // DOCUMENT_TYPE_NODE
+                case 11: // DOCUMENT_FRAGMENT_NODE
+                    sibling = null;
+                    break outer;
+            } // ignore comments and processing instructions
+        }
+        return sibling || null;
+    },
+    
+    /**
+     * APIMethod: lookupNamespaceURI
+     * Takes a prefix and returns the namespace URI associated with it on the given
+     *     node if found (and null if not). Supplying null for the prefix will
+     *     return the default namespace.
+     *
+     * For browsers that support it, this calls the native lookupNamesapceURI
+     *     function.  In other browsers, this is an implementation of
+     *     http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
+     *
+     * 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.
+     */
+    lookupNamespaceURI: function(node, prefix) {
+        var uri = null;
+        if(node) {
+            if(node.lookupNamespaceURI) {
+                uri = node.lookupNamespaceURI(prefix);
+            } else {
+                outer: switch(node.nodeType) {
+                    case 1: // ELEMENT_NODE
+                        if(node.namespaceURI !== null && node.prefix === prefix) {
+                            uri = node.namespaceURI;
+                            break outer;
+                        }
+                        var len = node.attributes.length;
+                        if(len) {
+                            var attr;
+                            for(var i=0; i<len; ++i) {
+                                attr = node.attributes[i];
+                                if(attr.prefix === "xmlns" && attr.name === "xmlns:" + prefix) {
+                                    uri = attr.value || null;
+                                    break outer;
+                                } else if(attr.name === "xmlns" && prefix === null) {
+                                    uri = attr.value || null;
+                                    break outer;
+                                }
+                            }
+                        }
+                        uri = this.lookupNamespaceURI(node.parentNode, prefix);
+                        break outer;
+                    case 2: // ATTRIBUTE_NODE
+                        uri = this.lookupNamespaceURI(node.ownerElement, prefix);
+                        break outer;
+                    case 9: // DOCUMENT_NODE
+                        uri = this.lookupNamespaceURI(node.documentElement, prefix);
+                        break outer;
+                    case 6: // ENTITY_NODE
+                    case 12: // NOTATION_NODE
+                    case 10: // DOCUMENT_TYPE_NODE
+                    case 11: // DOCUMENT_FRAGMENT_NODE
+                        break outer;
+                    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);
+                        break outer;
+                }
+            }
+        }
+        return uri;
+    },
+    
+    CLASS_NAME: "OpenLayers.Format.XML" 
 
-        var tileoffsetlon = tileLayout.tileoffsetlon;
-        var tileoffsetlat = tileLayout.tileoffsetlat;
-        
-        var tilelon = tileLayout.tilelon;
-        var tilelat = tileLayout.tilelat;
+});     
 
-        this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
+OpenLayers.Format.XML.CONTENT_TYPE = {EMPTY: 0, SIMPLE: 1, COMPLEX: 2, MIXED: 3};
 
-        var startX = tileoffsetx; 
-        var startLon = tileoffsetlon;
+/**
+ * APIFunction: OpenLayers.Format.XML.lookupNamespaceURI
+ * Takes a prefix and returns the namespace URI associated with it on the given
+ *     node if found (and null if not). Supplying null for the prefix will
+ *     return the default namespace.
+ *
+ * For browsers that support it, this calls the native lookupNamesapceURI
+ *     function.  In other browsers, this is an implementation of
+ *     http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
+ *
+ * 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.
+ */
+OpenLayers.Format.XML.lookupNamespaceURI = OpenLayers.Function.bind(
+    OpenLayers.Format.XML.prototype.lookupNamespaceURI,
+    OpenLayers.Format.XML.prototype
+);
+/* ======================================================================
+    OpenLayers/Format/WFST.js
+   ====================================================================== */
 
-        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) {
-                row = [];
-                this.grid.push(row);
-            }
+/* Copyright (c) 2006-2011 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. */
 
-            tileoffsetlon = startLon;
-            tileoffsetx = startX;
-            var colidx = 0;
- 
-            do {
-                var tileBounds = 
-                    new OpenLayers.Bounds(tileoffsetlon, 
-                                          tileoffsetlat, 
-                                          tileoffsetlon + tilelon,
-                                          tileoffsetlat + tilelat);
+/**
+ * @requires OpenLayers/Format.js
+ */
 
-                var x = tileoffsetx;
-                x -= layerContainerDivLeft;
+/**
+ * Function: OpenLayers.Format.WFST
+ * Used to create a versioned WFS protocol.  Default version is 1.0.0.
+ *
+ * Returns:
+ * {<OpenLayers.Format>} A WFST format of the given version.
+ */
+OpenLayers.Format.WFST = function(options) {
+    options = OpenLayers.Util.applyDefaults(
+        options, OpenLayers.Format.WFST.DEFAULTS
+    );
+    var cls = OpenLayers.Format.WFST["v"+options.version.replace(/\./g, "_")];
+    if(!cls) {
+        throw "Unsupported WFST version: " + options.version;
+    }
+    return new cls(options);
+};
 
-                var y = tileoffsety;
-                y -= layerContainerDivTop;
+/**
+ * Constant: OpenLayers.Format.WFST.DEFAULTS
+ * {Object} Default properties for the WFST format.
+ */
+OpenLayers.Format.WFST.DEFAULTS = {
+    "version": "1.0.0"
+};
+/* ======================================================================
+    OpenLayers/Format/WFST/v1.js
+   ====================================================================== */
 
-                var px = new OpenLayers.Pixel(x, y);
-                var tile = row[colidx++];
-                if (!tile) {
-                    tile = this.addTile(tileBounds, px);
-                    this.addTileMonitoringHooks(tile);
-                    row.push(tile);
-                } else {
-                    tile.moveTo(tileBounds, px, false);
-                }
-     
-                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);
+/* Copyright (c) 2006-2011 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. */
 
-        //now actually draw the tiles
-        this.spiralTileLoad();
-    },
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Format/WFST.js
+ */
 
+/**
+ * Class: OpenLayers.Format.WFST.v1
+ * Superclass for WFST parsers.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WFST.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
+    
     /**
-     * Method: getMaxExtent
-     * Get this layer's maximum extent. (Implemented as a getter for
-     *     potential specific implementations in sub-classes.)
-     *
-     * Returns:
-     * {OpenLayers.Bounds}
+     * Property: namespaces
+     * {Object} Mapping of namespace aliases to namespace URIs.
      */
-    getMaxExtent: function() {
-        return this.maxExtent;
+    namespaces: {
+        xlink: "http://www.w3.org/1999/xlink",
+        xsi: "http://www.w3.org/2001/XMLSchema-instance",
+        wfs: "http://www.opengis.net/wfs",
+        gml: "http://www.opengis.net/gml",
+        ogc: "http://www.opengis.net/ogc"
     },
     
     /**
-     * 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. 
+     * Property: defaultPrefix
      */
-    spiralTileLoad: function() {
-        var tileQueue = [];
- 
-        var directions = ["right", "down", "left", "up"];
+    defaultPrefix: "wfs",
 
-        var iRow = 0;
-        var iCell = -1;
-        var direction = OpenLayers.Util.indexOf(directions, "right");
-        var directionsTried = 0;
-        
-        while( directionsTried < directions.length) {
+    /**
+     * Property: version
+     * {String} WFS version number.
+     */
+    version: null,
 
-            var testRow = iRow;
-            var testCell = iCell;
+    /**
+     * Property: schemaLocation
+     * {String} Schema location for a particular minor version.
+     */
+    schemaLocations: null,
+    
+    /**
+     * APIProperty: srsName
+     * {String} URI for spatial reference system.
+     */
+    srsName: null,
 
-            switch (directions[direction]) {
-                case "right":
-                    testCell++;
-                    break;
-                case "down":
-                    testRow++;
-                    break;
-                case "left":
-                    testCell--;
-                    break;
-                case "up":
-                    testRow--;
-                    break;
-            } 
+    /**
+     * APIProperty: extractAttributes
+     * {Boolean} Extract attributes from GML.  Default is true.
+     */
+    extractAttributes: true,
     
-            // 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;
-                iCell = testCell;
+    /**
+     * 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,
+
+    /**
+     * Property: stateName
+     * {Object} Maps feature states to node names.
+     */
+    stateName: null,
+
+    /**
+     * Constructor: OpenLayers.Format.WFST.v1
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.WFST.v1_0_0> or <OpenLayers.Format.WFST.v1_1_0>
+     *     constructor instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        // set state name mapping
+        this.stateName = {};
+        this.stateName[OpenLayers.State.INSERT] = "wfs:Insert";
+        this.stateName[OpenLayers.State.UPDATE] = "wfs:Update";
+        this.stateName[OpenLayers.State.DELETE] = "wfs:Delete";
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * Method: getSrsName
+     */
+    getSrsName: function(feature, options) {
+        var srsName = options && options.srsName;
+        if(!srsName) {
+            if(feature && feature.layer) {
+                srsName = feature.layer.projection.getCode();
             } else {
-                //need to try to load a tile in a different direction
-                direction = (direction + 1) % 4;
-                directionsTried++;
+                srsName = this.srsName;
             }
-        } 
-        
-        // 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;       
         }
+        return srsName;
     },
 
     /**
-     * APIMethod: addTile
-     * 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.
+     * APIMethod: read
+     * Parse the response from a transaction.  Because WFS is split into
+     *     Transaction requests (create, update, and delete) and GetFeature
+     *     requests (read), this method handles parsing of both types of
+     *     responses.
      *
-     * Parameters
-     * bounds - {<OpenLayers.Bounds>}
-     * position - {<OpenLayers.Pixel>}
+     * Parameters:
+     * data - {String | Document} The WFST document to read
+     * options - {Object} Options for the reader
      *
+     * Valid options properties:
+     * output - {String} either "features" or "object". The default is
+     *     "features", which means that the method will return an array of
+     *     features. If set to "object", an object with a "features" property
+     *     and other properties read by the parser will be returned.
+     *
      * Returns:
-     * {<OpenLayers.Tile>} The added OpenLayers.Tile
+     * {Array | Object} Output depending on the output option.
      */
-    addTile:function(bounds, position) {
-        // Should be implemented by subclasses
+    read: function(data, options) {
+        options = options || {};
+        OpenLayers.Util.applyDefaults(options, {
+            output: "features"
+        });
+        
+        if(typeof data == "string") { 
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        if(data && data.nodeType == 9) {
+            data = data.documentElement;
+        }
+        var obj = {};
+        if(data) {
+            this.readNode(data, obj);
+        }
+        if(obj.features && options.output === "features") {
+            obj = obj.features;
+        }
+        return obj;
     },
     
-    /** 
-     * Method: addTileMonitoringHooks
-     * 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: 
-     * tile - {<OpenLayers.Tile>}
+    /**
+     * Property: readers
+     * Contains public functions, grouped by namespace prefix, that will
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
      */
-    addTileMonitoringHooks: function(tile) {
+    readers: {
+        "wfs": {
+            "FeatureCollection": function(node, obj) {
+                obj.features = [];
+                this.readChildNodes(node, obj);
+            }
+        }
+    },
+    
+    /**
+     * Method: write
+     * Given an array of features, write a WFS transaction.  This assumes
+     *     the features have a state property that determines the operation
+     *     type - insert, update, or delete.
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>)} A list of features.
+     *
+     * Returns:
+     * {String} A serialized WFS transaction.
+     */
+    write: function(features) {
+        var node = this.writeNode("wfs:Transaction", features);
+        var value = this.schemaLocationAttr();
+        if(value) {
+            this.setAttributeNS(
+                node, this.namespaces["xsi"], "xsi:schemaLocation",  value
+            )
+        }
+        return OpenLayers.Format.XML.prototype.write.apply(this, [node]);
+    },
+    
+    /**
+     * Property: writers
+     * As a compliment to the readers property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: {
+        "wfs": {
+            "GetFeature": function(options) {
+                var node = this.createElementNSPlus("wfs:GetFeature", {
+                    attributes: {
+                        service: "WFS",
+                        version: this.version,
+                        outputFormat: options && options.outputFormat,
+                        maxFeatures: options && options.maxFeatures,
+                        "xsi:schemaLocation": this.schemaLocationAttr(options)
+                    }
+                });
+                if (typeof this.featureType == "string") {
+                    this.writeNode("Query", options, node);
+                } else {
+                    for (var i=0,len = this.featureType.length; i<len; i++) { 
+                        options.featureType = this.featureType[i]; 
+                        this.writeNode("Query", options, node); 
+                    } 
+                }
+                return node;
+            },
+            "Transaction": function(features) {
+                var node = this.createElementNSPlus("wfs:Transaction", {
+                    attributes: {
+                        service: "WFS",
+                        version: this.version
+                    }
+                });
+                if(features) {
+                    var name, feature;
+                    for(var i=0, len=features.length; i<len; ++i) {
+                        feature = features[i];
+                        name = this.stateName[feature.state];
+                        if(name) {
+                            this.writeNode(name, feature, node);
+                        }
+                    }
+                }
+                return node;
+            },
+            "Insert": function(feature) {
+                var node = this.createElementNSPlus("wfs:Insert");
+                this.srsName = this.getSrsName(feature);
+                this.writeNode("feature:_typeName", feature, node);
+                return node;
+            },
+            "Update": function(feature) {
+                var node = this.createElementNSPlus("wfs:Update", {
+                    attributes: {
+                        typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
+                            this.featureType
+                    }
+                });
+                if(this.featureNS) {
+                    node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
+                }
+                
+                // add in geometry
+                if (this.geometryName !== null) {
+                    this.srsName = this.getSrsName(feature);
+                    this.writeNode(
+                        "Property", {name: this.geometryName, value: feature.geometry}, node
+                    );
+                }
         
-        tile.onLoadStart = function() {
-            //if that was first tile then trigger a 'loadstart' on the layer
-            if (this.numLoadingTiles == 0) {
-                this.events.triggerEvent("loadstart");
+                // add in attributes
+                for(var key in feature.attributes) {
+                    if(feature.attributes[key] !== undefined) {
+                        this.writeNode(
+                            "Property", {name: key, value: feature.attributes[key]}, node
+                        );
+                    }
+                }
+                
+                // add feature id filter
+                this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
+                    fids: [feature.fid]
+                }), node);
+        
+                return node;
+            },
+            "Property": function(obj) {
+                var node = this.createElementNSPlus("wfs:Property");
+                this.writeNode("Name", obj.name, node);
+                if(obj.value !== null) {
+                    this.writeNode("Value", obj.value, node);
+                }
+                return node;
+            },
+            "Name": function(name) {
+                return this.createElementNSPlus("wfs:Name", {value: name});
+            },
+            "Value": function(obj) {
+                var node;
+                if(obj instanceof OpenLayers.Geometry) {
+                    node = this.createElementNSPlus("wfs:Value");
+                    var geom = this.writeNode("feature:_geometry", obj).firstChild;
+                    node.appendChild(geom);
+                } else {
+                    node = this.createElementNSPlus("wfs:Value", {value: obj});                
+                }
+                return node;
+            },
+            "Delete": function(feature) {
+                var node = this.createElementNSPlus("wfs:Delete", {
+                    attributes: {
+                        typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
+                            this.featureType
+                    }
+                });
+                if(this.featureNS) {
+                    node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
+                }
+                this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
+                    fids: [feature.fid]
+                }), node);
+                return node;
             }
-            this.numLoadingTiles++;
-        };
-        tile.events.register("loadstart", this, tile.onLoadStart);
-      
-        tile.onLoadEnd = function() {
-            this.numLoadingTiles--;
-            this.events.triggerEvent("tileloaded");
-            //if that was the last tile, then trigger a 'loadend' on the layer
-            if (this.numLoadingTiles == 0) {
-                this.events.triggerEvent("loadend");
+        }
+    },
+
+    /**
+     * Method: schemaLocationAttr
+     * Generate the xsi:schemaLocation attribute value.
+     *
+     * Returns:
+     * {String} The xsi:schemaLocation attribute or undefined if none.
+     */
+    schemaLocationAttr: function(options) {
+        options = OpenLayers.Util.extend({
+            featurePrefix: this.featurePrefix,
+            schema: this.schema
+        }, options);
+        var schemaLocations = OpenLayers.Util.extend({}, this.schemaLocations);
+        if(options.schema) {
+            schemaLocations[options.featurePrefix] = options.schema;
+        }
+        var parts = [];
+        var uri;
+        for(var key in schemaLocations) {
+            uri = this.namespaces[key];
+            if(uri) {
+                parts.push(uri + " " + schemaLocations[key]);
             }
-        };
-        tile.events.register("loadend", this, tile.onLoadEnd);
-        tile.events.register("unload", this, tile.onLoadEnd);
+        }
+        var value = parts.join(" ") || undefined;
+        return value;
     },
+    
+    /**
+     * Method: setFilterProperty
+     * Set the property of each spatial filter.
+     *
+     * Parameters:
+     * filter - {<OpenLayers.Filter>}
+     */
+    setFilterProperty: function(filter) {
+        if(filter.filters) {
+            for(var i=0, len=filter.filters.length; i<len; ++i) {
+                this.setFilterProperty(filter.filters[i]);
+            }
+        } else {
+            if(filter instanceof OpenLayers.Filter.Spatial) {
+                // got a spatial filter, set its property
+                filter.property = this.geometryName;
+            }
+        }
+    },
 
+    CLASS_NAME: "OpenLayers.Format.WFST.v1" 
+
+});
+/* ======================================================================
+    OpenLayers/Icon.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2011 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/Class.js
+ */
+
+/**
+ * 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 
+ * 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. 
+ * 
+ */
+OpenLayers.Icon = OpenLayers.Class({
+    
     /** 
-     * Method: removeTileMonitoringHooks
-     * This function takes a tile as input and removes the tile hooks 
-     *     that were added in addTileMonitoringHooks()
+     * Property: url 
+     * {String}  image url
+     */
+    url: null,
+    
+    /** 
+     * Property: size 
+     * {<OpenLayers.Size>} 
+     */
+    size: null,
+
+    /** 
+     * 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) 
+     */
+    calculateOffset: null,    
+    
+    /** 
+     * Property: imageDiv 
+     * {DOMElement} 
+     */
+    imageDiv: null,
+
+    /** 
+     * Property: px 
+     * {<OpenLayers.Pixel>} 
+     */
+    px: null,
+    
+    /** 
+     * Constructor: OpenLayers.Icon
+     * Creates an icon, which is an image tag in a div.  
+     *
+     * url - {String} 
+     * size - {<OpenLayers.Size>} 
+     * offset - {<OpenLayers.Pixel>}
+     * calculateOffset - {Function} 
+     */
+    initialize: function(url, size, offset, calculateOffset) {
+        this.url = url;
+        this.size = (size) ? size : new OpenLayers.Size(20,20);
+        this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2));
+        this.calculateOffset = calculateOffset;
+
+        var id = OpenLayers.Util.createUniqueID("OL_Icon_");
+        this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
+    },
+    
+    /** 
+     * Method: destroy
+     * 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); 
+        this.imageDiv.innerHTML = "";
+        this.imageDiv = null;
+    },
+
+    /** 
+     * Method: clone
      * 
-     * Parameters: 
-     * tile - {<OpenLayers.Tile>}
+     * Returns:
+     * {<OpenLayers.Icon>} A fresh copy of the icon.
      */
-    removeTileMonitoringHooks: function(tile) {
-        tile.unload();
-        tile.events.un({
-            "loadstart": tile.onLoadStart,
-            "loadend": tile.onLoadEnd,
-            "unload": tile.onLoadEnd,
-            scope: this
-        });
+    clone: function() {
+        return new OpenLayers.Icon(this.url, 
+                                   this.size, 
+                                   this.offset, 
+                                   this.calculateOffset);
     },
     
     /**
-     * Method: moveGriddedTiles
+     * Method: setSize
      * 
      * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
+     * size - {<OpenLayers.Size>} 
      */
-    moveGriddedTiles: function(bounds) {
-        var buffer = this.buffer || 1;
-        while (true) {
-            var tlLayer = this.grid[0][0].position;
-            var tlViewPort = 
-                this.map.getViewPortPxFromLayerPx(tlLayer);
-            if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
-                this.shiftColumn(true);
-            } else if (tlViewPort.x < -this.tileSize.w * buffer) {
-                this.shiftColumn(false);
-            } else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
-                this.shiftRow(true);
-            } else if (tlViewPort.y < -this.tileSize.h * buffer) {
-                this.shiftRow(false);
-            } else {
-                break;
-            }
-        };
+    setSize: function(size) {
+        if (size != null) {
+            this.size = size;
+        }
+        this.draw();
     },
-
+    
     /**
-     * Method: shiftRow
-     * Shifty grid work
-     *
+     * Method: setUrl
+     * 
      * Parameters:
-     * prepend - {Boolean} if true, prepend to beginning.
-     *                          if false, then append to end
+     * url - {String} 
      */
-    shiftRow:function(prepend) {
-        var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
-        var grid = this.grid;
-        var modelRow = grid[modelRowIndex];
+    setUrl: function(url) {
+        if (url != null) {
+            this.url = url;
+        }
+        this.draw();
+    },
 
-        var resolution = this.map.getResolution();
-        var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
-        var deltaLat = resolution * -deltaY;
+    /** 
+     * Method: draw
+     * Move the div to the given pixel.
+     * 
+     * Parameters:
+     * 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, 
+                                            "absolute");
+        this.moveTo(px);
+        return this.imageDiv;
+    }, 
 
-        var row = (prepend) ? grid.pop() : grid.shift();
-
-        for (var i=0, len=modelRow.length; i<len; i++) {
-            var modelTile = modelRow[i];
-            var bounds = modelTile.bounds.clone();
-            var position = modelTile.position.clone();
-            bounds.bottom = bounds.bottom + deltaLat;
-            bounds.top = bounds.top + deltaLat;
-            position.y = position.y + deltaY;
-            row[i].moveTo(bounds, position);
+    /** 
+     * Method: erase
+     * Erase the underlying image element.
+     *
+     */
+    erase: function() {
+        if (this.imageDiv != null && this.imageDiv.parentNode != null) {
+            OpenLayers.Element.remove(this.imageDiv);
         }
+    }, 
+    
+    /** 
+     * Method: setOpacity
+     * Change the icon's opacity
+     *
+     * Parameters:
+     * opacity - {float} 
+     */
+    setOpacity: function(opacity) {
+        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, 
+                                            null, null, null, null, opacity);
 
-        if (prepend) {
-            grid.unshift(row);
-        } else {
-            grid.push(row);
-        }
     },
-
+    
     /**
-     * Method: shiftColumn
-     * Shift grid work in the other dimension
+     * Method: moveTo
+     * move icon to passed in px.
      *
      * Parameters:
-     * prepend - {Boolean} if true, prepend to beginning.
-     *                          if false, then append to end
+     * px - {<OpenLayers.Pixel>} 
      */
-    shiftColumn: function(prepend) {
-        var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
-        var resolution = this.map.getResolution();
-        var deltaLon = resolution * deltaX;
+    moveTo: function (px) {
+        //if no px passed in, use stored location
+        if (px != null) {
+            this.px = px;
+        }
 
-        for (var i=0, len=this.grid.length; i<len; i++) {
-            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;
-            bounds.right = bounds.right + deltaLon;
-            position.x = position.x + deltaX;
-
-            var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
-            tile.moveTo(bounds, position);
-            if (prepend) {
-                row.unshift(tile);
+        if (this.imageDiv != null) {
+            if (this.px == null) {
+                this.display(false);
             } else {
-                row.push(tile);
+                if (this.calculateOffset) {
+                    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: function(display) {
+        this.imageDiv.style.display = (display) ? "" : "none"; 
+    },
+    
+
     /**
-     * Method: removeExcessTiles
-     * When the size of the map or the buffer changes, we may need to
-     *     remove some excess rows and columns.
+     * 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));    
+
+        return isDrawn;   
+    },
+
+    CLASS_NAME: "OpenLayers.Icon"
+});
+/* ======================================================================
+    OpenLayers/Marker.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2011 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/Class.js
+ * @requires OpenLayers/Events.js
+ * @requires OpenLayers/Icon.js
+ */
+
+/**
+ * Class: OpenLayers.Marker
+ * 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>.
+ *
+ * Example:
+ * (code)
+ * var markers = new OpenLayers.Layer.Markers( "Markers" );
+ * map.addLayer(markers);
+ *
+ * var size = new OpenLayers.Size(21,25);
+ * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
+ * 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()));
+ *
+ * (end)
+ *
+ * Note that if you pass an icon into the Marker constructor, it will take
+ * that icon and use it. This means that you should not share icons between
+ * markers -- you use them once, but you should clone() for any additional
+ * markers using that same icon.
+ */
+OpenLayers.Marker = OpenLayers.Class({
+    
+    /** 
+     * Property: icon 
+     * {<OpenLayers.Icon>} The icon used by this marker.
+     */
+    icon: null,
+
+    /** 
+     * Property: lonlat 
+     * {<OpenLayers.LonLat>} location of object
+     */
+    lonlat: null,
+    
+    /** 
+     * Property: events 
+     * {<OpenLayers.Events>} the event handler.
+     */
+    events: null,
+    
+    /** 
+     * Property: map 
+     * {<OpenLayers.Map>} the map this marker is attached to
+     */
+    map: null,
+    
+    /** 
+     * Constructor: OpenLayers.Marker
      * 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.
+     * lonlat - {<OpenLayers.LonLat>} the position of this marker
+     * icon - {<OpenLayers.Icon>}  the icon for this marker
      */
-    removeExcessTiles: function(rows, columns) {
+    initialize: function(lonlat, icon) {
+        this.lonlat = lonlat;
         
-        // remove extra rows
-        while (this.grid.length > rows) {
-            var row = this.grid.pop();
-            for (var i=0, l=row.length; i<l; i++) {
-                var tile = row[i];
-                this.removeTileMonitoringHooks(tile);
-                tile.destroy();
-            }
+        var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
+        if (this.icon == null) {
+            this.icon = newIcon;
+        } else {
+            this.icon.url = newIcon.url;
+            this.icon.size = newIcon.size;
+            this.icon.offset = newIcon.offset;
+            this.icon.calculateOffset = newIcon.calculateOffset;
         }
-        
-        // remove extra columns
-        while (this.grid[0].length > columns) {
-            for (var i=0, l=this.grid.length; i<l; i++) {
-                var row = this.grid[i];
-                var tile = row.pop();
-                this.removeTileMonitoringHooks(tile);
-                tile.destroy();
-            }
+        this.events = new OpenLayers.Events(this, this.icon.imageDiv, null);
+    },
+    
+    /**
+     * APIMethod: destroy
+     * 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.)
+     */
+    destroy: function() {
+        // erase any drawn features
+        this.erase();
+
+        this.map = null;
+
+        this.events.destroy();
+        this.events = null;
+
+        if (this.icon != null) {
+            this.icon.destroy();
+            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 
+    * location passed-in
+    */
+    draw: function(px) {
+        return this.icon.draw(px);
+    }, 
 
+    /** 
+    * Method: erase
+    * Erases any drawn elements for this marker.
+    */
+    erase: function() {
+        if (this.icon != null) {
+            this.icon.erase();
+        }
+    }, 
+
     /**
-     * Method: onMapResize
-     * For singleTile layers, this will set a new tile size according to the
-     * dimensions of the map pane.
+    * Method: moveTo
+    * Move the marker to the new location.
+    *
+    * Parameters:
+    * px - {<OpenLayers.Pixel>} the pixel position to move to
+    */
+    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.
      */
-    onMapResize: function() {
-        if (this.singleTile) {
-            this.clearGrid();
-            this.setTileSize();
-        }
+    isDrawn: function() {
+        var isDrawn = (this.icon && this.icon.isDrawn());
+        return isDrawn;   
     },
+
+    /**
+     * Method: onScreen
+     *
+     * Returns:
+     * {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;
+    },
     
     /**
-     * APIMethod: getTileBounds
-     * Returns The tile bounds for a layer given a pixel location.
+     * Method: inflate
+     * Englarges the markers icon by the specified ratio.
      *
      * Parameters:
-     * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport.
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location.
+     * inflate - {float} the ratio to enlarge the marker by (passing 2
+     *                   will double the size).
      */
-    getTileBounds: function(viewPortPx) {
-        var maxExtent = this.maxExtent;
-        var resolution = this.getResolution();
-        var tileMapWidth = resolution * this.tileSize.w;
-        var tileMapHeight = resolution * this.tileSize.h;
-        var mapPoint = this.getLonLatFromViewPortPx(viewPortPx);
-        var tileLeft = maxExtent.left + (tileMapWidth *
-                                         Math.floor((mapPoint.lon -
-                                                     maxExtent.left) /
-                                                    tileMapWidth));
-        var tileBottom = maxExtent.bottom + (tileMapHeight *
-                                             Math.floor((mapPoint.lat -
-                                                         maxExtent.bottom) /
-                                                        tileMapHeight));
-        return new OpenLayers.Bounds(tileLeft, tileBottom,
-                                     tileLeft + tileMapWidth,
-                                     tileBottom + tileMapHeight);
+    inflate: function(inflate) {
+        if (this.icon) {
+            var newSize = new OpenLayers.Size(this.icon.size.w * inflate,
+                                              this.icon.size.h * inflate);
+            this.icon.setSize(newSize);
+        }        
     },
     
-    CLASS_NAME: "OpenLayers.Layer.Grid"
+    /** 
+     * Method: setOpacity
+     * Change the opacity of the marker by changin the opacity of 
+     *   its icon
+     * 
+     * Parameters:
+     * opacity - {float}  Specified as fraction (0.4, etc)
+     */
+    setOpacity: function(opacity) {
+        this.icon.setOpacity(opacity);
+    },
+
+    /**
+     * Method: setUrl
+     * Change URL of the Icon Image.
+     * 
+     * url - {String} 
+     */
+    setUrl: function(url) {
+        this.icon.setUrl(url);
+    },    
+
+    /** 
+     * Method: display
+     * Hide or show the icon
+     * 
+     * display - {Boolean} 
+     */
+    display: function(display) {
+        this.icon.display(display);
+    },
+
+    CLASS_NAME: "OpenLayers.Marker"
 });
+
+
+/**
+ * Function: defaultIcon
+ * Creates a default <OpenLayers.Icon>.
+ * 
+ * Returns:
+ * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
+ */
+OpenLayers.Marker.defaultIcon = function() {
+    var url = OpenLayers.Util.getImagesLocation() + "marker.png";
+    var size = new OpenLayers.Size(21, 25);
+    var calculateOffset = function(size) {
+                    return new OpenLayers.Pixel(-(size.w/2), -size.h);
+                 };
+
+    return new OpenLayers.Icon(url, size, null, calculateOffset);        
+};
+    
+
 /* ======================================================================
-    OpenLayers/Layer/VirtualEarth.js
+    OpenLayers/Popup.js
    ====================================================================== */
 
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for 
+/* Copyright (c) 2006-2011 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
+ * @requires OpenLayers/BaseTypes/Class.js
  */
 
+
 /**
- * Class: OpenLayers.Layer.VirtualEarth
- * 
- * Inherits from:
- *  - <OpenLayers.Layer.EventPane>
- *  - <OpenLayers.Layer.FixedZoomLevels>
+ * 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.  
+ * 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", 
+ *                    new OpenLayers.LonLat(5,40),
+ *                    new OpenLayers.Size(200,200),
+ *                    "example popup",
+ *                    true);
+ *       
+ * map.addPopup(popup);
+ * (end)
  */
-OpenLayers.Layer.VirtualEarth = OpenLayers.Class(
-    OpenLayers.Layer.EventPane,
-    OpenLayers.Layer.FixedZoomLevels, {
+OpenLayers.Popup = OpenLayers.Class({
+
+    /** 
+     * Property: events  
+     * {<OpenLayers.Events>} custom event manager 
+     */
+    events: null,
     
+    /** Property: id
+     * {String} the unique identifier assigned to this popup.
+     */
+    id: "",
+
     /** 
-     * Constant: MIN_ZOOM_LEVEL
-     * {Integer} 1 
+     * Property: lonlat 
+     * {<OpenLayers.LonLat>} the position of this popup on the map
      */
-    MIN_ZOOM_LEVEL: 1,
+    lonlat: null,
+
+    /** 
+     * Property: div 
+     * {DOMElement} the div that contains this popup.
+     */
+    div: null,
+
+    /** 
+     * Property: contentSize 
+     * {<OpenLayers.Size>} the width and height of the content.
+     */
+    contentSize: null,    
+
+    /** 
+     * Property: size 
+     * {<OpenLayers.Size>} the width and height of the popup.
+     */
+    size: null,    
+
+    /** 
+     * Property: contentHTML 
+     * {String} An HTML string for this popup to display.
+     */
+    contentHTML: null,
     
     /** 
-     * Constant: MAX_ZOOM_LEVEL
-     * {Integer} 19
+     * Property: backgroundColor 
+     * {String} the background color used by the popup.
      */
-    MAX_ZOOM_LEVEL: 19,
+    backgroundColor: "",
+    
+    /** 
+     * Property: opacity 
+     * {float} the opacity of this popup (between 0.0 and 1.0)
+     */
+    opacity: "",
 
     /** 
-     * Constant: RESOLUTIONS
-     * {Array(Float)} Hardcode these resolutions so that they are more closely
-     *                tied with the standard wms projection
+     * Property: border 
+     * {String} the border size of the popup.  (eg 2px)
      */
-    RESOLUTIONS: [
-        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.00004291534423828125,
-        0.00002145767211914062, 
-        0.00001072883605957031,
-        0.00000536441802978515
-    ],
+    border: "",
+    
+    /** 
+     * Property: contentDiv 
+     * {DOMElement} a reference to the element that holds the content of
+     *              the div.
+     */
+    contentDiv: null,
+    
+    /** 
+     * Property: groupDiv 
+     * {DOMElement} First and only child of 'div'. The group Div contains the
+     *     'contentDiv' and the 'closeDiv'.
+     */
+    groupDiv: null,
 
-    /**
-     * APIProperty: type
-     * {VEMapType}
+    /** 
+     * Property: closeDiv
+     * {DOMElement} the optional closer image
      */
-    type: null,
+    closeDiv: 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. 
+    /** 
+     * APIProperty: autoSize
+     * {Boolean} Resize the popup to auto-fit the contents.
+     *     Default is false.
      */
-    wrapDateLine: true,
+    autoSize: false,
 
     /**
-     * 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: minSize
+     * {<OpenLayers.Size>} Minimum size allowed for the popup's contents.
      */
-    sphericalMercator: false,
-    
+    minSize: null,
+
     /**
-     * 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.
+     * APIProperty: maxSize
+     * {<OpenLayers.Size>} Maximum size allowed for the popup's contents.
      */
-    animationEnabled: true, 
+    maxSize: null,
 
     /** 
-     * Constructor: OpenLayers.Layer.VirtualEarth
+     * 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 
+     *     padding of the content div inside the popup. This was originally
+     *     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. 
      * 
-     * Parameters:
-     * name - {String}
-     * options - {Object}
+     *     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.
      */
-    initialize: function(name, options) {
-        OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
-        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, 
-                                                                    arguments);
-        if(this.sphericalMercator) {
-            OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
-            this.initMercatorParameters();
+    padding: 0,
+
+    /** 
+     * Property: disableFirefoxOverflowHack
+     * {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.
+     */
+    disableFirefoxOverflowHack: false,
+
+    /**
+     * 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, 
+     *     instead of an <OpenLayers.Bounds> object.
+     */
+    fixPadding: function() {
+        if (typeof this.padding == "number") {
+            this.padding = new OpenLayers.Bounds(
+                this.padding, this.padding, this.padding, this.padding
+            );
         }
     },
+
+    /**
+     * APIProperty: panMapIfOutOfView
+     * {Boolean} When drawn, pan map such that the entire popup is visible in
+     *     the current viewport (if necessary).
+     *     Default is false.
+     */
+    panMapIfOutOfView: false,
     
     /**
-     * Method: loadMapObject
+     * 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.
      */
-    loadMapObject:function() {
+    keepInMap: false,
 
-        // create div and set to same size as map
-        var veDiv = OpenLayers.Util.createDiv(this.name);
-        var sz = this.map.getSize();
-        veDiv.style.width = sz.w + "px";
-        veDiv.style.height = sz.h + "px";
-        this.div.appendChild(veDiv);
+    /**
+     * APIProperty: closeOnMove
+     * {Boolean} When map pans, close the popup.
+     *     Default is false.
+     */
+    closeOnMove: false,
+    
+    /** 
+     * Property: map 
+     * {<OpenLayers.Map>} this gets set in Map.js when the popup is added to the map
+     */
+    map: null,
 
-        try { // crash prevention
-            this.mapObject = new VEMap(this.name);
-        } catch (e) { }
+    /** 
+    * Constructor: OpenLayers.Popup
+    * Create a popup.
+    * 
+    * Parameters: 
+    * id - {String} a unqiue identifier for this popup.  If null is passed
+    *               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   
+    *                                 popup.
+    * closeBox - {Boolean}            Whether to display a close box inside
+    *                                 the popup.
+    * closeBoxCallback - {Function}   Function to be called on closeBox click.
+    */
+    initialize:function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) {
+        if (id == null) {
+            id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+        }
 
-        if (this.mapObject != null) {
-            try { // this is to catch a Mozilla bug without falling apart
+        this.id = id;
+        this.lonlat = lonlat;
 
-                // 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", OpenLayers.Function.True);
-
-            } catch (e) { }
-            this.mapObject.HideDashboard();
-            if(typeof this.mapObject.SetAnimationEnabled == "function") {
-                this.mapObject.SetAnimationEnabled(this.animationEnabled);
-            }
+        this.contentSize = (contentSize != null) ? contentSize 
+                                  : new OpenLayers.Size(
+                                                   OpenLayers.Popup.WIDTH,
+                                                   OpenLayers.Popup.HEIGHT);
+        if (contentHTML != null) { 
+             this.contentHTML = contentHTML;
         }
+        this.backgroundColor = OpenLayers.Popup.COLOR;
+        this.opacity = OpenLayers.Popup.OPACITY;
+        this.border = OpenLayers.Popup.BORDER;
 
-        //can we do smooth panning? this is an unpublished method, so we need 
-        // to be careful
-        if ( !this.mapObject ||
-             !this.mapObject.vemapcontrol ||
-             !this.mapObject.vemapcontrol.PanMap ||
-             (typeof this.mapObject.vemapcontrol.PanMap != "function")) {
+        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, 
+                                                    null, "relative", null,
+                                                    "hidden");
 
-            this.dragPanMapObject = null;
-        }
+        var id = this.div.id + "_contentDiv";
+        this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(), 
+                                                    null, "relative");
+        this.contentDiv.className = this.contentDisplayClass;
+        this.groupDiv.appendChild(this.contentDiv);
+        this.div.appendChild(this.groupDiv);
 
-    },
+        if (closeBox) {
+            this.addCloseBox(closeBoxCallback);
+        } 
 
-    /**
-     * Method: onMapResize
-     */
-    onMapResize: function() {
-        this.mapObject.Resize(this.map.size.w, this.map.size.h);
+        this.registerEvents();
     },
 
     /** 
-     * APIMethod: getWarningHTML
-     * 
-     * Returns: 
-     * {String} String with information on why layer is broken, how to get
-     *          it working.
+     * Method: destroy
+     * nullify references to prevent circular references and memory leaks
      */
-    getWarningHTML:function() {
-        return OpenLayers.i18n(
-            "getLayerWarning", {'layerType':'VE', 'layerLib':'VirtualEarth'}
-        );
+    destroy: function() {
+
+        this.id = null;
+        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); 
+            this.groupDiv.removeChild(this.closeDiv);
+        }
+        this.closeDiv = null;
+        
+        this.div.removeChild(this.groupDiv);
+        this.groupDiv = null;
+
+        if (this.map != null) {
+            this.map.removePopup(this);
+        }
+        this.map = null;
+        this.div = null;
+        
+        this.autoSize = null;
+        this.minSize = null;
+        this.maxSize = null;
+        this.padding = null;
+        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
+    */
+    draw: function(px) {
+        if (px == null) {
+            if ((this.lonlat != null) && (this.map != null)) {
+                px = this.map.getLayerPxFromLonLat(this.lonlat);
+            }
+        }
 
+        // 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.BROWSER_NAME == 'firefox') {
+            this.map.events.register("movestart", this, function() {
+                var style = document.defaultView.getComputedStyle(
+                    this.contentDiv, null
+                );
+                var currentOverflow = style.getPropertyValue("overflow");
+                if (currentOverflow != "hidden") {
+                    this.contentDiv._oldOverflow = currentOverflow;
+                    this.contentDiv.style.overflow = "hidden";
+                }
+            });
+            this.map.events.register("moveend", this, function() {
+                var oldOverflow = this.contentDiv._oldOverflow;
+                if (oldOverflow) {
+                    this.contentDiv.style.overflow = oldOverflow;
+                    this.contentDiv._oldOverflow = null;
+                }
+            });
+        }
 
-    /************************************
-     *                                  *
-     *   MapObject Interface Controls   *
-     *                                  *
-     ************************************/
+        this.moveTo(px);
+        if (!this.autoSize && !this.size) {
+            this.setSize(this.contentSize);
+        }
+        this.setBackgroundColor();
+        this.setOpacity();
+        this.setBorder();
+        this.setContentHTML();
+        
+        if (this.panMapIfOutOfView) {
+            this.panIntoView();
+        }    
 
+        return this.div;
+    },
 
-  // Get&Set Center, Zoom
+    /** 
+     * Method: updatePosition
+     * 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);           
+            }    
+        }
+    },
 
-    /** 
-     * APIMethod: setMapObjectCenter
-     * Set the mapObject to the specified center and zoom
+    /**
+     * Method: moveTo
      * 
      * Parameters:
-     * center - {Object} MapObject LonLat format
-     * zoom - {int} MapObject zoom format
+     * px - {<OpenLayers.Pixel>} the top and left position of the popup div. 
      */
-    setMapObjectCenter: function(center, zoom) {
-        this.mapObject.SetCenterAndZoom(center, zoom); 
+    moveTo: function(px) {
+        if ((px != null) && (this.div != null)) {
+            this.div.style.left = px.x + "px";
+            this.div.style.top = px.y + "px";
+        }
     },
-   
+
     /**
-     * APIMethod: getMapObjectCenter
-     * 
-     * Returns: 
-     * {Object} The mapObject's current center in Map Object format
+     * Method: visible
+     *
+     * Returns:      
+     * {Boolean} Boolean indicating whether or not the popup is visible
      */
-    getMapObjectCenter: function() {
-        return this.mapObject.GetCenter();
+    visible: function() {
+        return OpenLayers.Element.visible(this.div);
     },
 
     /**
-     * APIMethod: dragPanMapObject
-     * 
-     * Parameters:
-     * dX - {Integer}
-     * dY - {Integer}
+     * Method: toggle
+     * Toggles visibility of the popup.
      */
-    dragPanMapObject: function(dX, dY) {
-        this.mapObject.vemapcontrol.PanMap(dX, -dY);
+    toggle: function() {
+        if (this.visible()) {
+            this.hide();
+        } else {
+            this.show();
+        }
     },
 
-    /** 
-     * APIMethod: getMapObjectZoom
-     * 
-     * Returns:
-     * {Integer} The mapObject's current zoom, in Map Object format
+    /**
+     * Method: show
+     * Makes the popup visible.
      */
-    getMapObjectZoom: function() {
-        return this.mapObject.GetZoomLevel();
+    show: function() {
+        OpenLayers.Element.show(this.div);
+
+        if (this.panMapIfOutOfView) {
+            this.panIntoView();
+        }    
     },
 
+    /**
+     * Method: hide
+     * Makes the popup invisible.
+     */
+    hide: function() {
+        OpenLayers.Element.hide(this.div);
+    },
 
-  // LonLat - Pixel Translation
-  
     /**
-     * APIMethod: getMapObjectLonLatFromMapObjectPixel
+     * Method: setSize
+     * Used to adjust the size of the popup. 
+     *
+     * Parameters:
+     * 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". 
+        var contentDivPadding = this.getContentDivPadding();
+        var wPadding = contentDivPadding.left + contentDivPadding.right;
+        var hPadding = contentDivPadding.top + contentDivPadding.bottom;
+
+        // take into account the popup's 'padding' property
+        this.fixPadding();
+        wPadding += this.padding.left + this.padding.right;
+        hPadding += this.padding.top + this.padding.bottom;
+
+        // make extra space for the close div
+        if (this.closeDiv) {
+            var closeDivWidth = parseInt(this.closeDiv.style.width);
+            wPadding += closeDivWidth + contentDivPadding.right;
+        }
+
+        //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 
+        // me want to shoot someone, but so it goes.
+        if (OpenLayers.BROWSER_NAME == "msie") {
+            this.contentSize.w += 
+                contentDivPadding.left + contentDivPadding.right;
+            this.contentSize.h += 
+                contentDivPadding.bottom + contentDivPadding.top;
+        }
+
+        if (this.div != null) {
+            this.div.style.width = this.size.w + "px";
+            this.div.style.height = this.size.h + "px";
+        }
+        if (this.contentDiv != null){
+            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 
+     *     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 + 
+            "</div>";
+ 
+        var containerElement = (this.map) ? this.map.layerContainerDiv
+        								  : document.body;
+        var realSize = OpenLayers.Util.getRenderedDimensions(
+            preparedHTML, null,	{
+                displayClass: this.displayClass,
+                containerElement: containerElement
+            }
+        );
+
+        // is the "real" size of the div is safe to display in our map?
+        var safeSize = this.getSafeContentSize(realSize);
+
+        var newSize = null;
+        if (safeSize.equals(realSize)) {
+            //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 
+            // 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.                
+                newSize = safeSize;
+            } else {
+                //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, {
+                        displayClass: this.contentDisplayClass,
+                        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 
+                // adjust for that.
+                //
+                var currentOverflow = OpenLayers.Element.getStyle(
+                    this.contentDiv, "overflow"
+                );
+                if ( (currentOverflow != "hidden") && 
+                     (clippedSize.equals(safeSize)) ) {
+                    var scrollBar = OpenLayers.Util.getScrollbarWidth();
+                    if (fixedSize.w) {
+                        clippedSize.h += scrollBar;
+                    } else {
+                        clippedSize.w += scrollBar;
+                    }
+                }
+                
+                newSize = this.getSafeContentSize(clippedSize);
+            }
+        }                        
+        this.setSize(newSize);     
+    },    
+
+    /**
+     * Method: setBackgroundColor
+     * Sets the background color of the popup.
+     *
+     * Parameters:
+     * color - {String} the background color.  eg "#FFBBBB"
+     */
+    setBackgroundColor:function(color) { 
+        if (color != undefined) {
+            this.backgroundColor = color; 
+        }
+        
+        if (this.div != null) {
+            this.div.style.backgroundColor = this.backgroundColor;
+        }
+    },  
+    
+    /**
+     * Method: setOpacity
+     * Sets the opacity of the popup.
      * 
      * Parameters:
-     * moPixel - {Object} MapObject Pixel format
-     * 
-     * Returns:
-     * {Object} MapObject LonLat translated from MapObject Pixel
+     * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid).   
      */
-    getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
-        //the conditional here is to test if we are running the v6 of VE
-        return (typeof VEPixel != 'undefined') 
-            ? this.mapObject.PixelToLatLong(moPixel)
-            : this.mapObject.PixelToLatLong(moPixel.x, moPixel.y);
+    setOpacity:function(opacity) { 
+        if (opacity != undefined) {
+            this.opacity = opacity