[fusion-commits] r1357 - sandbox/olcore/lib/OpenLayers

svn_fusion at osgeo.org svn_fusion at osgeo.org
Tue Apr 1 15:16:05 EDT 2008


Author: madair
Date: 2008-04-01 15:16:04 -0400 (Tue, 01 Apr 2008)
New Revision: 1357

Modified:
   sandbox/olcore/lib/OpenLayers/OpenLayers.js
   sandbox/olcore/lib/OpenLayers/OpenLayersCompressed.js
   sandbox/olcore/lib/OpenLayers/OpenLayersUncompressed.js
Log:
re #5: update to OL 2.6 RC1

Modified: sandbox/olcore/lib/OpenLayers/OpenLayers.js
===================================================================
--- sandbox/olcore/lib/OpenLayers/OpenLayers.js	2008-03-31 21:04:04 UTC (rev 1356)
+++ sandbox/olcore/lib/OpenLayers/OpenLayers.js	2008-04-01 19:16:04 UTC (rev 1357)
@@ -182,6 +182,8 @@
             "OpenLayers/Layer/TileCache.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",
@@ -255,6 +257,8 @@
             "OpenLayers/Format/WKT.js",
             "OpenLayers/Format/OSM.js",
             "OpenLayers/Format/SLD.js",
+            "OpenLayers/Format/SLD/v1.js",
+            "OpenLayers/Format/SLD/v1_0_0.js",
             "OpenLayers/Format/Text.js",
             "OpenLayers/Format/JSON.js",
             "OpenLayers/Format/GeoJSON.js",
@@ -1798,7 +1802,7 @@
 };
 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;		
+OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
 
 /** 
  * Constant: DOTS_PER_INCH
@@ -2202,6 +2206,137 @@
     
     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:
+ * 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.
+ * 
+ * Returns:
+ * {OpenLayers.Size}
+ */
+OpenLayers.Util.getRenderedDimensions = function(contentHTML, size) {
+    
+    var w = h = null;
+    
+    // create temp container div with restricted size
+    var container = document.createElement("div");
+    container.style.overflow= "";
+    container.style.position = "absolute";
+    container.style.left = "-9999px";
+        
+    //fix a dimension, if specified.
+    if (size) {
+        if (size.w) {
+            w = container.style.width = size.w;
+        } else if (size.h) {
+            h = container.style.height = size.h;
+        }
+    }
+    
+    // create temp content div and assign content
+    var content = document.createElement("div");
+    content.innerHTML = contentHTML;
+    
+    // add content to restricted container 
+    container.appendChild(content);
+    
+    // append container to body for rendering
+    document.body.appendChild(container);
+    
+    // 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);
+    document.body.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;
+};
 /* ======================================================================
     Rico/Corner.js
    ====================================================================== */
@@ -2971,7 +3106,7 @@
      */
     getStatus: function() {
         try {
-        	return this.transport.status || 0;
+            return this.transport.status || 0;
         } catch (e) {
             return 0;
         }
@@ -4699,6 +4834,15 @@
     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. 
@@ -4860,6 +5004,11 @@
         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 = function() { return(false); }; 
+            }    
             if (this.title != "") {
                 this.div.title = this.title;
             }
@@ -5218,7 +5367,7 @@
                 'Failed to find OpenLayers.Lang.' + parts.join("-") +
                 ' dictionary, falling back to default language'
             );
-            lang = OpenLayers.Lang.defaultCode
+            lang = OpenLayers.Lang.defaultCode;
         }
         
         OpenLayers.Lang.code = lang;
@@ -5362,7 +5511,8 @@
     
     /** 
      * Property: groupDiv 
-     * {DOMElement} the parent of <OpenLayers.Popup.contentDiv> 
+     * {DOMElement} First and only child of 'div'. The group Div contains the
+     *     'contentDiv' and the 'closeDiv'.
      */
     groupDiv: null,
 
@@ -5373,12 +5523,64 @@
     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.
+     */
+    minSize: null,
+
+    /**
+     * APIProperty: maxSize
+     * {<OpenLayers.Size>} Maximum size allowed for the popup's contents.
+     */
+    maxSize: null,
+
+    /** 
      * Property: padding 
-     * {int} the internal padding of the content div.
+     * {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: 5,
+    padding: 0,
 
+    /** 
+     * 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,
+    
     /** 
      * Property: map 
      * {<OpenLayers.Map>} this gets set in Map.js when the popup is added to the map
@@ -5423,38 +5625,22 @@
                                              null, null, null, "hidden");
         this.div.className = 'olPopup';
         
-        this.groupDiv = OpenLayers.Util.createDiv(null, null, null, 
+        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.size.clone(), 
-                                                    null, "relative", null,
-                                                    "hidden");
+                                                    null, "relative");
         this.contentDiv.className = 'olPopupContent';                                            
         this.groupDiv.appendChild(this.contentDiv);
         this.div.appendChild(this.groupDiv);
 
         if (closeBox) {
-           // close icon
-            var closeSize = new OpenLayers.Size(17,17);
-            var img = OpenLayers.Util.getImagesLocation() + "close.gif";
-            this.closeDiv = OpenLayers.Util.createAlphaImageDiv(
-                this.id + "_close", null, closeSize, img
-            );
-            this.closeDiv.style.right = this.padding + "px";
-            this.closeDiv.style.top = this.padding + "px";
-            this.groupDiv.appendChild(this.closeDiv);
+            this.addCloseBox(closeBoxCallback);
+        } 
 
-            var closePopup = closeBoxCallback || function(e) {
-                this.hide();
-                OpenLayers.Event.stop(e);
-            };
-            OpenLayers.Event.observe(this.closeDiv, "click", 
-                    OpenLayers.Function.bindAsEventListener(closePopup, this));
-
-        }
-
         this.registerEvents();
     },
 
@@ -5463,13 +5649,39 @@
      * 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;
+        
+        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.events.destroy();
-        this.events = null;
+        this.map = null;
         this.div = null;
+        
+        this.autoSize = null;
+        this.minSize = null;
+        this.maxSize = null;
+        this.padding = null;
+        this.panMapIfOutOfView = null;
     },
 
     /** 
@@ -5489,12 +5701,39 @@
             }
         }
         
-        this.setSize();
+        //listen to movestart, moveend to disable overflow (FF bug)
+        if (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.setSize(this.size);
+        }
         this.setBackgroundColor();
         this.setOpacity();
         this.setBorder();
         this.setContentHTML();
-        this.moveTo(px);
+        
+        if (this.panMapIfOutOfView) {
+            this.panIntoView();
+        }    
 
         return this.div;
     },
@@ -5541,7 +5780,11 @@
      * Toggles visibility of the popup.
      */
     toggle: function() {
-        OpenLayers.Element.toggle(this.div);
+        if (this.visible()) {
+            this.hide();
+        } else {
+            this.show();
+        }
     },
 
     /**
@@ -5550,6 +5793,10 @@
      */
     show: function() {
         OpenLayers.Element.show(this.div);
+
+        if (this.panMapIfOutOfView) {
+            this.panIntoView();
+        }    
     },
 
     /**
@@ -5565,30 +5812,61 @@
      * Used to adjust the size of the popup. 
      *
      * Parameters:
-     * size - {<OpenLayers.Size>} the new size of the popup in pixels.
+     * size - {<OpenLayers.Size>} the new size of the popup's contents div
+     *     (in pixels).
      */
     setSize:function(size) { 
-        if (size != undefined) {
-            this.size = size; 
+        this.size = size; 
+
+        var contentSize = this.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;
+
+        // 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") {
+            contentSize.w += contentDivPadding.left + contentDivPadding.right;
+            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 = this.size.w + "px";
-            this.contentDiv.style.height = this.size.h + "px";
+            this.contentDiv.style.width = contentSize.w + "px";
+            this.contentDiv.style.height = contentSize.h + "px";
         }
     },  
 
     /**
-    * Method: setBackgroundColor
-    * Sets the background color of the popup.
-    *
-    * Parameters:
-    * color - {String} the background color.  eg "#FFBBBB"
-    */
+     * 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; 
@@ -5649,13 +5927,256 @@
             this.contentHTML = contentHTML;
         }
         
+        if (this.autoSize) {
+
+            // determine actual render dimensions of the contents
+            var realSize = 
+                 OpenLayers.Util.getRenderedDimensions(this.contentHTML);
+
+            // 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(
+                        this.contentHTML, fixedSize
+                    );
+                    
+                    //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);     
+        }        
+
         if (this.contentDiv != null) {
             this.contentDiv.innerHTML = this.contentHTML;
         }    
     },
     
 
+    /**
+     * 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) {
+
+            // Note that there *was* a reference to a
+            // 'OpenLayers.Popup.SCROLL_BAR_WIDTH' constant here, with special
+            // tolerance for it and everything... but it was never defined in
+            // the first place, so I don't know what to think.
+          
+            var maxY = this.map.size.h - 
+                this.map.paddingForPopups.top - 
+                this.map.paddingForPopups.bottom - 
+                hPadding;
     
+            var maxX = this.map.size.w - 
+                this.map.paddingForPopups.left - 
+                this.map.paddingForPopups.right - 
+                wPadding;
+    
+            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. 
+     *
+     *     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>}
+     */
+    getContentDivPadding: function() {
+
+        //use cached value if we have it
+        var contentDivPadding = this._contentDivPadding;
+        if (!contentDivPadding) {
+            //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;
+    
+            //remove the div from the page and make it visible again
+            document.body.removeChild(this.div);
+            this.div.style.display = "";
+        }
+        return contentDivPadding;
+    },
+
+    /**
+     * 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.
@@ -6314,7 +6835,7 @@
      */
     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;
+        return -c/2 * ((--t)*(t-2) - 1) + b;
     },
 
     CLASS_NAME: "OpenLayers.Easing.Quad"
@@ -7965,7 +8486,6 @@
         if (!this.element) {
             this.div.left = "";
             this.div.top = "";
-            this.div.className = this.displayClass;
             this.element = this.div;
         }
         
@@ -9046,7 +9566,6 @@
         OpenLayers.Control.prototype.draw.apply(this, arguments);
           
         if (!this.element) {
-            this.div.className = this.displayClass;
             this.element = document.createElement("a");
             this.element.innerHTML = OpenLayers.i18n("permalink");
             this.element.href="";
@@ -9160,7 +9679,6 @@
         OpenLayers.Control.prototype.draw.apply(this, arguments);
         if (!this.element) {
             this.element = document.createElement("div");
-            this.div.className = this.displayClass;
             this.div.appendChild(this.element);
         }
         this.map.events.register( 'moveend', this, this.updateScale);
@@ -9278,7 +9796,6 @@
     draw: function() {
         OpenLayers.Control.prototype.draw.apply(this, arguments);
         if (!this.eTop) {
-            this.div.className = this.displayClass;
             this.div.style.display = "block";
             this.div.style.position = "absolute";
             
@@ -10441,66 +10958,59 @@
                                            offset: new OpenLayers.Pixel(0,0)};
     },
 
-    /** 
-     * Method: draw
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     * 
-     * Returns: 
-     * {DOMElement} Reference to a div that contains the drawn popup.
+    /**
+     * APIMethod: destroy
      */
-    draw: function(px) {
-        if (px == null) {
-            if ((this.lonlat != null) && (this.map != null)) {
-                px = this.map.getLayerPxFromLonLat(this.lonlat);
-            }
-        }
+    destroy: function() {
+        this.anchor = null;
+        this.relativePosition = null;
         
-        //calculate relative position
-        this.relativePosition = this.calculateRelativePosition(px);
-        
-        return OpenLayers.Popup.prototype.draw.apply(this, arguments);
+        OpenLayers.Popup.prototype.destroy.apply(this, arguments);        
     },
-    
-    /** 
-     * Method: calculateRelativePosition
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     * 
-     * Returns:
-     * {String} The relative position ("br" "tr" "tl "bl") at which the popup
-     *     should be placed.
+
+    /**
+     * 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)
      */
-    calculateRelativePosition:function(px) {
-        var lonlat = this.map.getLonLatFromLayerPx(px);        
-        
-        var extent = this.map.getExtent();
-        var quadrant = extent.determineQuadrant(lonlat);
-        
-        return OpenLayers.Bounds.oppositeQuadrant(quadrant);
-    }, 
+    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.
+     *     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();
+        }
     },
-    
+
     /**
-     * Method: setSize
+     * APIMethod: setSize
      * 
      * Parameters:
      * size - {<OpenLayers.Size>}
@@ -10515,6 +11025,39 @@
     },  
     
     /** 
+     * 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);
+    }, 
+
+    /**
+     * 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:
@@ -10870,9 +11413,9 @@
             node = this.drawGeometryNode(node, geometry);
             
             // append the node to root (but only if it's new)
-	        if (node.parentNode != this.root) { 
-	            this.root.appendChild(node); 
-	        }
+            if (node.parentNode != this.root) { 
+                this.root.appendChild(node); 
+            }
             this.postDraw(node);
         } else {
             node = OpenLayers.Util.getElement(geometry.id);
@@ -13490,7 +14033,7 @@
     layerContainerDiv: null,
 
     /**
-     * Property: layers
+     * APIProperty: layers
      * {Array(<OpenLayers.Layer>)} Ordered list of layers in the map
      */
     layers: null,
@@ -13691,6 +14234,13 @@
     panMethod: OpenLayers.Easing.Expo.easeOut,
     
     /**
+     * Property: paddingForPopups
+     * {<OpenLayers.Bounds>} Outside margin of the popup. Used to prevent 
+     *     the popup from getting too close to the map border.
+     */
+    paddingForPopups : null,
+    
+    /**
      * Constructor: OpenLayers.Map
      * Constructor for a new OpenLayers.Map instance.
      *
@@ -13721,6 +14271,8 @@
                                             OpenLayers.Map.TILE_HEIGHT);
         
         this.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
+        
+        this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);
 
         this.theme = OpenLayers._getScriptLocation() + 
                              'theme/default/style.css'; 
@@ -13862,6 +14414,8 @@
         } else {
             this.events.unregister("resize", this, this.updateSize);
         }    
+        
+        this.paddingForPopups = null;    
 
         if (this.controls != null) {
             for (var i = this.controls.length - 1; i>=0; --i) {
@@ -15724,6 +16278,11 @@
      */
     initialize:function(id, lonlat, size, 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);
     },
 
@@ -15750,17 +16309,12 @@
     },
 
     /**
-     * Method: moveTo
-     * The popup may have been moved to a new relative location, in which case
+     * Method: updateRelativePosition
+     * The popup has been moved to a new relative location, in which case
      *     we will want to re-do the rico corners.
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
      */
-    moveTo: function(px) {
-        OpenLayers.Popup.Anchored.prototype.moveTo.apply(this, arguments);
-        this.setRicoCorners(!this.rounded);
-        this.rounded = true;
+    updateRelativePosition: function() {
+        this.setRicoCorners();
     },
 
     /**
@@ -15771,22 +16325,8 @@
      */
     setSize:function(size) { 
         OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments);
-        
-        if (this.contentDiv != null) {
 
-            var contentSize = this.size.clone();
-            contentSize.h -= (2 * OpenLayers.Popup.AnchoredBubble.CORNER_SIZE);
-            contentSize.h -= (2 * this.padding);
-    
-            this.contentDiv.style.height = contentSize.h + "px";
-            this.contentDiv.style.width  = contentSize.w + "px";
-            
-            if (this.map) {
-                //size has changed - must redo corners        
-                this.setRicoCorners(!this.rounded);
-                this.rounded = true;
-            }    
-        }
+        this.setRicoCorners();
     },  
 
     /**
@@ -15803,7 +16343,7 @@
         if (this.div != null) {
             if (this.contentDiv != null) {
                 this.div.style.background = "transparent";
-                OpenLayers.Rico.Corner.changeColor(this.contentDiv, 
+                OpenLayers.Rico.Corner.changeColor(this.groupDiv, 
                                                    this.backgroundColor);
             }
         }
@@ -15840,11 +16380,8 @@
     /** 
      * Method: setRicoCorners
      * Update RICO corners according to the popup's current relative postion.
-     *  
-     * Parameters:
-     * firstTime - {Boolean} This the first time the corners are being rounded.
      */
-    setRicoCorners:function(firstTime) {
+    setRicoCorners:function() {
     
         var corners = this.getCornersToRound(this.relativePosition);
         var options = {corners: corners,
@@ -15852,8 +16389,9 @@
                        bgColor: "transparent",
                          blend: false};
 
-        if (firstTime) {
+        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
@@ -15889,6 +16427,341 @@
 OpenLayers.Popup.AnchoredBubble.CORNER_SIZE = 5;
 
 /* ======================================================================
+    OpenLayers/Popup/Framed.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Popup/Anchored.js
+ */
+
+/**
+ * Class: OpenLayers.Popup.Framed
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Popup.Anchored>
+ */
+OpenLayers.Popup.Framed =
+  OpenLayers.Class(OpenLayers.Popup.Anchored, {
+
+    /**
+     * Property: imageSrc
+     * {String} location of the image to be used as the popup frame
+     */
+    imageSrc: null,
+
+    /**
+     * Property: imageSize
+     * {<OpenLayers.Size>} Size (measured in pixels) of the image located
+     *     by the 'imageSrc' property.
+     */
+    imageSize: null,
+
+    /**
+     * APIProperty: isAlphaImage
+     * {Boolean} The image has some alpha and thus needs to use the alpha 
+     *     image hack. Note that setting this to true will have no noticeable
+     *     effect in FF or IE7 browsers, but will all but crush the ie6 
+     *     browser. 
+     *     Default is false.
+     */
+    isAlphaImage: false,
+
+    /**
+     * Property: positionBlocks
+     * {Object} Hash of different position blocks (Object/Hashs). Each block 
+     *     will be keyed by a two-character 'relativePosition' 
+     *     code string (ie "tl", "tr", "bl", "br"). Block properties are 
+     *     'offset', 'padding' (self-explanatory), and finally the 'blocks'
+     *     parameter, which is an array of the block objects. 
+     * 
+     *     Each block object must have 'size', 'anchor', and 'position' 
+     *     properties.
+     * 
+     *     Note that positionBlocks should never be modified at runtime.
+     */
+    positionBlocks: null,
+
+    /**
+     * Property: blocks
+     * {Array[Object]} Array of objects, each of which is one "block" of the 
+     *     popup. Each block has a 'div' and an 'image' property, both of 
+     *     which are DOMElements, and the latter of which is appended to the 
+     *     former. These are reused as the popup goes changing positions for
+     *     great economy and elegance.
+     */
+    blocks: null,
+
+    /** 
+     * APIProperty: fixedRelativePosition
+     * {Boolean} We want the framed popup to work dynamically placed relative
+     *     to its anchor but also in just one fixed position. A well designed
+     *     framed popup will have the pixels and logic to display itself in 
+     *     any of the four relative positions, but (understandably), this will
+     *     not be the case for all of them. By setting this property to 'true', 
+     *     framed popup will not recalculate for the best placement each time
+     *     it's open, but will always open the same way. 
+     *     Note that if this is set to true, it is generally advisable to also
+     *     set the 'panIntoView' property to true so that the popup can be 
+     *     scrolled into view (since it will often be offscreen on open)
+     *     Default is false.
+     */
+    fixedRelativePosition: false,
+
+    /** 
+     * Constructor: OpenLayers.Popup.Framed
+     * 
+     * Parameters:
+     * id - {String}
+     * lonlat - {<OpenLayers.LonLat>}
+     * size - {<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, size, contentHTML, anchor, closeBox, 
+                        closeBoxCallback) {
+
+        OpenLayers.Popup.Anchored.prototype.initialize.apply(this, arguments);
+
+        if (this.fixedRelativePosition) {
+            //based on our decided relativePostion, set the current padding
+            // this keeps us from getting into trouble 
+            this.updateRelativePosition();
+            
+            //make calculateRelativePosition always returnt the specified
+            // fiexed position.
+            this.calculateRelativePosition = function(px) {
+                return this.relativePosition;
+            };
+        }
+
+        this.contentDiv.style.position = "absolute";
+        this.contentDiv.style.zIndex = 1;
+
+        if (closeBox) {
+            this.closeDiv.style.zIndex = 1;
+        }
+
+        this.groupDiv.style.position = "absolute";
+        this.groupDiv.style.top = "0px";
+        this.groupDiv.style.left = "0px";
+        this.groupDiv.style.height = "100%";
+        this.groupDiv.style.width = "100%";
+    },
+
+    /** 
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        this.imageSrc = null;
+        this.imageSize = null;
+        this.isAlphaImage = null;
+
+        this.fixedRelativePosition = false;
+        this.positionBlocks = null;
+
+        //remove our blocks
+        for(var i = 0; i < this.blocks.length; i++) {
+            var block = this.blocks[i];
+
+            if (block.image) {
+                block.div.removeChild(block.image);
+            }
+            block.image = null;
+
+            if (block.div) {
+                this.groupDiv.removeChild(block.div);
+            }
+            block.div = null;
+        }
+        this.blocks = null;
+
+        OpenLayers.Popup.Anchored.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
+     * APIMethod: setBackgroundColor
+     */
+    setBackgroundColor:function(color) {
+        //does nothing since the framed popup's entire scheme is based on a 
+        // an image -- changing the background color makes no sense. 
+    },
+
+    /**
+     * APIMethod: setBorder
+     */
+    setBorder:function() {
+        //does nothing since the framed popup's entire scheme is based on a 
+        // an image -- changing the popup's border makes no sense. 
+    },
+
+    /**
+     * Method: setOpacity
+     * Sets the opacity of the popup.
+     * 
+     * Parameters:
+     * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid).   
+     */
+    setOpacity:function(opacity) {
+        //does nothing since we suppose that we'll never apply an opacity
+        // to a framed popup
+    },
+
+    /**
+     * APIMethod: setSize
+     * Overridden here, because we need to update the blocks whenever the size
+     *     of the popup has changed.
+     * 
+     * Parameters:
+     * size - {<OpenLayers.Size>}
+     */
+    setSize:function(size) { 
+        OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments);
+
+        this.updateBlocks();
+    },
+
+    /**
+     * Method: updateRelativePosition
+     * When the relative position changes, we need to set the new padding 
+     *     BBOX on the popup, reposition the close div, and update the blocks.
+     */
+    updateRelativePosition: function() {
+
+        //update the padding
+        this.padding = this.positionBlocks[this.relativePosition].padding;
+
+        //update the position of our close box to new padding
+        if (this.closeDiv) {
+            // 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 + 
+                                        this.padding.right + "px";
+            this.closeDiv.style.top = contentDivPadding.top + 
+                                      this.padding.top + "px";
+        }
+
+        this.updateBlocks();
+    },
+
+    /** 
+     * Method: calculateNewPx
+     * Besides the standard offset as determined by the Anchored class, our 
+     *     Framed popups have a special 'offset' property for each of their 
+     *     positions, which is used to offset the popup relative to its anchor.
+     * 
+     * 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 = OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply(
+            this, arguments
+        );
+
+        newPx = newPx.offset(this.positionBlocks[this.relativePosition].offset);
+
+        return newPx;
+    },
+
+    /**
+     * Method: createBlocks
+     */
+    createBlocks: function() {
+        this.blocks = [];
+
+        var position = this.positionBlocks[this.relativePosition];
+        for (var i = 0; i < position.blocks.length; i++) {
+
+            var block = {};
+            this.blocks.push(block);
+
+            var divId = this.id + '_FrameDecorationDiv_' + i;
+            block.div = OpenLayers.Util.createDiv(divId, 
+                null, null, null, "absolute", null, "hidden", null
+            );
+
+            var imgId = this.id + '_FrameDecorationImg_' + i;
+            var imageCreator = 
+                (this.isAlphaImage) ? OpenLayers.Util.createAlphaImageDiv
+                                    : OpenLayers.Util.createImage;
+
+            block.image = imageCreator(imgId, 
+                null, this.imageSize, this.imageSrc, 
+                "absolute", null, null, null
+            );
+
+            block.div.appendChild(block.image);
+            this.groupDiv.appendChild(block.div);
+        }
+    },
+
+    /**
+     * Method: updateBlocks
+     * Internal method, called on initialize and when the popup's relative
+     *     position has changed. This function takes care of re-positioning
+     *     the popup's blocks in their appropropriate places.
+     */
+    updateBlocks: function() {
+
+        if (!this.blocks) {
+            this.createBlocks();
+        }
+
+        var position = this.positionBlocks[this.relativePosition];
+        for (var i = 0; i < position.blocks.length; i++) {
+
+            var positionBlock = position.blocks[i];
+            var block = this.blocks[i];
+
+            // adjust sizes
+            var l = positionBlock.anchor.left;
+            var b = positionBlock.anchor.bottom;
+            var r = positionBlock.anchor.right;
+            var t = positionBlock.anchor.top;
+
+            //note that we use the isNaN() test here because if the 
+            // size object is initialized with a "auto" parameter, the 
+            // size constructor calls parseFloat() on the string, 
+            // which will turn it into NaN
+            //
+            var w = (isNaN(positionBlock.size.w)) ? this.size.w - (r + l) 
+                                                  : positionBlock.size.w;
+
+            var h = (isNaN(positionBlock.size.h)) ? this.size.h - (b + t) 
+                                                  : positionBlock.size.h;
+
+            block.div.style.width = w + 'px';
+            block.div.style.height = h + 'px';
+
+            block.div.style.left = (l != null) ? l + 'px' : '';
+            block.div.style.bottom = (b != null) ? b + 'px' : '';
+            block.div.style.right = (r != null) ? r + 'px' : '';            
+            block.div.style.top = (t != null) ? t + 'px' : '';
+
+            block.image.style.left = positionBlock.position.x + 'px';
+            block.image.style.top = positionBlock.position.y + 'px';
+        }
+
+        this.contentDiv.style.left = this.padding.left + "px";
+        this.contentDiv.style.top = this.padding.top + "px";
+    },
+
+    CLASS_NAME: "OpenLayers.Popup.Framed"
+});
+/* ======================================================================
     OpenLayers/Renderer/SVG.js
    ====================================================================== */
 
@@ -16631,7 +17504,7 @@
         // stroke 
         if (options.isStroked) { 
             node.setAttribute("strokecolor", style.strokeColor); 
-            node.setAttribute("strokeweight", style.strokeWidth); 
+            node.setAttribute("strokeweight", style.strokeWidth + "px"); 
         } else { 
             node.setAttribute("stroked", "false"); 
         }
@@ -16675,7 +17548,7 @@
         }
         if (strokeColor == "none" &&
                 node.getAttribute("strokecolor") != strokeColor) {
-            node.setAttribute("strokecolor", strokeColor)
+            node.setAttribute("strokecolor", strokeColor);
         }
     },
 
@@ -16728,6 +17601,12 @@
         if (id) {
             node.setAttribute('id', id);
         }
+        
+        // IE hack to make elements unselectable, to prevent 'blue flash'
+        // while dragging vectors; #1410
+        node.setAttribute('unselectable', 'on', 0);
+        node.onselectstart = function() { return(false); };
+        
         return node;    
     },
     
@@ -17362,9 +18241,12 @@
         this.frame.style.display = '';
         // Force a reflow on gecko based browsers to actually show the element
         // before continuing execution.
-        if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) { 
-            this.frame.scrollLeft = this.frame.scrollLeft; 
-        } 
+        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; 
+            } 
+        }
     },
     
     /** 
@@ -17778,7 +18660,7 @@
         // Optionally add min/max buttons if the control will go in the
         // map viewport.
         if(!this.outsideViewport) {
-            this.div.className = this.displayClass + 'Container';
+            this.div.className += " " + this.displayClass + 'Container';
             var imgLocation = OpenLayers.Util.getImagesLocation();
             // maximize button div
             var img = imgLocation + 'layer-switcher-maximize.png';
@@ -18956,7 +19838,7 @@
      * Method: read_wmc_Format
      */
     read_wmc_Format: function(layerInfo, node) {
-        var format = this.getChildValue(node)
+        var format = this.getChildValue(node);
         layerInfo.formats.push(format);
         if(node.getAttribute("current") == "1") {
             layerInfo.params.format = format;
@@ -22138,6 +23020,234 @@
 });
 
 /* ======================================================================
+    OpenLayers/Popup/FramedCloud.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Popup/Framed.js
+ * @requires OpenLayers/Util.js
+ */
+
+/**
+ * Class: OpenLayers.Popup.FramedCloud
+ * 
+ * Inherits from: 
+ *  - <OpenLayers.Popup.Framed>
+ */
+OpenLayers.Popup.FramedCloud = 
+  OpenLayers.Class(OpenLayers.Popup.Framed, {
+
+    /**
+     * APIProperty: autoSize
+     * {Boolean} Framed Cloud is autosizing by default.
+     */
+    autoSize: true,
+
+    /**
+     * APIProperty: panMapIfOutOfView
+     * {Boolean} Framed Cloud does pan into view by default.
+     */
+    panMapIfOutOfView: true,
+
+    /**
+     * APIProperty: imageSize
+     * {<OpenLayers.Size>}
+     */
+    imageSize: new OpenLayers.Size(676, 736),
+
+    /**
+     * APIProperty: isAlphaImage
+     * {Boolean} The FramedCloud does not use an alpha image (in honor of the 
+     *     good ie6 folk out there)
+     */
+    isAlphaImage: false,
+
+    /** 
+     * APIProperty: fixedRelativePosition
+     * {Boolean} The Framed Cloud popup works in just one fixed position.
+     */
+    fixedRelativePosition: false,
+
+    /**
+     * Property: positionBlocks
+     * {Object} Hash of differen position blocks, keyed by relativePosition
+     *     two-character code string (ie "tl", "tr", "bl", "br")
+     */
+    positionBlocks: {
+        "tl": {
+            'offset': new OpenLayers.Pixel(44, 0),
+            'padding': new OpenLayers.Bounds(8, 40, 8, 9),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 51, 22, 0),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 50, 0, 0),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 21),
+                    anchor: new OpenLayers.Bounds(0, 32, 80, null),
+                    position: new OpenLayers.Pixel(0, -629)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 21),
+                    anchor: new OpenLayers.Bounds(null, 32, 0, null),
+                    position: new OpenLayers.Pixel(-638, -629)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 54),
+                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
+                    position: new OpenLayers.Pixel(0, -668)
+                }
+            ]
+        },
+        "tr": {
+            'offset': new OpenLayers.Pixel(-45, 0),
+            'padding': new OpenLayers.Bounds(8, 40, 8, 9),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 51, 22, 0),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 50, 0, 0),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 21),
+                    anchor: new OpenLayers.Bounds(0, 32, 22, null),
+                    position: new OpenLayers.Pixel(0, -629)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 21),
+                    anchor: new OpenLayers.Bounds(null, 32, 0, null),
+                    position: new OpenLayers.Pixel(-638, -629)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 54),
+                    anchor: new OpenLayers.Bounds(0, 0, null, null),
+                    position: new OpenLayers.Pixel(-215, -668)
+                }
+            ]
+        },
+        "bl": {
+            'offset': new OpenLayers.Pixel(45, 0),
+            'padding': new OpenLayers.Bounds(8, 9, 8, 40),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 21, 22, 32),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 21, 0, 32),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 21),
+                    anchor: new OpenLayers.Bounds(0, 0, 22, null),
+                    position: new OpenLayers.Pixel(0, -629)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 21),
+                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
+                    position: new OpenLayers.Pixel(-638, -629)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 54),
+                    anchor: new OpenLayers.Bounds(null, null, 0, 0),
+                    position: new OpenLayers.Pixel(-101, -674)
+                }
+            ]
+        },
+        "br": {
+            'offset': new OpenLayers.Pixel(-44, 0),
+            'padding': new OpenLayers.Bounds(8, 9, 8, 40),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 21, 22, 32),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 21, 0, 32),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 21),
+                    anchor: new OpenLayers.Bounds(0, 0, 22, null),
+                    position: new OpenLayers.Pixel(0, -629)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 21),
+                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
+                    position: new OpenLayers.Pixel(-638, -629)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 54),
+                    anchor: new OpenLayers.Bounds(0, null, null, 0),
+                    position: new OpenLayers.Pixel(-311, -674)
+                }
+            ]
+        }
+    },
+
+    /**
+     * APIProperty: minSize
+     * {<OpenLayers.Size>}
+     */
+    minSize: new OpenLayers.Size(105, 10),
+
+    /**
+     * APIProperty: maxSize
+     * {<OpenLayers.Size>}
+     */
+    maxSize: new OpenLayers.Size(600, 660),
+
+    /** 
+     * Constructor: OpenLayers.Popup.FramedCloud
+     * 
+     * Parameters:
+     * id - {String}
+     * lonlat - {<OpenLayers.LonLat>}
+     * size - {<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, size, contentHTML, anchor, closeBox, 
+                        closeBoxCallback) {
+
+        this.imageSrc = OpenLayers.Util.getImagesLocation() + 'cloud-popup-relative.png';
+        OpenLayers.Popup.Framed.prototype.initialize.apply(this, arguments);
+        this.contentDiv.className = "olFramedCloudPopupContent";
+    },
+
+    /** 
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        OpenLayers.Popup.Framed.prototype.destroy.apply(this, arguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Popup.FramedCloud"
+});
+/* ======================================================================
     OpenLayers/Control/DragFeature.js
    ====================================================================== */
 
@@ -27306,7 +28416,7 @@
           tilelon: tilelon, tilelat: tilelat,
           tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
           tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
-        }  
+        };
 
     },
 
@@ -27533,7 +28643,7 @@
      * tile - {<OpenLayers.Tile>}
      */
     removeTileMonitoringHooks: function(tile) {
-        tile.unload()
+        tile.unload();
         tile.events.un({
             "loadstart": tile.onLoadStart,
             "loadend": tile.onLoadEnd,
@@ -29039,6 +30149,18 @@
     name: null,
     
     /**
+     * Property: title
+     * {String} Title of this style (set if included in SLD)
+     */
+    title: null,
+    
+    /**
+     * Property: description
+     * {String} Description of this style (set if abstract is included in SLD)
+     */
+    description: null,
+
+    /**
      * APIProperty: layerName
      * {<String>} name of the layer that this style belongs to, usually
      * according to the NamedLayer attribute of an SLD document.
@@ -29351,7 +30473,7 @@
         value = (isNaN(value) || !value) ? value : parseFloat(value);
     }
     return value;
-}
+};
     
 /**
  * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES
@@ -29959,7 +31081,7 @@
         originGeometry.move = function(x, y) {
             OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
             geometry.move(x, y);
-        }
+        };
         this.dragHandle = origin;
         this.layer.addFeatures([this.dragHandle], {silent: true});
     },
@@ -29999,7 +31121,7 @@
                 var l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1));
                 geometry.resize(l1 / l0, originGeometry);
             }
-        }
+        };
         this.radiusHandle = radius;
         this.layer.addFeatures([this.radiusHandle], {silent: true});
     },
@@ -30671,7 +31793,7 @@
           tilelon: tilelon, tilelat: tilelat,
           tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
           tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
-        }  
+        };
     },    
 
     /**
@@ -31065,7 +32187,7 @@
           tilelon: tilelon, tilelat: tilelat,
           tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
           tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
-        }  
+        };
     },
     
     CLASS_NAME: "OpenLayers.Layer.MapGuide"
@@ -31980,12 +33102,30 @@
 OpenLayers.Rule = OpenLayers.Class({
     
     /**
+     * Property: id
+     * {String} A unique id for this session.
+     */
+    id: null,
+    
+    /**
      * APIProperty: name
      * {String} name of this rule
      */
     name: 'default',
     
     /**
+     * Property: title
+     * {String} Title of this rule (set if included in SLD)
+     */
+    title: null,
+    
+    /**
+     * Property: description
+     * {String} Description of this rule (set if abstract is included in SLD)
+     */
+    description: null,
+
+    /**
      * Property: context
      * {Object} An optional object with properties that the rule should be
      * evaluatad against. If no context is specified, feature.attributes will
@@ -32038,6 +33178,7 @@
      * {<OpenLayers.Rule>}
      */
     initialize: function(options) {
+        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
         this.symbolizer = {};
 
         OpenLayers.Util.extend(this, options);
@@ -33805,9 +34946,9 @@
             
             case OpenLayers.Rule.Comparison.BETWEEN:
                 var result =
-                        context[this.property] > this.lowerBoundary;
+                        context[this.property] >= this.lowerBoundary;
                 result = result &&
-                        context[this.property] < this.upperBoundary;
+                        context[this.property] <= this.upperBoundary;
                 return result;
             case OpenLayers.Rule.Comparison.LIKE:
                 var regexp = new RegExp(this.value,
@@ -33862,6 +35003,41 @@
     },
     
     /**
+     * Method: regex2value
+     * Convert the value of this rule from a regular expression string into an
+     *     ogc literal string using a wildCard of *, a singleChar of ., and an
+     *     escape of !.  Leaves the <value> property unmodified.
+     * 
+     * Returns:
+     * {String} A string value.
+     */
+    regex2value: function() {
+        
+        var value = this.value;
+        
+        // replace ! with !!
+        value = value.replace(/!/g, "!!");
+
+        // replace \. with !. (watching out for \\.)
+        value = value.replace(/(\\)?\\\./g, function($0, $1) {
+            return $1 ? $0 : "!.";
+        });
+        
+        // replace \* with #* (watching out for \\*)
+        value = value.replace(/(\\)?\\\*/g, function($0, $1) {
+            return $1 ? $0 : "!*";
+        });
+        
+        // replace \\ with \
+        value = value.replace(/\\\\/g, "\\");
+
+        // convert .* to * (the sequence #.* is not allowed)
+        value = value.replace(/\.\*/g, "*");
+        
+        return value;
+    },
+
+    /**
      * Function: binaryCompare
      * Compares a feature property to a rule value
      * 
@@ -34110,60 +35286,24 @@
 OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML, {
     
     /**
-     * APIProperty: sldns
-     * Namespace used for sld.
+     * APIProperty: defaultVersion
+     * {String} Version number to assume if none found.  Default is "1.0.0".
      */
-    sldns: "http://www.opengis.net/sld",
+    defaultVersion: "1.0.0",
     
     /**
-     * APIProperty: ogcns
-     * Namespace used for ogc.
+     * APIProperty: version
+     * {String} Specify a version string if one is known.
      */
-    ogcns: "http://www.opengis.net/ogc",
+    version: null,
     
     /**
-     * APIProperty: gmlns
-     * Namespace used for gml.
+     * Property: parser
+     * {Object} Instance of the versioned parser.  Cached for multiple read and
+     *     write calls of the same version.
      */
-    gmlns: "http://www.opengis.net/gml",
-    
-    /**
-     * APIProperty: defaultStyle.
-     * {Object}
-     * A simple style, preset with the SLD defaults.
-     */
-    defaultStyle: {
-            fillColor: "#808080",
-            fillOpacity: 1,
-            strokeColor: "#000000",
-            strokeOpacity: 1,
-            strokeWidth: 1,
-            pointRadius: 6
-    },
-    
-    /**
-     * Property: withNamedLayer
-     * {Boolean} Option set during <read>.  Default is false.  If true, the
-     *     return from <read> will be a two item array ([styles, namedLayer]): 
-     *         - styles - {Array(<OpenLayers.Style>)}
-     *         - namedLayer - {Object} hash of userStyles, keyed by
-     *             sld:NamedLayer/Name, each again keyed by 
-     *             sld:UserStyle/Name. Each entry of namedLayer is a
-     *             StyleMap for a layer, with the userStyle names as style
-     *             keys.
-     */
-    withNamedLayer: false,
-     
-    /**
-     * APIProperty: overrideDefaultStyleKey
-     * {Boolean} Store styles with key of "default" instead of user style name.
-     *     If true, userStyles with sld:IsDefault==1 will be stored with
-     *     key "default" instead of the sld:UserStyle/Name in the style map.
-     *     Default is true.
-     */
-    overrideDefaultStyleKey: true,
+    parser: null,
 
-
     /**
      * Constructor: OpenLayers.Format.SLD
      * Create a new parser for SLD.
@@ -34177,517 +35317,68 @@
     },
 
     /**
-     * APIMethod: read
-     * Read data from a string, and return a list of features. 
-     * 
-     * Parameters:
-     * data - {String} or {XMLNode} data to read/parse.
-     * options - {Object} Object that sets optional read configuration values.
-     *     These include <withNamedLayer>, and <overrideDefaultStyleKey>.
+     * APIMethod: write
+     * Write a SLD document given a list of styles.
      *
-     * Returns:
-     * {Array(<OpenLayers.Style>)} List of styles.  If <withNamedLayer> is
-     *     true, return will be a two item array where the first item is
-     *     a list of styles and the second is the namedLayer object.
-     */
-    read: function(data, options) {
-        if (typeof data == "string") { 
-            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
-        }
-        
-        options = options || {};
-        OpenLayers.Util.applyDefaults(options, {
-            withNamedLayer: false,
-            overrideDefaultStyleKey: true
-        });
-        
-        var userStyles = this.getElementsByTagNameNS(
-            data, this.sldns, "UserStyle"
-        );
-        var result = {};
-        if (userStyles.length > 0) {
-            var namedLayer = {};
-            var styles = new Array(userStyles.length);
-            var styleName, userStyle, style;
-            for (var i=0; i<userStyles.length; i++) {
-                userStyle = userStyles[i];
-                styleName = this.parseProperty(
-                    userStyle, this.sldns, "Name"
-                );
-                style = this.parseUserStyle(userStyle, styleName);
-    
-                if (options.overrideDefaultStyleKey && style.isDefault == true) {
-                    styleName = "default";
-                }
-    
-                if (!namedLayer[style.layerName]) {
-                    namedLayer[style.layerName] = {};
-                }
-                namedLayer[style.layerName][styleName] = style;
-                styles[i] = style;
-            }
-            result = options.withNamedLayer ? [styles, namedLayer] : styles;
-        }
-        return result;
-    },
-
-    /**
-     * Method: parseUserStyle
-     * parses a sld userStyle for rules
-     * 
      * Parameters:
-     * xmlNode - {DOMElement} xml node to read the style from
-     * name - {String} name of the style
-     * 
-     * Returns:
-     * {<OpenLayers.Style>}
-     */
-    parseUserStyle: function(xmlNode, name) {
-        var userStyle = new OpenLayers.Style(this.defaultStyle, {name: name});
-        
-        userStyle.isDefault = (
-            this.parseProperty(xmlNode, this.sldns, "IsDefault") == 1
-        );
-        
-        // get the name of the layer if we have a NamedLayer
-        var namedLayerNode = xmlNode.parentNode;
-        var nameNodes = this.getElementsByTagNameNS(
-            namedLayerNode, this.sldns, "Name"
-        );
-        if (namedLayerNode.nodeName.indexOf("NamedLayer") != -1 &&
-                nameNodes &&
-                nameNodes.length > 0 &&
-                nameNodes[0].parentNode == namedLayerNode) {
-            userStyle.layerName = this.getChildValue(nameNodes[0]);
-        }
-         
-        var ruleNodes = this.getElementsByTagNameNS(
-            xmlNode, this.sldns, "Rule"
-        );
-
-        if (ruleNodes.length > 0) {
-            var rules = userStyle.rules;
-            var ruleName;
-            for (var i=0; i<ruleNodes.length; i++) {
-                ruleName = this.parseProperty(ruleNodes[i], this.sldns, "Name");
-                rules.push(this.parseRule(ruleNodes[i], ruleName));
-            }
-        }
-
-        return userStyle;
-    },        
-    
-    /**
-     * Method: parseRule
-     * This function is the core of the SLD parsing code in OpenLayers.
-     *     It creates the rule with its constraints and symbolizers.
+     * sld - {Object} An object representing the SLD.
+     * options - {Object} Optional configuration object.
      *
-     * Parameters:
-     * xmlNode - {<DOMElement>}
-     * 
      * Returns:
-     * {Object} Hash of rule properties
+     * {String} An SLD document string.
      */
-    parseRule: function(xmlNode, name) {
-
-        // FILTERS
-        
-        var filter = this.getElementsByTagNameNS(xmlNode, this.ogcns, "Filter");
-        if (filter && filter.length > 0) {
-            var rule = this.parseFilter(filter[0]);
-        } else {
-            // start with an empty rule that always applies
-            var rule = new OpenLayers.Rule();
-            // and check if the rule is an ElseFilter
-            var elseFilter = this.getElementsByTagNameNS(xmlNode, this.ogcns,
-                "ElseFilter");
-            if (elseFilter && elseFilter.length > 0) {
-                rule.elseFilter = true;
+    write: function(sld, options) {
+        var version = (options && options.version) ||
+                      this.version || this.defaultVersion;
+        if(!this.parser || this.parser.VERSION != version) {
+            var format = OpenLayers.Format.SLD[
+                "v" + version.replace(/\./g, "_")
+            ];
+            if(!format) {
+                throw "Can't find a SLD parser for version " +
+                      version;
             }
+            this.parser = new format(this.options);
         }
-        
-        rule.name = name;
-        
-        // SCALE DENOMINATORS
-        
-        // MinScaleDenominator
-        var minScale = this.getElementsByTagNameNS(
-            xmlNode, this.sldns, "MinScaleDenominator"
-        );
-        if (minScale && minScale.length > 0) {
-            rule.minScaleDenominator = 
-                parseFloat(this.getChildValue(minScale[0]));
-        }
-        
-        // MaxScaleDenominator
-        var maxScale = this.getElementsByTagNameNS(
-            xmlNode, this.sldns, "MaxScaleDenominator"
-        );
-        if (maxScale && maxScale.length > 0) {
-            rule.maxScaleDenominator =
-                parseFloat(this.getChildValue(maxScale[0]));
-        }
-        
-        // STYLES
-        
-        // walk through all symbolizers
-        var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;
-        for (var s=0; s<prefixes.length; s++) {
-            
-            // symbolizer type
-            var symbolizer = this.getElementsByTagNameNS(
-                xmlNode, this.sldns, prefixes[s]+"Symbolizer"
-            );
-            
-            if (symbolizer && symbolizer.length > 0) {
-            
-                var style = {};
-            
-                // externalGraphic
-                var graphic = this.getElementsByTagNameNS(
-                    symbolizer[0], this.sldns, "Graphic"
-                );
-                if (graphic && graphic.length > 0) {
-                    style.externalGraphic = this.parseProperty(
-                        graphic[0], this.sldns, "OnlineResource", "xlink:href"
-                    );
-                    style.pointRadius = this.parseProperty(
-                        graphic[0], this.sldns, "Size"
-                    );
-                    style.graphicOpacity = this.parseProperty(
-                        graphic[0], this.sldns, "Opacity"
-                    );
-                }
-                
-                // fill
-                var fill = this.getElementsByTagNameNS(
-                    symbolizer[0], this.sldns, "Fill"
-                );
-                if (fill && fill.length > 0) {
-                    style.fillColor = this.parseProperty(
-                        fill[0], this.sldns, "CssParameter", "name", "fill"
-                    );
-                    style.fillOpacity = this.parseProperty(
-                        fill[0], this.sldns, "CssParameter",
-                        "name", "fill-opacity"
-                    ) || 1;
-                }
-            
-                // stroke
-                var stroke = this.getElementsByTagNameNS(
-                    symbolizer[0], this.sldns, "Stroke"
-                );
-                if (stroke && stroke.length > 0) {
-                    style.strokeColor = this.parseProperty(
-                        stroke[0], this.sldns, "CssParameter", "name", "stroke"
-                    );
-                    style.strokeOpacity = this.parseProperty(
-                        stroke[0], this.sldns, "CssParameter",
-                        "name", "stroke-opacity"
-                    ) || 1;
-                    style.strokeWidth = this.parseProperty(
-                        stroke[0], this.sldns, "CssParameter",
-                        "name", "stroke-width"
-                    );
-                    style.strokeLinecap = this.parseProperty(
-                        stroke[0], this.sldns, "CssParameter",
-                        "name", "stroke-linecap"
-                    );
-                }
-                
-                // set the [point|line|polygon]Symbolizer property of the rule
-                rule.symbolizer[prefixes[s]] = style;
-            }
-        }
-
-        return rule;
+        var root = this.parser.write(sld);
+        return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
     },
     
     /**
-     * Method: parseFilter
-     * Parses ogc fiters.
+     * APIMethod: read
+     * Read and SLD doc and return an object representing the SLD.
      *
      * Parameters:
-     * xmlNode - {<DOMElement>}
-     * 
-     * Returns:
-     * {<OpenLayers.Rule>} rule representing the filter
-     */
-    parseFilter: function(xmlNode) {
-        // ogc:FeatureId filter
-        var filter = this.getNodeOrChildrenByTagName(xmlNode, "FeatureId");
-        if (filter) {
-            var rule = new OpenLayers.Rule.FeatureId();
-            for (var i=0; i<filter.length; i++) {
-                rule.fids.push(filter[i].getAttribute("fid"));
-            }
-            return rule;
-        }
-        
-        // ogc:And filter
-        filter = this.getNodeOrChildrenByTagName(xmlNode, "And");
-        if (filter) {
-            var rule = new OpenLayers.Rule.Logical(
-                    {type: OpenLayers.Rule.Logical.AND});
-            var filters = filter[0].childNodes; 
-            for (var i=0; i<filters.length; i++) {
-                if (filters[i].nodeType == 1) {
-                    rule.rules.push(this.parseFilter(filters[i]));
-                }
-            }
-            return rule;
-        }
-
-        // ogc:Or filter
-        filter = this.getNodeOrChildrenByTagName(xmlNode, "Or");
-        if (filter) {
-            var rule = new OpenLayers.Rule.Logical(
-                    {type: OpenLayers.Rule.Logical.OR})
-            var filters = filter[0].childNodes; 
-            for (var i=0; i<filters.length; i++) {
-                if (filters[i].nodeType == 1) {
-                    rule.rules.push(this.parseFilter(filters[i]));
-                }
-            }
-            return rule;
-        }
-
-        // ogc:Not filter
-        filter = this.getNodeOrChildrenByTagName(xmlNode, "Not");
-        if (filter) {
-            var rule = new OpenLayers.Rule.Logical(
-                    {type: OpenLayers.Rule.Logical.NOT});
-            var filters = filter[0].childNodes; 
-            for (var i=0; i<filters.length; i++) {
-                if (filters[i].nodeType == 1) {
-                    rule.rules.push(this.parseFilter(filters[i]));
-                }
-            }
-            return rule;
-        }
-        
-        // Comparison filters
-        for (var type in this.TYPES) {
-            var filter = this.getNodeOrChildrenByTagName(xmlNode, type);
-            if (filter) {
-                filter = filter[0];
-                var rule = new OpenLayers.Rule.Comparison({
-                        type: OpenLayers.Rule.Comparison[this.TYPES[type]],
-                        property: this.parseProperty(
-                                filter, this.ogcns, "PropertyName")});
-                // ogc:PropertyIsBetween
-                if (this.TYPES[type] == "BETWEEN") {
-                    rule.lowerBoundary = this.parseProperty(
-                            filter, this.ogcns, "LowerBoundary");
-                    rule.upperBoudary = this.parseProperty(
-                            filter, this.ogcns, "UpperBoundary");
-                } else {
-                    rule.value = this.parseProperty(
-                            filter, this.ogcns, "Literal");
-                    // ogc:PropertyIsLike
-                    if (this.TYPES[type] == "LIKE") {
-                        var wildCard = filter.getAttribute("wildCard");
-                        var singleChar = filter.getAttribute("singleChar");
-                        var escape = filter.getAttribute("escape");
-                        rule.value2regex(wildCard, singleChar, escape);
-                    }
-                }
-                return rule;
-            }
-        }
-        
-        // if we get here, the filter was empty
-        return new OpenLayers.Rule();
-    },
-    
-    /**
-     * Method: getNodeOrChildrenByTagName
-     * Convenience method to get a node or its child nodes, but only
-     *     those matching a tag name.
-     * 
-     * Returns:
-     * {Array(<DOMElement>)} or null if no matching content is found
-     */
-    getNodeOrChildrenByTagName: function(xmlNode, tagName) {
-        var nodeName = (xmlNode.prefix) ?
-               xmlNode.nodeName.split(":")[1] :
-               xmlNode.nodeName;
-
-        if (nodeName == tagName) {
-            return [xmlNode];
-        } else {
-            var nodelist = this.getElementsByTagNameNS(
-                    xmlNode, this.ogcns, tagName);
-        }
-
-        // make a new list which only contains matching child nodes
-        if (nodelist.length > 0) {
-            var node;
-            var list = [];
-            for (var i=0; i<nodelist.length; i++) {
-                node = nodelist[i];
-                if (node.parentNode == xmlNode) {
-                    list.push(node);
-                }
-            }
-            return list.length > 0 ? list : null;
-        }
-        
-        return null;
-    },
-    
-    /**
-     * Method: parseProperty
-     * Convenience method to parse the different kinds of properties
-     *     found in the sld and ogc namespace.
+     * data - {String | DOMElement} Data to read.
      *
-     * Parses an ogc node that can either contain a value directly,
-     *     or inside a <Literal> property. The parsing can also be limited
-     *     to nodes with certain attribute names and/or values.
-     *
-     * Parameters:
-     * xmlNode        - {<DOMElement>}
-     * namespace      - {String} namespace of the node to find
-     * propertyName   - {String} name of the property to parse
-     * attributeName  - {String} optional name of the property to match
-     * attributeValue - {String} optional value of the specified attribute
-     * 
      * Returns:
-     * {String} The value for the requested property.
-     */    
-    parseProperty: function(xmlNode, namespace, propertyName, attributeName,
-                                                              attributeValue) {
-        var result = null;
-        var propertyNodeList = this.getElementsByTagNameNS(
-                xmlNode, namespace, propertyName);
-                
-        if (propertyNodeList && propertyNodeList.length > 0) {
-            var propertyNode = attributeName ?
-                    this.getNodeWithAttribute(propertyNodeList, 
-                            attributeName) :
-                    propertyNodeList[0];
-
-            // strip namespace from attribute name for Opera browsers
-            if (window.opera && attributeName) {
-                var nsDelimiterPos = attributeName.indexOf(":");
-                if (nsDelimiterPos != -1) {
-                    attributeName = attributeName.substring(++nsDelimiterPos);
-                }
-            }
-            
-            // get the property value from the node matching attributeName
-            // and attributeValue, eg.:
-            // <CssParameter name="stroke">
-            //     <ogc:Literal>red</ogc:Literal>
-            // </CssParameter>
-            // or:
-            // <CssParameter name="stroke">red</CssParameter>
-            if (attributeName && attributeValue) {
-                propertyNode = this.getNodeWithAttribute(propertyNodeList,
-                        attributeName, attributeValue);
-                result = this.parseParameter(propertyNode);
-            }
-
-            // get the attribute value and use it as result, eg.:
-            // <sld:OnlineResource xlink:href="../img/marker.png"/>
-            if (attributeName && !attributeValue) {
-                var propertyNode = this.getNodeWithAttribute(propertyNodeList,
-                        attributeName);
-                result = propertyNode.getAttribute(attributeName);                
-            }
-            
-            // get the property value directly or from an ogc:propertyName,
-            // ogc:Literal or any other property at the level of the property
-            // node, eg.:
-            // <sld:Opacity>0.5</sld:Opacity>
-            if (!attributeName) {
-                var result = this.parseParameter(propertyNode);
-            }
-        }
-        
-        // adjust the result to be a trimmed string or a number
-        if (result) {
-            result = OpenLayers.String.trim(result);
-            if (!isNaN(result)) {
-                result = parseFloat(result);
-            }
-        }
-        
-        return result;
-    },
-    
-    /**
-     * Method: parseParameter
-     * parses a property for propertyNames, Literals and textContent and
-     * creates the according value string.
-     * 
-     * Parameters:
-     * xmlNode - {<DOMElement>}
-     * 
-     * Returns:
-     * {String} a string holding a value suitable for OpenLayers.Style.value
+     * {Object} An object representing the SLD.
      */
-    parseParameter: function(xmlNode) {
-        if (!xmlNode) {
-            return null;
+    read: function(data) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
         }
-        var childNodes = xmlNode.childNodes;
-        if (!childNodes) {
-            return null;
-        }
-
-        var value = new Array(childNodes.length);
-        for (var i=0; i<childNodes.length; i++) {
-            if (childNodes[i].nodeName.indexOf("Literal") != -1) {
-                value[i] = this.getChildValue(childNodes[i]);
-            } else
-            if (childNodes[i].nodeName.indexOf("propertyName") != -1) {
-                value[i] = "${" + this.getChildValue(childNodes[i]) + "}";
-            } else
-            if (childNodes[i].nodeType == 3) {
-                value[i] = childNodes[i].text || childNodes[i].textContent;
+        var root = data.documentElement;
+        var version = this.version;
+        if(!version) {
+            version = root.getAttribute("version");
+            if(!version) {
+                version = this.defaultVersion;
             }
         }
-        return value.join("");
-    },
-        
-    /**
-     * Method: getNodeWithAttribute
-     * Walks through a list of xml nodes and returns the fist node that has an
-     * attribute with the name and optional value specified.
-     * 
-     * Parameters:
-     * xmlNodeList    - {Array(<DOMElement>)} list to search
-     * attributeName  - {String} name of the attribute to match
-     * attributeValue - {String} optional value of the attribute
-     */
-    getNodeWithAttribute: function(xmlNodeList, attributeName, attributeValue) {
-        for (var i=0; i<xmlNodeList.length; i++) {
-            var currentAttributeValue =
-                    xmlNodeList[i].getAttribute(attributeName);
-            if (currentAttributeValue) {
-                if (!attributeValue) {
-                    return xmlNodeList[i];
-                } else if (currentAttributeValue == attributeValue) {
-                    return xmlNodeList[i];
-                }
+        if(!this.parser || this.parser.VERSION != version) {
+            var format = OpenLayers.Format.SLD[
+                "v" + version.replace(/\./g, "_")
+            ];
+            if(!format) {
+                throw "Can't find a SLD parser for version " +
+                      version;
             }
+            this.parser = new format(this.options);
         }
+        var sld = this.parser.read(data);
+        return sld;
     },
-    
-    /**
-     * Constant: TYPES
-     * {Object} Mapping between SLD rule names and rule type constants.
-     * 
-     */
-    TYPES: {'PropertyIsEqualTo': 'EQUAL_TO',
-            'PropertyIsNotEqualTo': 'NOT_EQUAL_TO',
-            'PropertyIsLessThan': 'LESS_THAN',
-            'PropertyIsGreaterThan': 'GREATER_THAN',
-            'PropertyIsLessThanOrEqualTo': 'LESS_THAN_OR_EQUAL_TO',
-            'PropertyIsGreaterThanOrEqualTo': 'GREATER_THAN_OR_EQUAL_TO',
-            'PropertyIsBetween': 'BETWEEN',
-            'PropertyIsLike': 'LIKE'},
 
     CLASS_NAME: "OpenLayers.Format.SLD" 
 });
@@ -36292,6 +36983,1196 @@
     CLASS_NAME: "OpenLayers.Layer.WFS"
 });
 /* ======================================================================
+    OpenLayers/Format/SLD/v1.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/SLD.js
+ */
+
+/**
+ * Class: OpenLayers.Format.SLD.v1
+ * Superclass for SLD version 1 parsers.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * Property: namespaces
+     * {Object} Mapping of namespace aliases to namespace URIs.
+     */
+    namespaces: {
+        sld: "http://www.opengis.net/sld",
+        ogc: "http://www.opengis.net/ogc",
+        xlink: "http://www.w3.org/1999/xlink",
+        xsi: "http://www.w3.org/2001/XMLSchema-instance"
+    },
+    
+    /**
+     * Property: defaultPrefix
+     */
+    defaultPrefix: "sld",
+
+    /**
+     * Property: schemaLocation
+     * {String} Schema location for a particular minor version.
+     */
+    schemaLocation: null,
+
+    /**
+     * APIProperty: defaultSymbolizer.
+     * {Object} A symbolizer with the SLD defaults.
+     */
+    defaultSymbolizer: {
+        fillColor: "#808080",
+        fillOpacity: 1,
+        strokeColor: "#000000",
+        strokeOpacity: 1,
+        strokeWidth: 1,
+        pointRadius: 6
+    },
+    
+    /**
+     * Constructor: OpenLayers.Format.SLD.v1
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.SLD> constructor instead.
+     *
+     * 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]);
+    },
+    
+    /**
+     * Method: read
+     *
+     * Parameters:
+     * data - {DOMElement} An SLD document element.
+     *
+     * Returns:
+     * {Object} An object representing the SLD.
+     */
+    read: function(data) {        
+        var sld = {
+            namedLayers: {}
+        };
+        this.readChildNodes(data, sld);
+        return sld;
+    },
+    
+    /**
+     * 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: {
+        "sld": {
+            "StyledLayerDescriptor": function(node, sld) {
+                sld.version = node.getAttribute("version");
+                this.readChildNodes(node, sld);
+            },
+            "Name": function(node, obj) {
+                obj.name = this.getChildValue(node);
+            },
+            "Title": function(node, obj) {
+                obj.title = this.getChildValue(node);
+            },
+            "Abstract": function(node, obj) {
+                obj.description = this.getChildValue(node);
+            },
+            "NamedLayer": function(node, sld) {
+                var layer = {
+                    userStyles: [],
+                    namedStyles: []
+                };
+                this.readChildNodes(node, layer);
+                // give each of the user styles this layer name
+                for(var i=0; i<layer.userStyles.length; ++i) {
+                    layer.userStyles[i].layerName = layer.name;
+                }
+                sld.namedLayers[layer.name] = layer;
+            },
+            "NamedStyle": function(node, layer) {
+                layer.namedStyles.push(
+                    this.getChildName(node.firstChild)
+                );
+            },
+            "UserStyle": function(node, layer) {
+                var style = new OpenLayers.Style(this.defaultSymbolizer);
+                this.readChildNodes(node, style);
+                layer.userStyles.push(style);
+            },
+            "IsDefault": function(node, style) {
+                if(this.getChildValue(node) == "1") {
+                    style.isDefault = true;
+                }
+            },
+            "FeatureTypeStyle": function(node, style) {
+                // OpenLayers doesn't have a place for FeatureTypeStyle
+                // Name, Title, Abstract, FeatureTypeName, or
+                // SemanticTypeIdentifier so, we make a temporary object
+                // and later just use the Rule(s).
+                var obj = {
+                    rules: []
+                };
+                this.readChildNodes(node, obj);
+                style.rules = obj.rules;
+            },
+            "Rule": function(node, obj) {
+                // Rule elements are represented as OpenLayers.Rule instances.
+                // Filter elements are represented as instances of
+                // OpenLayers.Rule subclasses.
+                var config = {
+                    rules: [],
+                    symbolizer: {}
+                };
+                this.readChildNodes(node, config);
+                // Now we've either got zero or one rules (from filters)
+                var rule;
+                if(config.rules.length == 0) {
+                    delete config.rules;
+                    rule = new OpenLayers.Rule(config);
+                } else {
+                    rule = config.rules[0];
+                    delete config.rules;
+                    OpenLayers.Util.extend(rule, config);
+                }
+                obj.rules.push(rule);
+            },
+            "ElseFilter": function(node, rule) {
+                rule.elseFilter = true;
+            },
+            "MinScaleDenominator": function(node, rule) {
+                rule.minScaleDenominator = this.getChildValue(node);
+            },
+            "MaxScaleDenominator": function(node, rule) {
+                rule.maxScaleDenominator = this.getChildValue(node);
+            },
+            "LineSymbolizer": function(node, rule) {
+                // OpenLayers doens't do painter's order, instead we extend
+                var symbolizer = rule.symbolizer["Line"] || {};
+                this.readChildNodes(node, symbolizer);
+                // in case it didn't exist before
+                rule.symbolizer["Line"] = symbolizer;
+            },
+            "PolygonSymbolizer": function(node, rule) {
+                // OpenLayers doens't do painter's order, instead we extend
+                var symbolizer = rule.symbolizer["Polygon"] || {};
+                this.readChildNodes(node, symbolizer);
+                // in case it didn't exist before
+                rule.symbolizer["Polygon"] = symbolizer;
+            },
+            "PointSymbolizer": function(node, rule) {
+                // OpenLayers doens't do painter's order, instead we extend
+                var symbolizer = rule.symbolizer["Point"] || {};
+                this.readChildNodes(node, symbolizer);
+                // in case it didn't exist before
+                rule.symbolizer["Point"] = symbolizer;
+            },
+            "Stroke": function(node, symbolizer) {
+                this.readChildNodes(node, symbolizer);
+            },
+            "Fill": function(node, symbolizer) {
+                this.readChildNodes(node, symbolizer);
+            },
+            "CssParameter": function(node, symbolizer) {
+                var cssProperty = node.getAttribute("name");
+                var symProperty = this.cssMap[cssProperty];
+                if(symProperty) {
+                    // Limited support for parsing of OGC expressions
+                    var value = this.readOgcExpression(node);
+                    // always string, could be an empty string
+                    if(value) {
+                        symbolizer[symProperty] = value;
+                    }
+                }
+            },
+            "Graphic": function(node, symbolizer) {
+                var graphic = {};
+                // painter's order not respected here, clobber previous with next
+                this.readChildNodes(node, graphic);
+                // directly properties with names that match symbolizer properties
+                var properties = [
+                    "strokeColor", "strokeWidth", "strokeOpacity",
+                    "strokeLinecap", "fillColor", "fillOpacity",
+                    "graphicName", "rotation", "graphicFormat"
+                ];
+                var prop, value;
+                for(var i=0; i<properties.length; ++i) {
+                    prop = properties[i];
+                    value = graphic[prop];
+                    if(value != undefined) {
+                        symbolizer[prop] = value;
+                    }
+                }
+                // set other generic properties with specific graphic property names
+                if(graphic.opacity != undefined) {
+                    symbolizer.graphicOpacity = graphic.opacity;
+                }
+                if(graphic.size != undefined) {
+                    symbolizer.pointRadius = graphic.size;
+                }
+                if(graphic.href != undefined) {
+                    symbolizer.externalGraphic = graphic.href;
+                }
+            },
+            "ExternalGraphic": function(node, graphic) {
+                this.readChildNodes(node, graphic);
+            },
+            "Mark": function(node, graphic) {
+                this.readChildNodes(node, graphic);
+            },
+            "WellKnownName": function(node, graphic) {
+                graphic.graphicName = this.getChildValue(node);
+            },
+            "Opacity": function(node, obj) {
+                // No support for parsing of OGC expressions
+                var opacity = this.getChildValue(node);
+                // always string, could be empty string
+                if(opacity) {
+                    obj.opacity = opacity;
+                }
+            },
+            "Size": function(node, obj) {
+                // No support for parsing of OGC expressions
+                var size = this.getChildValue(node);
+                // always string, could be empty string
+                if(size) {
+                    obj.size = size;
+                }
+            },
+            "Rotation": function(node, obj) {
+                // No support for parsing of OGC expressions
+                var rotation = this.getChildValue(node);
+                // always string, could be empty string
+                if(rotation) {
+                    obj.rotation = rotation;
+                }
+            },
+            "OnlineResource": function(node, obj) {
+                obj.href = this.getAttributeNS(
+                    node, this.namespaces.xlink, "href"
+                );
+            },
+            "Format": function(node, graphic) {
+                graphic.graphicFormat = this.getChildValue(node);
+            }
+        },
+        "ogc": {
+            "Filter": function(node, rule) {
+                // Filters correspond to subclasses of OpenLayers.Rule.
+                // Since they contain information we don't persist, we
+                // create a temporary object and then pass on the rules
+                // (ogc:Filter) to the parent rule (sld:Rule).
+                var filter = {
+                    fids: [],
+                    rules: []
+                };
+                this.readChildNodes(node, filter);
+                if(filter.fids.length > 0) {
+                    rule.rules.push(new OpenLayers.Rule.FeatureId({
+                        fids: filter.fids
+                    }));
+                }
+                if(filter.rules.length > 0) {
+                    rule.rules = rule.rules.concat(filter.rules);
+                }
+            },
+            "FeatureId": function(node, filter) {
+                var fid = node.getAttribute("fid");
+                if(fid) {
+                    filter.fids.push(fid);
+                }
+            },
+            "And": function(node, filter) {
+                var rule = new OpenLayers.Rule.Logical({
+                    type: OpenLayers.Rule.Logical.AND
+                });
+                // since FeatureId rules may be nested here, make room for them
+                rule.fids = [];
+                this.readChildNodes(node, rule);
+                if(rule.fids.length > 0) {
+                    rule.rules.push(new OpenLayers.Rule.FeatureId({
+                        fids: rule.fids
+                    }));
+                }
+                delete rule.fids;
+                filter.rules.push(rule);
+            },
+            "Or": function(node, filter) {
+                var rule = new OpenLayers.Rule.Logical({
+                    type: OpenLayers.Rule.Logical.OR
+                });
+                // since FeatureId rules may be nested here, make room for them
+                rule.fids = [];
+                this.readChildNodes(node, rule);
+                if(rule.fids.length > 0) {
+                    rule.rules.push(new OpenLayers.Rule.FeatureId({
+                        fids: rule.fids
+                    }));
+                }
+                delete rule.fids;
+                filter.rules.push(rule);
+            },
+            "Not": function(node, filter) {
+                var rule = new OpenLayers.Rule.Logical({
+                    type: OpenLayers.Rule.Logical.NOT
+                });
+                // since FeatureId rules may be nested here, make room for them
+                rule.fids = [];
+                this.readChildNodes(node, rule);
+                if(rule.fids.length > 0) {
+                    rule.rules.push(new OpenLayers.Rule.FeatureId({
+                        fids: rule.fids
+                    }));
+                }
+                delete rule.fids;
+                filter.rules.push(rule);
+            },
+            "PropertyIsEqualTo": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.EQUAL_TO
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsNotEqualTo": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.NOT_EQUAL_TO
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsLessThan": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.LESS_THAN
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsGreaterThan": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.GREATER_THAN
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsLessThanOrEqualTo": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsGreaterThanOrEqualTo": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsBetween": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.BETWEEN
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsLike": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.LIKE
+                });
+                this.readChildNodes(node, rule);
+                var wildCard = node.getAttribute("wildCard");
+                var singleChar = node.getAttribute("singleChar");
+                var esc = node.getAttribute("escape");
+                rule.value2regex(wildCard, singleChar, esc);
+                filter.rules.push(rule);
+            },
+            "Literal": function(node, obj) {
+                obj.value = this.getChildValue(node);
+            },
+            "PropertyName": function(node, rule) {
+                rule.property = this.getChildValue(node);
+            },
+            "LowerBoundary": function(node, rule) {
+                rule.lowerBoundary = this.readOgcExpression(node);
+            },
+            "UpperBoundary": function(node, rule) {
+                rule.upperBoundary = this.readOgcExpression(node);
+            }
+        }
+    },
+    
+    /**
+     * Method: readOgcExpression
+     * Limited support for OGC expressions.
+     *
+     * Parameters:
+     * node - {DOMElement} A DOM element that contains an ogc:expression.
+     *
+     * Returns:
+     * {String} A value to be used in a symbolizer.
+     */
+    readOgcExpression: function(node) {
+        var obj = {};
+        this.readChildNodes(node, obj);
+        var value = obj.value;
+        if(!value) {
+            value = this.getChildValue(node);
+        }
+        return value;
+    },
+    
+    /**
+     * Property: cssMap
+     * {Object} Object mapping supported css property names to OpenLayers
+     *     symbolizer property names.
+     */
+    cssMap: {
+        "stroke": "strokeColor",
+        "stroke-opacity": "strokeOpacity",
+        "stroke-width": "strokeWidth",
+        "stroke-linecap": "strokeLinecap",
+        "fill": "fillColor",
+        "fill-opacity": "fillOpacity"
+    },
+    
+    /**
+     * Method: getCssProperty
+     * Given a symbolizer property, get the corresponding CSS property
+     *     from the <cssMap>.
+     *
+     * Parameters:
+     * sym - {String} A symbolizer property name.
+     *
+     * Returns:
+     * {String} A CSS property name or null if none found.
+     */
+    getCssProperty: function(sym) {
+        var css = null;
+        for(var prop in this.cssMap) {
+            if(this.cssMap[prop] == sym) {
+                css = prop;
+                break;
+            }
+        }
+        return css;
+    },
+    
+    /**
+     * Method: getGraphicFormat
+     * Given a href for an external graphic, try to determine the mime-type.
+     *     This method doesn't try too hard, and will fall back to
+     *     <defautlGraphicFormat> if one of the known <graphicFormats> is not
+     *     the file extension of the provided href.
+     *
+     * Parameters:
+     * href - {String}
+     *
+     * Returns:
+     * {String} The graphic format.
+     */
+    getGraphicFormat: function(href) {
+        var format, regex;
+        for(var key in this.graphicFormats) {
+            if(this.graphicFormats[key].test(href)) {
+                format = key;
+                break;
+            }
+        }
+        return format || this.defautlGraphicFormat;
+    },
+    
+    /**
+     * Property: defaultGraphicFormat
+     * {String} If none other can be determined from <getGraphicFormat>, this
+     *     default will be returned.
+     */
+    defaultGraphicFormat: "image/png",
+    
+    /**
+     * Property: graphicFormats
+     * {Object} Mapping of image mime-types to regular extensions matching 
+     *     well-known file extensions.
+     */
+    graphicFormats: {
+        "image/jpeg": /\.jpe?g$/i,
+        "image/gif": /\.gif$/i,
+        "image/png": /\.png$/i
+    },
+
+    /**
+     * Method: write
+     *
+     * Parameters:
+     * sld - {Object} An object representing the SLD.
+     *
+     * Returns:
+     * {DOMElement} The root of an SLD document.
+     */
+    write: function(sld) {
+        return this.writers.sld.StyledLayerDescriptor.apply(this, [sld]);
+    },
+    
+    /**
+     * 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: {
+        "sld": {
+            "StyledLayerDescriptor": function(sld) {
+                var root = this.createElementNSPlus(
+                    "StyledLayerDescriptor",
+                    {attributes: {
+                        "version": this.VERSION,
+                        "xsi:schemaLocation": this.schemaLocation
+                    }}
+                );
+                // add in optional name
+                if(sld.name) {
+                    this.writeNode(root, "Name", sld.name);
+                }
+                // add in optional title
+                if(sld.title) {
+                    this.writeNode(root, "Title", sld.title);
+                }
+                // add in optional description
+                if(sld.description) {
+                    this.writeNode(root, "Abstract", sld.description);
+                }
+                // add in named layers
+                for(var name in sld.namedLayers) {
+                    this.writeNode(root, "NamedLayer", sld.namedLayers[name]);
+                }
+                return root;
+            },
+            "Name": function(name) {
+                return this.createElementNSPlus("Name", {value: name});
+            },
+            "Title": function(title) {
+                return this.createElementNSPlus("Title", {value: title});
+            },
+            "Abstract": function(description) {
+                return this.createElementNSPlus(
+                    "Abstract", {value: description}
+                );
+            },
+            "NamedLayer": function(layer) {
+                var node = this.createElementNSPlus("NamedLayer");
+
+                // add in required name
+                this.writeNode(node, "Name", layer.name);
+
+                // optional sld:LayerFeatureConstraints here
+
+                // add in named styles
+                if(layer.namedStyles) {
+                    for(var i=0; i<layer.namedStyles.length; ++i) {
+                        this.writeNode(
+                            node, "NamedStyle", layer.namedStyles[i]
+                        );
+                    }
+                }
+                
+                // add in user styles
+                if(layer.userStyles) {
+                    for(var i=0; i<layer.userStyles.length; ++i) {
+                        this.writeNode(
+                            node, "UserStyle", layer.userStyles[i]
+                        );
+                    }
+                }
+                
+                return node;
+            },
+            "NamedStyle": function(name) {
+                var node = this.createElementNSPlus("NamedStyle");
+                this.writeNode(node, "Name", name);
+                return node;
+            },
+            "UserStyle": function(style) {
+                var node = this.createElementNSPlus("UserStyle");
+
+                // add in optional name
+                if(style.name) {
+                    this.writeNode(node, "Name", style.name);
+                }
+                // add in optional title
+                if(style.title) {
+                    this.writeNode(node, "Title", style.title);
+                }
+                // add in optional description
+                if(style.description) {
+                    this.writeNode(node, "Abstract", style.description);
+                }
+                
+                // add isdefault
+                if(style.isDefault) {
+                    this.writeNode(node, "IsDefault", style.isDefault);
+                }
+                
+                // add FeatureTypeStyles
+                this.writeNode(node, "FeatureTypeStyle", style);
+                
+                return node;
+            },
+            "IsDefault": function(bool) {
+                return this.createElementNSPlus(
+                    "IsDefault", {value: (bool) ? "1" : "0"}
+                );
+            },
+            "FeatureTypeStyle": function(style) {
+                var node = this.createElementNSPlus("FeatureTypeStyle");
+                
+                // OpenLayers currently stores no Name, Title, Abstract,
+                // FeatureTypeName, or SemanticTypeIdentifier information
+                // related to FeatureTypeStyle
+                
+                // add in rules
+                for(var i=0; i<style.rules.length; ++i) {
+                    this.writeNode(node, "Rule", style.rules[i]);
+                }
+                
+                return node;
+            },
+            "Rule": function(rule) {
+                var node = this.createElementNSPlus("Rule");
+
+                // add in optional name
+                if(rule.name) {
+                    this.writeNode(node, "Name", rule.name);
+                }
+                // add in optional title
+                if(rule.title) {
+                    this.writeNode(node, "Title", rule.title);
+                }
+                // add in optional description
+                if(rule.description) {
+                    this.writeNode(node, "Abstract", rule.description);
+                }
+                
+                // add in LegendGraphic here
+                
+                // add in optional filters
+                if(rule.elseFilter) {
+                    this.writeNode(node, "ElseFilter");
+                } else if(rule.CLASS_NAME != "OpenLayers.Rule") {
+                    this.writeNode(node, "ogc:Filter", rule);
+                }
+                
+                // add in scale limits
+                if(rule.minScaleDenominator != undefined) {
+                    this.writeNode(
+                        node, "MinScaleDenominator", rule.minScaleDenominator
+                    );
+                }
+                if(rule.maxScaleDenominator != undefined) {
+                    this.writeNode(
+                        node, "MaxScaleDenominator", rule.maxScaleDenominator
+                    );
+                }
+                
+                // add in symbolizers (relies on geometry type keys)
+                var types = OpenLayers.Style.SYMBOLIZER_PREFIXES;
+                var type, symbolizer;
+                for(var i=0; i<types.length; ++i) {
+                    type = types[i];
+                    symbolizer = rule.symbolizer[type];
+                    if(symbolizer) {
+                        this.writeNode(
+                            node, type + "Symbolizer", symbolizer
+                        );
+                    }
+                }
+                return node;
+
+            },
+            "ElseFilter": function() {
+                return this.createElementNSPlus("ElseFilter");
+            },
+            "MinScaleDenominator": function(scale) {
+                return this.createElementNSPlus(
+                    "MinScaleDenominator", {value: scale}
+                );
+            },
+            "MaxScaleDenominator": function(scale) {
+                return this.createElementNSPlus(
+                    "MaxScaleDenominator", {value: scale}
+                );
+            },
+            "LineSymbolizer": function(symbolizer) {
+                var node = this.createElementNSPlus("LineSymbolizer");
+                this.writeNode(node, "Stroke", symbolizer);
+                return node;
+            },
+            "Stroke": function(symbolizer) {
+                var node = this.createElementNSPlus("Stroke");
+
+                // GraphicFill here
+                // GraphicStroke here
+
+                // add in CssParameters
+                if(symbolizer.strokeColor != undefined) {
+                    this.writeNode(
+                        node, "CssParameter",
+                        {symbolizer: symbolizer, key: "strokeColor"}
+                    );
+                }
+                if(symbolizer.strokeOpacity != undefined) {
+                    this.writeNode(
+                        node, "CssParameter",
+                        {symbolizer: symbolizer, key: "strokeOpacity"}
+                    );
+                }
+                if(symbolizer.strokeWidth != undefined) {
+                    this.writeNode(
+                        node, "CssParameter",
+                        {symbolizer: symbolizer, key: "strokeWidth"}
+                    );
+                }
+                return node;
+            },
+            "CssParameter": function(obj) {
+                // not handling ogc:expressions for now
+                return this.createElementNSPlus("CssParameter", {
+                    attributes: {name: this.getCssProperty(obj.key)},
+                    value: obj.symbolizer[obj.key]
+                });
+            },
+            "PolygonSymbolizer": function(symbolizer) {
+                var node = this.createElementNSPlus("PolygonSymbolizer");
+                this.writeNode(node, "Fill", symbolizer);
+                this.writeNode(node, "Stroke", symbolizer);
+                return node;
+            },
+            "Fill": function(symbolizer) {
+                var node = this.createElementNSPlus("Fill");
+                
+                // GraphicFill here
+                
+                // add in CssParameters
+                if(symbolizer.fillColor) {
+                    this.writeNode(
+                        node, "CssParameter",
+                        {symbolizer: symbolizer, key: "fillColor"}
+                    );
+                }
+                if(symbolizer.fillOpacity) {
+                    this.writeNode(
+                        node, "CssParameter",
+                        {symbolizer: symbolizer, key: "fillOpacity"}
+                    );
+                }
+                return node;
+            },
+            "PointSymbolizer": function(symbolizer) {
+                var node = this.createElementNSPlus("PointSymbolizer");
+                this.writeNode(node, "Graphic", symbolizer);
+                return node;
+            },
+            "Graphic": function(symbolizer) {
+                var node = this.createElementNSPlus("Graphic");
+                if(symbolizer.externalGraphic != undefined) {
+                    this.writeNode(node, "ExternalGraphic", symbolizer);
+                } else if(symbolizer.graphicName) {
+                    this.writeNode(node, "Mark", symbolizer);
+                }
+                
+                if(symbolizer.graphicOpacity != undefined) {
+                    this.writeNode(node, "Opacity", symbolizer.graphicOpacity);
+                }
+                if(symbolizer.pointRadius != undefined) {
+                    this.writeNode(node, "Size", symbolizer.pointRadius);
+                }
+                if(symbolizer.rotation != undefined) {
+                    this.writeNode(node, "Rotation", symbolizer.rotation);
+                }
+                return node;
+            },
+            "ExternalGraphic": function(symbolizer) {
+                var node = this.createElementNSPlus("ExternalGraphic");
+                this.writeNode(
+                    node, "OnlineResource", symbolizer.externalGraphic
+                );
+                var format = symbolizer.graphicFormat ||
+                             this.getGraphicFormat(symbolizer.externalGraphic);
+                this.writeNode(node, "Format", format);
+                return node;
+            },
+            "Mark": function(symbolizer) {
+                var node = this.createElementNSPlus("Mark");
+                this.writeNode(node, "WellKnownName", symbolizer.graphicName);
+                this.writeNode(node, "Fill", symbolizer);
+                this.writeNode(node, "Stroke", symbolizer);
+                return node;
+            },
+            "WellKnownName": function(name) {
+                return this.createElementNSPlus("WellKnownName", {
+                    value: name
+                });
+            },
+            "Opacity": function(value) {
+                return this.createElementNSPlus("Opacity", {
+                    value: value
+                });
+            },
+            "Size": function(value) {
+                return this.createElementNSPlus("Size", {
+                    value: value
+                });
+            },
+            "Rotation": function(value) {
+                return this.createElementNSPlus("Rotation", {
+                    value: value
+                });
+            },
+            "OnlineResource": function(href) {
+                return this.createElementNSPlus("OnlineResource", {
+                    attributes: {
+                        "xlink:type": "simple",
+                        "xlink:href": href
+                    }
+                });
+            },
+            "Format": function(format) {
+                return this.createElementNSPlus("Format", {
+                    value: format
+                });
+            }
+        },
+        "ogc": {
+            "Filter": function(rule) {
+                var node = this.createElementNSPlus("ogc:Filter");
+                var sub = rule.CLASS_NAME.split(".").pop();
+                if(sub == "FeatureId") {
+                    for(var i=0; i<rule.fids.length; ++i) {
+                        this.writeNode(node, "FeatureId", rule.fids[i]);
+                    }
+                } else {
+                    this.writeNode(node, this.getFilterType(rule), rule);
+                }
+                return node;
+            },
+            "FeatureId": function(fid) {
+                return this.createElementNSPlus("ogc:FeatureId", {
+                    attributes: {fid: fid}
+                });
+            },
+            "And": function(rule) {
+                var node = this.createElementNSPlus("ogc:And");
+                var childRule;
+                for(var i=0; i<rule.rules.length; ++i) {
+                    childRule = rule.rules[i];
+                    this.writeNode(
+                        node, this.getFilterType(childRule), childRule
+                    );
+                }
+                return node;
+            },
+            "Or": function(rule) {
+                var node = this.createElementNSPlus("ogc:Or");
+                var childRule;
+                for(var i=0; i<rule.rules.length; ++i) {
+                    childRule = rule.rules[i];
+                    this.writeNode(
+                        node, this.getFilterType(childRule), childRule
+                    );
+                }
+                return node;
+            },
+            "Not": function(rule) {
+                var node = this.createElementNSPlus("ogc:Not");
+                var childRule = rule.rules[0];
+                this.writeNode(
+                    node, this.getFilterType(childRule), childRule
+                );
+                return node;
+            },
+            "PropertyIsEqualTo": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsEqualTo");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);
+                return node;
+            },
+            "PropertyIsNotEqualTo": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);
+                return node;
+            },
+            "PropertyIsLessThan": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsLessThan");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);                
+                return node;
+            },
+            "PropertyIsGreaterThan": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsGreaterThan");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);
+                return node;
+            },
+            "PropertyIsLessThanOrEqualTo": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);
+                return node;
+            },
+            "PropertyIsGreaterThanOrEqualTo": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);
+                return node;
+            },
+            "PropertyIsBetween": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsBetween");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "LowerBoundary", rule);
+                this.writeNode(node, "UpperBoundary", rule);
+                return node;
+            },
+            "PropertyIsLike": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsLike", {
+                    attributes: {
+                        wildCard: "*", singleChar: ".", escape: "!"
+                    }
+                });
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                // convert regex string to ogc string
+                this.writeNode(node, "Literal", {value: rule.regex2value()});
+                return node;
+            },
+            "PropertyName": function(rule) {
+                // no ogc:expression handling for now
+                return this.createElementNSPlus("ogc:PropertyName", {
+                    value: rule.property
+                });
+            },
+            "Literal": function(rule) {
+                // no ogc:expression handling for now
+                return this.createElementNSPlus("ogc:Literal", {
+                    value: rule.value
+                });
+            },
+            "LowerBoundary": function(rule) {
+                // no ogc:expression handling for now
+                var node = this.createElementNSPlus("ogc:LowerBoundary");
+                this.writeNode(node, "Literal", rule.lowerBoundary);
+                return node;
+            },
+            "UpperBoundary": function(rule) {
+                // no ogc:expression handling for now
+                var node = this.createElementNSPlus("ogc:UpperBoundary");
+                this.writeNode(node, "Literal", rule.upperBoundary);
+                return node;
+            }
+        }
+    },
+    
+    /**
+     * Method: getFilterType
+     */
+    getFilterType: function(rule) {
+        var filterType = this.filterMap[rule.type];
+        if(!filterType) {
+            throw "SLD writing not supported for rule type: " + rule.type;
+        }
+        return filterType;
+    },
+    
+    /**
+     * Property: filterMap
+     * {Object} Contains a member for each rule type.  Values are node names
+     *     for corresponding OGC Filter child elements.
+     */
+    filterMap: {
+        "&&": "And",
+        "||": "Or",
+        "!": "Not",
+        "==": "PropertyIsEqualTo",
+        "!=": "PropertyIsNotEqualTo",
+        "<": "PropertyIsLessThan",
+        ">": "PropertyIsGreaterThan",
+        "<=": "PropertyIsLessThanOrEqualTo",
+        ">=": "PropertyIsGreaterThanOrEqualTo",
+        "..": "PropertyIsBetween",
+        "~": "PropertyIsLike"
+    },
+    
+
+    /**
+     * Methods below this point are of general use for versioned XML parsers.
+     * These are candidates for an abstract class.
+     */
+    
+    /**
+     * Method: getNamespacePrefix
+     * Get the namespace prefix for a given uri from the <namespaces> object.
+     *
+     * Returns:
+     * {String} A namespace prefix or null if none found.
+     */
+    getNamespacePrefix: function(uri) {
+        var prefix = null;
+        if(uri == null) {
+            prefix = this.namespaces[this.defaultPrefix];
+        } else {
+            var gotPrefix = false;
+            for(prefix in this.namespaces) {
+                if(this.namespaces[prefix] == uri) {
+                    gotPrefix = true;
+                    break;
+                }
+            }
+            if(!gotPrefix) {
+                prefix = null;
+            }
+        }
+        return prefix;
+    },
+
+
+    /**
+     * Method: readChildNodes
+     */
+    readChildNodes: function(node, obj) {
+        var children = node.childNodes;
+        var child, group, reader, prefix, local;
+        for(var i=0; i<children.length; ++i) {
+            child = children[i];
+            if(child.nodeType == 1) {
+                prefix = this.getNamespacePrefix(child.namespaceURI);
+                local = child.nodeName.split(":").pop();
+                group = this.readers[prefix];
+                if(group) {
+                    reader = group[local];
+                    if(reader) {
+                        reader.apply(this, [child, 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:
+     * parent - {DOMElement} Result will be appended to this node.
+     * 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.
+     * obj - {Object} Structure containing data for the writer.
+     *
+     * Returns:
+     * {DOMElement} The child node.
+     */
+    writeNode: function(parent, name, obj) {
+        var prefix, local;
+        var split = name.indexOf(":");
+        if(split > 0) {
+            prefix = name.substring(0, split);
+            local = name.substring(split + 1);
+        } else {
+            prefix = this.getNamespacePrefix(parent.namespaceURI);
+            local = name;
+        }
+        var child = this.writers[prefix][local].apply(this, [obj]);
+        parent.appendChild(child);
+        return child;
+    },
+    
+    /**
+     * 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.
+     *
+     * Returns:
+     * {Element} An element node.
+     */
+    createElementNSPlus: function(name, options) {
+        options = options || {};
+        var loc = name.indexOf(":");
+        // 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) {
+            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);
+        }
+        if(options.value) {
+            node.appendChild(this.createTextNode(options.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, loc, alias, uri;
+        for(var name in obj) {
+            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);
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Format.SLD.v1" 
+
+});
+/* ======================================================================
     OpenLayers/Geometry/Curve.js
    ====================================================================== */
 
@@ -36352,6 +38233,59 @@
     CLASS_NAME: "OpenLayers.Geometry.Curve"
 });
 /* ======================================================================
+    OpenLayers/Format/SLD/v1_0_0.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/SLD/v1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.SLD.v1_0_0
+ * Write SLD version 1.0.0.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.SLD.v1>
+ */
+OpenLayers.Format.SLD.v1_0_0 = OpenLayers.Class(
+    OpenLayers.Format.SLD.v1, {
+    
+    /**
+     * Constant: VERSION
+     * {String} 1.0.0
+     */
+    VERSION: "1.0.0",
+    
+    /**
+     * Property: schemaLocation
+     * {String} http://www.opengis.net/sld
+     *   http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd
+     */
+    schemaLocation: "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd",
+
+    /**
+     * Constructor: OpenLayers.Format.SLD.v1_0_0
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.SLD> constructor instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.SLD.v1.prototype.initialize.apply(
+            this, [options]
+        );
+    },
+
+    CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0" 
+
+});
+/* ======================================================================
     OpenLayers/Geometry/LineString.js
    ====================================================================== */
 
@@ -36494,14 +38428,14 @@
                     y1: point1.y,
                     x2: point2.x,
                     y2: point2.y
-                }
+                };
             } else {
                 segments[i] = {
                     x1: point2.x,
                     y1: point2.y,
                     x2: point1.x,
                     y2: point1.y
-                }
+                };
             }
         }
         // more efficient to define this somewhere static
@@ -39305,7 +41239,7 @@
                         var name = (child.prefix) ?
                                 child.nodeName.split(":")[1] :
                                 child.nodeName;
-                        var value = OpenLayers.Util.getXmlNodeValue(grandchild)
+                        var value = OpenLayers.Util.getXmlNodeValue(grandchild);
                         if (value) {
                             value = value.replace(this.regExes.trimSpace, "");
                             attributes[name] = value;
@@ -39972,7 +41906,7 @@
     createFeatureNodes: function(feature) {
         var nodes = [];
         var className = feature.geometry.CLASS_NAME;
-        var type = className.substring(className.lastIndexOf(".") + 1)
+        var type = className.substring(className.lastIndexOf(".") + 1);
         type = type.toLowerCase();
         var builder = this.createXML[type];
         if (builder) {

Modified: sandbox/olcore/lib/OpenLayers/OpenLayersCompressed.js
===================================================================
--- sandbox/olcore/lib/OpenLayers/OpenLayersCompressed.js	2008-03-31 21:04:04 UTC (rev 1356)
+++ sandbox/olcore/lib/OpenLayers/OpenLayersCompressed.js	2008-04-01 19:16:04 UTC (rev 1357)
@@ -45,7 +45,7 @@
 
 var OpenLayers={singleFile:true};(function(){var singleFile=(typeof OpenLayers=="object"&&OpenLayers.singleFile);window.OpenLayers={_scriptName:(!singleFile)?"lib/OpenLayers.js":"OpenLayers.js",_getScriptLocation:function(){var scriptLocation="";var scriptName=OpenLayers._scriptName;var scripts=document.getElementsByTagName('script');for(var i=0;i<scripts.length;i++){var src=scripts[i].getAttribute('src');if(src){var index=src.lastIndexOf(scriptName);var pathLength=src.lastIndexOf('?');if(pathLength<0){pathLength=src.length;}
 if((index>-1)&&(index+scriptName.length==pathLength)){scriptLocation=src.slice(0,pathLength-scriptName.length);break;}}}
-return scriptLocation;}};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/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/WFS.js","OpenLayers/Layer/Image.js","OpenLayers/Layer/SphericalMercator.js","OpenLayers/Layer/EventPane.js","OpenLayers/Layer/FixedZoomLevels.js","OpenLayers/Layer/Google.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/MultiMap.js","OpenLayers/Layer/Markers.js","OpenLayers/Layer/Text.js","OpenLayers/Layer/WorldWind.js","OpenLayers/Layer/WMS.js","OpenLayers/Layer/WMS/Untiled.js","OpenLayers/Layer/GeoRSS.js","OpenLayers/Layer/Boxes.js","OpenLayers/Layer/TMS.js","OpenLayers/Layer/TileCache.js","OpenLayers/Popup/Anchored.js","OpenLayers/Popup/AnchoredBubble.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/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/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/VML.js","OpenLayers/Layer/Vector.js","OpenLayers/Layer/PointTrack.js","OpenLayers/Layer/GML.js","OpenLayers/Style.js","OpenLayers/StyleMap.js","OpenLayers/Rule.js","OpenLayers/Rule/FeatureId.js","OpenLayers/Rule/Logical.js","OpenLayers/Rule/Comparison.js","OpenLayers/Format.js","OpenLayers/Format/XML.js","OpenLayers/Format/GML.js","OpenLayers/Format/KML.js","OpenLayers/Format/GeoRSS.js","OpenLayers/Format/WFS.js","OpenLayers/Format/WKT.js","OpenLayers/Format/OSM.js","OpenLayers/Format/SLD.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/Layer/WFS.js","OpenLayers/Control/MouseToolbar.js","OpenLayers/Control/NavToolbar.js","OpenLayers/Control/EditingToolbar.js","OpenLayers/Lang.js","OpenLayers/Lang/en.js");var agent=navigator.userAgent;var docWrite=(agent.match("MSIE")||agent.match("Safari"));if(docWrite){var allScriptTags=new Array(jsfiles.length);}
+return scriptLocation;}};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/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/WFS.js","OpenLayers/Layer/Image.js","OpenLayers/Layer/SphericalMercator.js","OpenLayers/Layer/EventPane.js","OpenLayers/Layer/FixedZoomLevels.js","OpenLayers/Layer/Google.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/MultiMap.js","OpenLayers/Layer/Markers.js","OpenLayers/Layer/Text.js","OpenLayers/Layer/WorldWind.js","OpenLayers/Layer/WMS.js","OpenLayers/Layer/WMS/Untiled.js","OpenLayers/Layer/GeoRSS.js","OpenLayers/Layer/Boxes.js","OpenLayers/Layer/TMS.js","OpenLayers/Layer/TileCache.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/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/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/VML.js","OpenLayers/Layer/Vector.js","OpenLayers/Layer/PointTrack.js","OpenLayers/Layer/GML.js","OpenLayers/Style.js","OpenLayers/StyleMap.js","OpenLayers/Rule.js","OpenLayers/Rule/FeatureId.js","OpenLayers/Rule/Logical.js","OpenLayers/Rule/Comparison.js","OpenLayers/Format.js","OpenLayers/Format/XML.js","OpenLayers/Format/GML.js","OpenLayers/Format/KML.js","OpenLayers/Format/GeoRSS.js","OpenLayers/Format/WFS.js","OpenLayers/Format/WKT.js","OpenLayers/Format/OSM.js","OpenLayers/Format/SLD.js","OpenLayers/Format/SLD/v1.js","OpenLayers/Format/SLD/v1_0_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/Layer/WFS.js","OpenLayers/Control/MouseToolbar.js","OpenLayers/Control/NavToolbar.js","OpenLayers/Control/EditingToolbar.js","OpenLayers/Lang.js","OpenLayers/Lang/en.js");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;i<jsfiles.length;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(""));}}})();OpenLayers.VERSION_NUMBER="$Revision$";OpenLayers.String={startsWith:function(str,sub){return(str.indexOf(sub)==0);},contains:function(str,sub){return(str.indexOf(sub)!=-1);},trim:function(str){return str.replace(/^\s*(.*?)\s*$/,"$1");},camelize:function(str){var oStringList=str.split('-');var camelizedString=oStringList[0];for(var i=1;i<oStringList.length;i++){var s=oStringList[i];camelizedString+=s.charAt(0).toUpperCase()+s.substring(1);}
 return camelizedString;},format:function(template,context,args){if(!context){context=window;}
@@ -143,7 +143,11 @@
 if((urlObject.protocol=="file:")||(urlObject.protocol=="")){urlObject.host="localhost";}
 return urlObject;};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;};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;};OpenLayers.Rico=new Object();OpenLayers.Rico.Corner={round:function(e,options){e=OpenLayers.Util.getElement(e);this._setOptions(options);var color=this.options.color;if(this.options.color=="fromElement"){color=this._background(e);}
+return browserName;};OpenLayers.Util.getRenderedDimensions=function(contentHTML,size){var w=h=null;var container=document.createElement("div");container.style.overflow="";container.style.position="absolute";container.style.left="-9999px";if(size){if(size.w){w=container.style.width=size.w;}else if(size.h){h=container.style.height=size.h;}}
+var content=document.createElement("div");content.innerHTML=contentHTML;container.appendChild(content);document.body.appendChild(container);if(!w){w=parseInt(content.scrollWidth);container.style.width=w+"px";}
+if(!h){h=parseInt(content.scrollHeight);}
+container.removeChild(content);document.body.removeChild(container);return new OpenLayers.Size(w,h);};OpenLayers.Util.getScrollbarWidth=function(){var scrollbarWidth=OpenLayers.Util._scrollbarWidth;if(scrollbarWidth==null){var scr=null;var inn=null;var wNoScroll=0;var wScroll=0;scr=document.createElement('div');scr.style.position='absolute';scr.style.top='-1000px';scr.style.left='-1000px';scr.style.width='100px';scr.style.height='50px';scr.style.overflow='hidden';inn=document.createElement('div');inn.style.width='100%';inn.style.height='200px';scr.appendChild(inn);document.body.appendChild(scr);wNoScroll=inn.offsetWidth;scr.style.overflow='scroll';wScroll=inn.offsetWidth;document.body.removeChild(document.body.lastChild);OpenLayers.Util._scrollbarWidth=(wNoScroll-wScroll);scrollbarWidth=OpenLayers.Util._scrollbarWidth;}
+return scrollbarWidth;};OpenLayers.Rico=new Object();OpenLayers.Rico.Corner={round:function(e,options){e=OpenLayers.Util.getElement(e);this._setOptions(options);var color=this.options.color;if(this.options.color=="fromElement"){color=this._background(e);}
 var bgColor=this.options.bgColor;if(this.options.bgColor=="fromParent"){bgColor=this._background(e.offsetParent);}
 this._roundCornersImpl(e,color,bgColor);},changeColor:function(theDiv,newColor){theDiv.style.backgroundColor=newColor;var spanElements=theDiv.parentNode.getElementsByTagName("span");for(var currIdx=0;currIdx<spanElements.length;currIdx++){spanElements[currIdx].style.backgroundColor=newColor;}},changeOpacity:function(theDiv,newOpacity){var mozillaOpacity=newOpacity;var ieOpacity='alpha(opacity='+newOpacity*100+')';theDiv.style.opacity=mozillaOpacity;theDiv.style.filter=ieOpacity;var spanElements=theDiv.parentNode.getElementsByTagName("span");for(var currIdx=0;currIdx<spanElements.length;currIdx++){spanElements[currIdx].style.opacity=mozillaOpacity;spanElements[currIdx].style.filter=ieOpacity;}},reRound:function(theDiv,options){var topRico=theDiv.parentNode.childNodes[0];var bottomRico=theDiv.parentNode.childNodes[2];theDiv.parentNode.removeChild(topRico);theDiv.parentNode.removeChild(bottomRico);this.round(theDiv.parentNode,options);},_roundCornersImpl:function(e,color,bgColor){if(this.options.border){this._renderBorder(e,bgColor);}
 if(this._isTopRounded()){this._roundTopCorners(e,color,bgColor);}
@@ -215,13 +219,14 @@
 return equals;},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.i18n("pixelAddError");OpenLayers.Console.error(msg);return null;}
 return new OpenLayers.Pixel(this.x+x,this.y+y);},offset:function(px){var newPx=this.clone();if(px){newPx=this.add(px.x,px.y);}
 return newPx;},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0.0,h:0.0,initialize:function(w,h){this.w=parseFloat(w);this.h=parseFloat(h);},toString:function(){return("w="+this.w+",h="+this.h);},clone:function(){return new OpenLayers.Size(this.w,this.h);},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.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};(function(){if(window.console){var scripts=document.getElementsByTagName("script");for(var i=0;i<scripts.length;++i){if(scripts[i].src.indexOf("firebug.js")!=-1){OpenLayers.Util.extend(OpenLayers.Console,console);break;}}}})();OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,displayClass:"",title:"",active:null,handler:null,eventListeners:null,events:null,EVENT_TYPES:["activate","deactivate"],initialize:function(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);}
+return equals;},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};(function(){if(window.console){var scripts=document.getElementsByTagName("script");for(var i=0;i<scripts.length;++i){if(scripts[i].src.indexOf("firebug.js")!=-1){OpenLayers.Util.extend(OpenLayers.Console,console);break;}}}})();OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,allowSelection:false,displayClass:"",title:"",active:null,handler:null,eventListeners:null,events:null,EVENT_TYPES:["activate","deactivate"],initialize:function(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);}
 this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){if(this.events){if(this.eventListeners){this.events.un(this.eventListeners);}
 this.events.destroy();this.events=null;}
 this.eventListeners=null;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;}},setMap:function(map){this.map=map;if(this.handler){this.handler.setMap(map);}},draw:function(px){if(this.div==null){this.div=OpenLayers.Util.createDiv(this.id);this.div.className=this.displayClass;if(this.title!=""){this.div.title=this.title;}}
+if(this.map){this.map.removeControl(this);this.map=null;}},setMap:function(map){this.map=map;if(this.handler){this.handler.setMap(map);}},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=function(){return(false);};}
+if(this.title!=""){this.div.title=this.title;}}
 if(px!=null){this.position=px.clone();}
 this.moveTo(this.position);return this.div;},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},activate:function(){if(this.active){return false;}
 if(this.handler){this.handler.activate();}
@@ -235,21 +240,44 @@
 return OpenLayers.Lang.code;},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];}
 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}
+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;},translate:function(key,context){var dictionary=OpenLayers.Lang[OpenLayers.Lang.getCode()];var message=dictionary[key];if(!message){message=key;}
 if(context){message=OpenLayers.String.format(message,context);}
-return message;}};OpenLayers.i18n=OpenLayers.Lang.translate;OpenLayers.Popup=OpenLayers.Class({events:null,id:"",lonlat:null,div:null,size:null,contentHTML:"",backgroundColor:"",opacity:"",border:"",contentDiv:null,groupDiv:null,closeDiv:null,padding:5,map:null,initialize:function(id,lonlat,size,contentHTML,closeBox,closeBoxCallback){if(id==null){id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");}
+return message;}};OpenLayers.i18n=OpenLayers.Lang.translate;OpenLayers.Popup=OpenLayers.Class({events:null,id:"",lonlat:null,div:null,size:null,contentHTML:"",backgroundColor:"",opacity:"",border:"",contentDiv:null,groupDiv:null,closeDiv:null,autoSize:false,minSize:null,maxSize:null,padding:0,fixPadding:function(){if(typeof this.padding=="number"){this.padding=new OpenLayers.Bounds(this.padding,this.padding,this.padding,this.padding);}},panMapIfOutOfView:false,map:null,initialize:function(id,lonlat,size,contentHTML,closeBox,closeBoxCallback){if(id==null){id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");}
 this.id=id;this.lonlat=lonlat;this.size=(size!=null)?size: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='olPopup';this.groupDiv=OpenLayers.Util.createDiv(null,null,null,null,"relative",null,"hidden");var id=this.div.id+"_contentDiv";this.contentDiv=OpenLayers.Util.createDiv(id,null,this.size.clone(),null,"relative",null,"hidden");this.contentDiv.className='olPopupContent';this.groupDiv.appendChild(this.contentDiv);this.div.appendChild(this.groupDiv);if(closeBox){var closeSize=new OpenLayers.Size(17,17);var img=OpenLayers.Util.getImagesLocation()+"close.gif";this.closeDiv=OpenLayers.Util.createAlphaImageDiv(this.id+"_close",null,closeSize,img);this.closeDiv.style.right=this.padding+"px";this.closeDiv.style.top=this.padding+"px";this.groupDiv.appendChild(this.closeDiv);var closePopup=closeBoxCallback||function(e){this.hide();OpenLayers.Event.stop(e);};OpenLayers.Event.observe(this.closeDiv,"click",OpenLayers.Function.bindAsEventListener(closePopup,this));}
-this.registerEvents();},destroy:function(){if(this.map!=null){this.map.removePopup(this);this.map=null;}
-this.events.destroy();this.events=null;this.div=null;},draw:function(px){if(px==null){if((this.lonlat!=null)&&(this.map!=null)){px=this.map.getLayerPxFromLonLat(this.lonlat);}}
-this.setSize();this.setBackgroundColor();this.setOpacity();this.setBorder();this.setContentHTML();this.moveTo(px);return this.div;},updatePosition:function(){if((this.lonlat)&&(this.map)){var px=this.map.getLayerPxFromLonLat(this.lonlat);if(px){this.moveTo(px);}}},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},visible:function(){return OpenLayers.Element.visible(this.div);},toggle:function(){OpenLayers.Element.toggle(this.div);},show:function(){OpenLayers.Element.show(this.div);},hide:function(){OpenLayers.Element.hide(this.div);},setSize:function(size){if(size!=undefined){this.size=size;}
+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='olPopup';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.size.clone(),null,"relative");this.contentDiv.className='olPopupContent';this.groupDiv.appendChild(this.contentDiv);this.div.appendChild(this.groupDiv);if(closeBox){this.addCloseBox(closeBoxCallback);}
+this.registerEvents();},destroy:function(){this.id=null;this.lonlat=null;this.size=null;this.contentHTML=null;this.backgroundColor=null;this.opacity=null;this.border=null;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;},draw:function(px){if(px==null){if((this.lonlat!=null)&&(this.map!=null)){px=this.map.getLayerPxFromLonLat(this.lonlat);}}
+if(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.setSize(this.size);}
+this.setBackgroundColor();this.setOpacity();this.setBorder();this.setContentHTML();if(this.panMapIfOutOfView){this.panIntoView();}
+return this.div;},updatePosition:function(){if((this.lonlat)&&(this.map)){var px=this.map.getLayerPxFromLonLat(this.lonlat);if(px){this.moveTo(px);}}},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},visible:function(){return OpenLayers.Element.visible(this.div);},toggle:function(){if(this.visible()){this.hide();}else{this.show();}},show:function(){OpenLayers.Element.show(this.div);if(this.panMapIfOutOfView){this.panIntoView();}},hide:function(){OpenLayers.Element.hide(this.div);},setSize:function(size){this.size=size;var contentSize=this.size.clone();var contentDivPadding=this.getContentDivPadding();var wPadding=contentDivPadding.left+contentDivPadding.right;var hPadding=contentDivPadding.top+contentDivPadding.bottom;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;}
+this.size.w+=wPadding;this.size.h+=hPadding;if(OpenLayers.Util.getBrowserName()=="msie"){contentSize.w+=contentDivPadding.left+contentDivPadding.right;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=this.size.w+"px";this.contentDiv.style.height=this.size.h+"px";}},setBackgroundColor:function(color){if(color!=undefined){this.backgroundColor=color;}
+if(this.contentDiv!=null){this.contentDiv.style.width=contentSize.w+"px";this.contentDiv.style.height=contentSize.h+"px";}},setBackgroundColor:function(color){if(color!=undefined){this.backgroundColor=color;}
 if(this.div!=null){this.div.style.backgroundColor=this.backgroundColor;}},setOpacity:function(opacity){if(opacity!=undefined){this.opacity=opacity;}
 if(this.div!=null){this.div.style.opacity=this.opacity;this.div.style.filter='alpha(opacity='+this.opacity*100+')';}},setBorder:function(border){if(border!=undefined){this.border=border;}
 if(this.div!=null){this.div.style.border=this.border;}},setContentHTML:function(contentHTML){if(contentHTML!=null){this.contentHTML=contentHTML;}
-if(this.contentDiv!=null){this.contentDiv.innerHTML=this.contentHTML;}},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});},onmousedown:function(evt){this.mousedown=true;OpenLayers.Event.stop(evt,true);},onmousemove:function(evt){if(this.mousedown){OpenLayers.Event.stop(evt,true);}},onmouseup:function(evt){if(this.mousedown){this.mousedown=false;OpenLayers.Event.stop(evt,true);}},onclick:function(evt){OpenLayers.Event.stop(evt,true);},onmouseout:function(evt){this.mousedown=false;},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.Renderer=OpenLayers.Class({container:null,extent:null,size:null,resolution:null,map:null,initialize:function(containerID){this.container=OpenLayers.Util.getElement(containerID);},destroy:function(){this.container=null;this.extent=null;this.size=null;this.resolution=null;this.map=null;},supported:function(){return false;},setExtent:function(extent){this.extent=extent.clone();this.resolution=null;},setSize:function(size){this.size=size.clone();this.resolution=null;},getResolution:function(){this.resolution=this.resolution||this.map.getResolution();return this.resolution;},drawFeature:function(feature,style){if(style==null){style=feature.style;}
+if(this.autoSize){var realSize=OpenLayers.Util.getRenderedDimensions(this.contentHTML);var safeSize=this.getSafeContentSize(realSize);var newSize=null;if(safeSize.equals(realSize)){newSize=realSize;}else{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){newSize=safeSize;}else{var clippedSize=OpenLayers.Util.getRenderedDimensions(this.contentHTML,fixedSize);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);}
+if(this.contentDiv!=null){this.contentDiv.innerHTML=this.contentHTML;}},getSafeContentSize:function(size){var safeContentSize=size.clone();var contentDivPadding=this.getContentDivPadding();var wPadding=contentDivPadding.left+contentDivPadding.right;var hPadding=contentDivPadding.top+contentDivPadding.bottom;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;}
+if(this.minSize){safeContentSize.w=Math.max(safeContentSize.w,(this.minSize.w-wPadding));safeContentSize.h=Math.max(safeContentSize.h,(this.minSize.h-hPadding));}
+if(this.maxSize){safeContentSize.w=Math.min(safeContentSize.w,(this.maxSize.w-wPadding));safeContentSize.h=Math.min(safeContentSize.h,(this.maxSize.h-hPadding));}
+if(this.map&&this.map.size){var maxY=this.map.size.h-
+this.map.paddingForPopups.top-
+this.map.paddingForPopups.bottom-
+hPadding;var maxX=this.map.size.w-
+this.map.paddingForPopups.left-
+this.map.paddingForPopups.right-
+wPadding;safeContentSize.w=Math.min(safeContentSize.w,maxX);safeContentSize.h=Math.min(safeContentSize.h,maxY);}
+return safeContentSize;},getContentDivPadding:function(){var contentDivPadding=this._contentDivPadding;if(!contentDivPadding){this.div.style.display="none";document.body.appendChild(this.div);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"));this._contentDivPadding=contentDivPadding;document.body.removeChild(this.div);this.div.style.display="";}
+return contentDivPadding;},addCloseBox:function(callback){this.closeDiv=OpenLayers.Util.createDiv(this.id+"_close",null,new OpenLayers.Size(17,17));this.closeDiv.className="olPopupCloseBox";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));},panIntoView:function(){var mapSize=this.map.getSize();var origTL=this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel(parseInt(this.div.style.left),parseInt(this.div.style.top)));var newTL=origTL.clone();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;}
+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);},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});},onmousedown:function(evt){this.mousedown=true;OpenLayers.Event.stop(evt,true);},onmousemove:function(evt){if(this.mousedown){OpenLayers.Event.stop(evt,true);}},onmouseup:function(evt){if(this.mousedown){this.mousedown=false;OpenLayers.Event.stop(evt,true);}},onclick:function(evt){OpenLayers.Event.stop(evt,true);},onmouseout:function(evt){this.mousedown=false;},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.Renderer=OpenLayers.Class({container:null,extent:null,size:null,resolution:null,map:null,initialize:function(containerID){this.container=OpenLayers.Util.getElement(containerID);},destroy:function(){this.container=null;this.extent=null;this.size=null;this.resolution=null;this.map=null;},supported:function(){return false;},setExtent:function(extent){this.extent=extent.clone();this.resolution=null;},setSize:function(size){this.size=size.clone();this.resolution=null;},getResolution:function(){this.resolution=this.resolution||this.map.getResolution();return this.resolution;},drawFeature:function(feature,style){if(style==null){style=feature.style;}
 if(feature.geometry){this.drawGeometry(feature.geometry,style,feature.id);}},drawGeometry:function(geometry,style,featureId){},clear:function(){},getFeatureIdFromEvent:function(evt){},eraseFeatures:function(features){if(!(features instanceof Array)){features=[features];}
 for(var i=0;i<features.length;++i){this.eraseGeometry(features[i].geometry);}},eraseGeometry:function(geometry){},CLASS_NAME:"OpenLayers.Renderer"});OpenLayers.Tween=OpenLayers.Class({INTERVAL:10,easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,interval:null,playing:false,initialize:function(easing){this.easing=(easing)?easing:OpenLayers.Easing.Expo.easeOut;},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);}
@@ -308,7 +336,7 @@
 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;}
 if(delta){e.xy=this.mousePosition;if(delta<0){this.defaultWheelDown(e);}else{this.defaultWheelUp(e);}}
 OpenLayers.Event.stop(e);}},CLASS_NAME:"OpenLayers.Control.MouseDefaults"});OpenLayers.Control.MousePosition=OpenLayers.Class(OpenLayers.Control,{element:null,prefix:'',separator:', ',suffix:'',numdigits:5,granularity:10,lastXy:null,displayProjection:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){if(this.map){this.map.events.unregister('mousemove',this,this.redraw);}
-OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.div.left="";this.div.top="";this.div.className=this.displayClass;this.element=this.div;}
+OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.div.left="";this.div.top="";this.element=this.div;}
 this.redraw();return this.div;},redraw:function(evt){var lonLat;if(evt==null){lonLat=new OpenLayers.LonLat(0,0);}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){return;}
@@ -349,15 +377,15 @@
 this.redraw();}},onClick:function(ctrl,evt){OpenLayers.Event.stop(evt?evt:window.event);this.activateControl(ctrl);},getControlsBy:function(property,match){var test=(typeof match.test=="function");var found=OpenLayers.Array.filter(this.controls,function(item){return item[property]==match||(test&&match.test(item[property]));});return found;},getControlsByName:function(match){return this.getControlsBy("name",match);},getControlsByClass:function(match){return this.getControlsBy("CLASS_NAME",match);},CLASS_NAME:"OpenLayers.Control.Panel"});OpenLayers.Control.Permalink=OpenLayers.Class(OpenLayers.Control,{element:null,base:'',displayProjection:null,initialize:function(element,base,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.element=OpenLayers.Util.getElement(element);this.base=base||document.location.href;},destroy:function(){if(this.element.parentNode==this.div){this.div.removeChild(this.element);}
 this.element=null;this.map.events.unregister('moveend',this,this.updateLink);OpenLayers.Control.prototype.destroy.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var i=0;i<this.map.controls.length;i++){var control=this.map.controls[i];if(control.CLASS_NAME=="OpenLayers.Control.ArgParser"){if(control.displayProjection!=this.displayProjection){this.displayProjection=control.displayProjection;}
 break;}}
-if(i==this.map.controls.length){this.map.addControl(new OpenLayers.Control.ArgParser({'displayProjection':this.displayProjection}));}},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.div.className=this.displayClass;this.element=document.createElement("a");this.element.innerHTML=OpenLayers.i18n("permalink");this.element.href="";this.div.appendChild(this.element);}
+if(i==this.map.controls.length){this.map.addControl(new OpenLayers.Control.ArgParser({'displayProjection':this.displayProjection}));}},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.element=document.createElement("a");this.element.innerHTML=OpenLayers.i18n("permalink");this.element.href="";this.div.appendChild(this.element);}
 this.map.events.on({'moveend':this.updateLink,'changelayer':this.updateLink,'changebaselayer':this.updateLink,scope:this});return this.div;},updateLink:function(){var center=this.map.getCenter();if(!center){return;}
 var params=OpenLayers.Util.getParameters(this.base);params.zoom=this.map.getZoom();var lat=center.lat;var lon=center.lon;if(this.displayProjection){var mapPosition=OpenLayers.Projection.transform({x:lon,y:lat},this.map.getProjectionObject(),this.displayProjection);lon=mapPosition.x;lat=mapPosition.y;}
 params.lat=Math.round(lat*100000)/100000;params.lon=Math.round(lon*100000)/100000;params.layers='';for(var i=0;i<this.map.layers.length;i++){var layer=this.map.layers[i];if(layer.isBaseLayer){params.layers+=(layer==this.map.baseLayer)?"B":"0";}else{params.layers+=(layer.getVisibility())?"T":"F";}}
 var href=this.base;if(href.indexOf('?')!=-1){href=href.substring(0,href.indexOf('?'));}
-href+='?'+OpenLayers.Util.getParameterString(params);this.element.href=href;},CLASS_NAME:"OpenLayers.Control.Permalink"});OpenLayers.Control.Scale=OpenLayers.Class(OpenLayers.Control,{element:null,initialize:function(element,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.element=OpenLayers.Util.getElement(element);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.element=document.createElement("div");this.div.className=this.displayClass;this.div.appendChild(this.element);}
+href+='?'+OpenLayers.Util.getParameterString(params);this.element.href=href;},CLASS_NAME:"OpenLayers.Control.Permalink"});OpenLayers.Control.Scale=OpenLayers.Class(OpenLayers.Control,{element:null,initialize:function(element,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.element=OpenLayers.Util.getElement(element);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.element=document.createElement("div");this.div.appendChild(this.element);}
 this.map.events.register('moveend',this,this.updateScale);this.updateScale();return this.div;},updateScale:function(){var scale=this.map.getScale();if(!scale){return;}
 if(scale>=9500&&scale<=950000){scale=Math.round(scale/1000)+"K";}else if(scale>=950000){scale=Math.round(scale/1000000)+"M";}else{scale=Math.round(scale);}
-this.element.innerHTML=OpenLayers.i18n("scale",{'scaleDenom':scale});},CLASS_NAME:"OpenLayers.Control.Scale"});OpenLayers.Control.ScaleLine=OpenLayers.Class(OpenLayers.Control,{maxWidth:100,topOutUnits:"km",topInUnits:"m",bottomOutUnits:"mi",bottomInUnits:"ft",eTop:null,eBottom:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,[options]);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.eTop){this.div.className=this.displayClass;this.div.style.display="block";this.div.style.position="absolute";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";}
+this.element.innerHTML=OpenLayers.i18n("scale",{'scaleDenom':scale});},CLASS_NAME:"OpenLayers.Control.Scale"});OpenLayers.Control.ScaleLine=OpenLayers.Class(OpenLayers.Control,{maxWidth:100,topOutUnits:"km",topInUnits:"m",bottomOutUnits:"mi",bottomInUnits:"ft",eTop:null,eBottom:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,[options]);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.eTop){this.div.style.display="block";this.div.style.position="absolute";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";}
 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";}}
 this.map.events.register('moveend',this,this.update);this.update();return this.div;},getBarLen:function(maxLen){var digits=parseInt(Math.log(maxLen)/Math.log(10));var pow10=Math.pow(10,digits);var firstChar=parseInt(maxLen/pow10);var barLen;if(firstChar>5){barLen=5;}else if(firstChar>2){barLen=2;}else{barLen=1;}
 return barLen*pow10;},update:function(){var res=this.map.getResolution();if(!res){return;}
@@ -389,8 +417,7 @@
 return continueChain;},handleBrowserEvent:function(evt){evt.xy=this.getMousePosition(evt);this.triggerEvent(evt.type,evt);},getMousePosition:function(evt){if(!this.element.offsets){this.element.offsets=OpenLayers.Util.pagePosition(this.element);this.element.offsets[0]+=(document.documentElement.scrollLeft||document.body.scrollLeft);this.element.offsets[1]+=(document.documentElement.scrollTop||document.body.scrollTop);}
 return new OpenLayers.Pixel((evt.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft))-this.element.offsets[0]
 -(document.documentElement.clientLeft||0),(evt.clientY+(document.documentElement.scrollTop||document.body.scrollTop))-this.element.offsets[1]
--(document.documentElement.clientTop||0));},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Format=OpenLayers.Class({externalProjection:null,internalProjection:null,initialize:function(options){OpenLayers.Util.extend(this,options);},read:function(data){alert(OpenLayers.i18n("readNotImplemented"));},write:function(object){alert(OpenLayers.i18n("writeNotImplemented"));},CLASS_NAME:"OpenLayers.Format"});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}",'getFeatureError':"getFeatureFromEvent called on layer with no renderer. This usually means you "+"destroyed a layer, but not some handler which is associated with it.",'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 either 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}",'layerAlreadyAdded':"You tried to add the layer: ${layerName} to the map, but it has already been added",'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.",'methodDeprecated':"This method has been deprecated and will be removed in 3.0. "+"Please use ${newMethod} instead.",'boundsAddError':"You must pass both x and y values to the add function.",'lonlatAddError':"You must pass both lon and lat values to the add function.",'pixelAddError':"You must pass both x and y values to the add function.",'unsupportedGeometryType':"Unsupported geometry type: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",'end':''};OpenLayers.Popup.Anchored=OpenLayers.Class(OpenLayers.Popup,{relativePosition:null,anchor:null,initialize:function(id,lonlat,size,contentHTML,anchor,closeBox,closeBoxCallback){var newArguments=new Array(id,lonlat,size,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)};},draw:function(px){if(px==null){if((this.lonlat!=null)&&(this.map!=null)){px=this.map.getLayerPxFromLonLat(this.lonlat);}}
-this.relativePosition=this.calculateRelativePosition(px);return OpenLayers.Popup.prototype.draw.apply(this,arguments);},calculateRelativePosition:function(px){var lonlat=this.map.getLonLatFromLayerPx(px);var extent=this.map.getExtent();var quadrant=extent.determineQuadrant(lonlat);return OpenLayers.Bounds.oppositeQuadrant(quadrant);},moveTo:function(px){this.relativePosition=this.calculateRelativePosition(px);var newPx=this.calculateNewPx(px);var newArguments=new Array(newPx);OpenLayers.Popup.prototype.moveTo.apply(this,newArguments);},setSize:function(size){OpenLayers.Popup.prototype.setSize.apply(this,arguments);if((this.lonlat)&&(this.map)){var px=this.map.getLayerPxFromLonLat(this.lonlat);this.moveTo(px);}},calculateNewPx:function(px){var newPx=px.offset(this.anchor.offset);var top=(this.relativePosition.charAt(0)=='t');newPx.y+=(top)?-this.size.h:this.anchor.size.h;var left=(this.relativePosition.charAt(1)=='l');newPx.x+=(left)?-this.size.w:this.anchor.size.w;return newPx;},CLASS_NAME:"OpenLayers.Popup.Anchored"});OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,initialize:function(projCode,options){OpenLayers.Util.extend(this,options);this.projCode=projCode;if(window.Proj4js){this.proj=new Proj4js.Proj(projCode);}},getCode:function(){return this.proj?this.proj.srsCode:this.projCode;},getUnits:function(){return this.proj?this.proj.units:null;},toString:function(){return this.getCode();},equals:function(projection){if(projection&&projection.getCode){return this.getCode()==projection.getCode();}else{return false;}},destroy:function(){delete this.proj;delete this.projCode;},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={};OpenLayers.Projection.addTransform=function(from,to,method){if(!OpenLayers.Projection.transforms[from]){OpenLayers.Projection.transforms[from]={};}
+-(document.documentElement.clientTop||0));},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Format=OpenLayers.Class({externalProjection:null,internalProjection:null,initialize:function(options){OpenLayers.Util.extend(this,options);},read:function(data){alert(OpenLayers.i18n("readNotImplemented"));},write:function(object){alert(OpenLayers.i18n("writeNotImplemented"));},CLASS_NAME:"OpenLayers.Format"});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}",'getFeatureError':"getFeatureFromEvent called on layer with no renderer. This usually means you "+"destroyed a layer, but not some handler which is associated with it.",'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 either 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}",'layerAlreadyAdded':"You tried to add the layer: ${layerName} to the map, but it has already been added",'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.",'methodDeprecated':"This method has been deprecated and will be removed in 3.0. "+"Please use ${newMethod} instead.",'boundsAddError':"You must pass both x and y values to the add function.",'lonlatAddError':"You must pass both lon and lat values to the add function.",'pixelAddError':"You must pass both x and y values to the add function.",'unsupportedGeometryType':"Unsupported geometry type: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",'end':''};OpenLayers.Popup.Anchored=OpenLayers.Class(OpenLayers.Popup,{relativePosition:null,anchor:null,initialize:function(id,lonlat,size,contentHTML,anchor,closeBox,closeBoxCallback){var newArguments=new Array(id,lonlat,size,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)};},destroy:function(){this.anchor=null;this.relativePosition=null;OpenLayers.Popup.prototype.destroy.apply(this,arguments);},show:function(){this.updatePosition();OpenLayers.Popup.prototype.show.apply(this,arguments);},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.relativePosition!=oldRelativePosition){this.updateRelativePosition();}},setSize:function(size){OpenLayers.Popup.prototype.setSize.apply(this,arguments);if((this.lonlat)&&(this.map)){var px=this.map.getLayerPxFromLonLat(this.lonlat);this.moveTo(px);}},calculateRelativePosition:function(px){var lonlat=this.map.getLonLatFromLayerPx(px);var extent=this.map.getExtent();var quadrant=extent.determineQuadrant(lonlat);return OpenLayers.Bounds.oppositeQuadrant(quadrant);},updateRelativePosition:function(){},calculateNewPx:function(px){var newPx=px.offset(this.anchor.offset);var top=(this.relativePosition.charAt(0)=='t');newPx.y+=(top)?-this.size.h:this.anchor.size.h;var left=(this.relativePosition.charAt(1)=='l');newPx.x+=(left)?-this.size.w:this.anchor.size.w;return newPx;},CLASS_NAME:"OpenLayers.Popup.Anchored"});OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,initialize:function(projCode,options){OpenLayers.Util.extend(this,options);this.projCode=projCode;if(window.Proj4js){this.proj=new Proj4js.Proj(projCode);}},getCode:function(){return this.proj?this.proj.srsCode:this.projCode;},getUnits:function(){return this.proj?this.proj.units:null;},toString:function(){return this.getCode();},equals:function(projection){if(projection&&projection.getCode){return this.getCode()==projection.getCode();}else{return false;}},destroy:function(){delete this.proj;delete this.projCode;},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={};OpenLayers.Projection.addTransform=function(from,to,method){if(!OpenLayers.Projection.transforms[from]){OpenLayers.Projection.transforms[from]={};}
 OpenLayers.Projection.transforms[from][to]=method;};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.Renderer.Elements=OpenLayers.Class(OpenLayers.Renderer,{rendererRoot:null,root:null,xmlns:null,minimumSymbolizer:{strokeLinecap:"round",strokeOpacity:1,fillOpacity:1,pointRadius:0},initialize:function(containerID){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.rendererRoot=this.createRenderRoot();this.root=this.createRoot();this.rendererRoot.appendChild(this.root);this.container.appendChild(this.rendererRoot);},destroy:function(){this.clear();this.rendererRoot=null;this.root=null;this.xmlns=null;OpenLayers.Renderer.prototype.destroy.apply(this,arguments);},clear:function(){if(this.root){while(this.root.childNodes.length>0){this.root.removeChild(this.root.firstChild);}}},getNodeType:function(geometry,style){},drawGeometry:function(geometry,style,featureId){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,featureId);}
 return;};if(style.display!="none"){var nodeType=this.getNodeType(geometry,style);var node=this.nodeFactory(geometry.id,nodeType);node._featureId=featureId;node._geometryClass=geometry.CLASS_NAME;node._style=style;node=this.drawGeometryNode(node,geometry);if(node.parentNode!=this.root){this.root.appendChild(node);}
@@ -479,7 +506,7 @@
 var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0;i<events.length;i++){if(this[events[i]]){this.register(events[i],this[events[i]]);}}
 this.active=true;return true;},deactivate:function(){if(!this.active){return false;}
 var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0;i<events.length;i++){if(this[events[i]]){this.unregister(events[i],this[events[i]]);}}
-this.active=false;return true;},callback:function(name,args){if(name&&this.callbacks[name]){this.callbacks[name].apply(this.control,args);}},register:function(name,method){this.map.events.registerPriority(name,this,method);this.map.events.registerPriority(name,this,this.setEvent);},unregister:function(name,method){this.map.events.unregister(name,this,method);this.map.events.unregister(name,this,this.setEvent);},setEvent:function(evt){this.evt=evt;return true;},destroy:function(){this.deactivate();this.control=this.map=null;},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Popup:750,Control:1000},EVENT_TYPES:["preaddlayer","addlayer","removelayer","changelayer","movestart","move","moveend","zoomend","popupopen","popupclose","addmarker","removemarker","clearmarkers","mouseover","mouseout","mousemove","dragstart","drag","dragend","changebaselayer"],id:null,fractionalZoom:false,events:null,div:null,dragging:false,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,resolution:null,zoom:0,viewRequestID:0,tileSize:null,projection:"EPSG:4326",units:'degrees',resolutions:null,maxResolution:1.40625,minResolution:null,maxScale:null,minScale:null,maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,fallThrough:true,panTween:null,eventListeners:null,panMethod:OpenLayers.Easing.Expo.easeOut,initialize:function(div,options){this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.maxExtent=new OpenLayers.Bounds(-180,-90,180,90);this.theme=OpenLayers._getScriptLocation()+'theme/default/style.css';OpenLayers.Util.extend(this,options);this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(div);var id=this.div.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(id,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);id=this.div.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(id);this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;this.viewPortDiv.appendChild(this.layerContainerDiv);this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES,this.fallThrough);this.updateSize();if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}
+this.active=false;return true;},callback:function(name,args){if(name&&this.callbacks[name]){this.callbacks[name].apply(this.control,args);}},register:function(name,method){this.map.events.registerPriority(name,this,method);this.map.events.registerPriority(name,this,this.setEvent);},unregister:function(name,method){this.map.events.unregister(name,this,method);this.map.events.unregister(name,this,this.setEvent);},setEvent:function(evt){this.evt=evt;return true;},destroy:function(){this.deactivate();this.control=this.map=null;},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Popup:750,Control:1000},EVENT_TYPES:["preaddlayer","addlayer","removelayer","changelayer","movestart","move","moveend","zoomend","popupopen","popupclose","addmarker","removemarker","clearmarkers","mouseover","mouseout","mousemove","dragstart","drag","dragend","changebaselayer"],id:null,fractionalZoom:false,events:null,div:null,dragging:false,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,resolution:null,zoom:0,viewRequestID:0,tileSize:null,projection:"EPSG:4326",units:'degrees',resolutions:null,maxResolution:1.40625,minResolution:null,maxScale:null,minScale:null,maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,fallThrough:true,panTween:null,eventListeners:null,panMethod:OpenLayers.Easing.Expo.easeOut,paddingForPopups:null,initialize:function(div,options){this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.maxExtent=new OpenLayers.Bounds(-180,-90,180,90);this.paddingForPopups=new OpenLayers.Bounds(15,15,15,15);this.theme=OpenLayers._getScriptLocation()+'theme/default/style.css';OpenLayers.Util.extend(this,options);this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(div);var id=this.div.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(id,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);id=this.div.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(id);this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;this.viewPortDiv.appendChild(this.layerContainerDiv);this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES,this.fallThrough);this.updateSize();if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}
 this.events.register("movestart",this,this.updateSize);if(OpenLayers.String.contains(navigator.appName,"Microsoft")){this.events.register("resize",this,this.updateSize);}else{this.updateSizeDestroy=OpenLayers.Function.bind(this.updateSize,this);OpenLayers.Event.observe(window,'resize',this.updateSizeDestroy);}
 if(this.theme){var addNode=true;var nodes=document.getElementsByTagName('link');for(var i=0;i<nodes.length;++i){if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,this.theme)){addNode=false;break;}}
 if(addNode){var cssNode=document.createElement('link');cssNode.setAttribute('rel','stylesheet');cssNode.setAttribute('type','text/css');cssNode.setAttribute('href',this.theme);document.getElementsByTagName('head')[0].appendChild(cssNode);}}
@@ -487,7 +514,7 @@
 for(var i=0;i<this.controls.length;i++){this.addControlToMap(this.controls[i]);}
 this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,'unload',this.unloadDestroy);},unloadDestroy:null,updateSizeDestroy:null,destroy:function(){if(!this.unloadDestroy){return false;}
 OpenLayers.Event.stopObserving(window,'unload',this.unloadDestroy);this.unloadDestroy=null;if(this.updateSizeDestroy){OpenLayers.Event.stopObserving(window,'resize',this.updateSizeDestroy);}else{this.events.unregister("resize",this,this.updateSize);}
-if(this.controls!=null){for(var i=this.controls.length-1;i>=0;--i){this.controls[i].destroy();}
+this.paddingForPopups=null;if(this.controls!=null){for(var i=this.controls.length-1;i>=0;--i){this.controls[i].destroy();}
 this.controls=null;}
 if(this.layers!=null){for(var i=this.layers.length-1;i>=0;--i){this.layers[i].destroy(false);}
 this.layers=null;}
@@ -567,8 +594,18 @@
 return layerPx;},getLonLatFromLayerPx:function(px){px=this.getViewPortPxFromLayerPx(px);return this.getLonLatFromViewPortPx(px);},getLayerPxFromLonLat:function(lonlat){var px=this.getViewPortPxFromLonLat(lonlat);return this.getLayerPxFromViewPortPx(px);},CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,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);},destroy:function(){this.map=null;this.events.destroy();this.events=null;if(this.icon!=null){this.icon.destroy();this.icon=null;}},draw:function(px){return this.icon.draw(px);},moveTo:function(px){if((px!=null)&&(this.icon!=null)){this.icon.moveTo(px);}
 this.lonlat=this.map.getLonLatFromLayerPx(px);},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
-return onScreen;},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);}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},setUrl:function(url){this.icon.setUrl(url);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.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.Popup.AnchoredBubble=OpenLayers.Class(OpenLayers.Popup.Anchored,{rounded:false,initialize:function(id,lonlat,size,contentHTML,anchor,closeBox,closeBoxCallback){OpenLayers.Popup.Anchored.prototype.initialize.apply(this,arguments);},draw:function(px){OpenLayers.Popup.Anchored.prototype.draw.apply(this,arguments);this.setContentHTML();this.setBackgroundColor();this.setOpacity();return this.div;},moveTo:function(px){OpenLayers.Popup.Anchored.prototype.moveTo.apply(this,arguments);this.setRicoCorners(!this.rounded);this.rounded=true;},setSize:function(size){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);if(this.contentDiv!=null){var contentSize=this.size.clone();contentSize.h-=(2*OpenLayers.Popup.AnchoredBubble.CORNER_SIZE);contentSize.h-=(2*this.padding);this.contentDiv.style.height=contentSize.h+"px";this.contentDiv.style.width=contentSize.w+"px";if(this.map){this.setRicoCorners(!this.rounded);this.rounded=true;}}},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.contentDiv,this.backgroundColor);}}},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);}}},setBorder:function(border){this.border=0;},setRicoCorners:function(firstTime){var corners=this.getCornersToRound(this.relativePosition);var options={corners:corners,color:this.backgroundColor,bgColor:"transparent",blend:false};if(firstTime){OpenLayers.Rico.Corner.round(this.div,options);}else{OpenLayers.Rico.Corner.reRound(this.groupDiv,options);this.setBackgroundColor();this.setOpacity();}},getCornersToRound:function(){var corners=['tl','tr','bl','br'];var corner=OpenLayers.Bounds.oppositeQuadrant(this.relativePosition);OpenLayers.Util.removeItem(corners,corner);return corners.join(" ");},CLASS_NAME:"OpenLayers.Popup.AnchoredBubble"});OpenLayers.Popup.AnchoredBubble.CORNER_SIZE=5;OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",MAX_PIXEL:15000,localResolution:null,initialize:function(containerID){if(!this.supported()){return;}
+return onScreen;},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);}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},setUrl:function(url){this.icon.setUrl(url);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.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.Popup.AnchoredBubble=OpenLayers.Class(OpenLayers.Popup.Anchored,{rounded:false,initialize:function(id,lonlat,size,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);},draw:function(px){OpenLayers.Popup.Anchored.prototype.draw.apply(this,arguments);this.setContentHTML();this.setBackgroundColor();this.setOpacity();return this.div;},updateRelativePosition:function(){this.setRicoCorners();},setSize:function(size){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);this.setRicoCorners();},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);}}},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);}}},setBorder:function(border){this.border=0;},setRicoCorners:function(){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);this.setBackgroundColor();this.setOpacity();}},getCornersToRound:function(){var corners=['tl','tr','bl','br'];var corner=OpenLayers.Bounds.oppositeQuadrant(this.relativePosition);OpenLayers.Util.removeItem(corners,corner);return corners.join(" ");},CLASS_NAME:"OpenLayers.Popup.AnchoredBubble"});OpenLayers.Popup.AnchoredBubble.CORNER_SIZE=5;OpenLayers.Popup.Framed=OpenLayers.Class(OpenLayers.Popup.Anchored,{imageSrc:null,imageSize:null,isAlphaImage:false,positionBlocks:null,blocks:null,fixedRelativePosition:false,initialize:function(id,lonlat,size,contentHTML,anchor,closeBox,closeBoxCallback){OpenLayers.Popup.Anchored.prototype.initialize.apply(this,arguments);if(this.fixedRelativePosition){this.updateRelativePosition();this.calculateRelativePosition=function(px){return this.relativePosition;};}
+this.contentDiv.style.position="absolute";this.contentDiv.style.zIndex=1;if(closeBox){this.closeDiv.style.zIndex=1;}
+this.groupDiv.style.position="absolute";this.groupDiv.style.top="0px";this.groupDiv.style.left="0px";this.groupDiv.style.height="100%";this.groupDiv.style.width="100%";},destroy:function(){this.imageSrc=null;this.imageSize=null;this.isAlphaImage=null;this.fixedRelativePosition=false;this.positionBlocks=null;for(var i=0;i<this.blocks.length;i++){var block=this.blocks[i];if(block.image){block.div.removeChild(block.image);}
+block.image=null;if(block.div){this.groupDiv.removeChild(block.div);}
+block.div=null;}
+this.blocks=null;OpenLayers.Popup.Anchored.prototype.destroy.apply(this,arguments);},setBackgroundColor:function(color){},setBorder:function(){},setOpacity:function(opacity){},setSize:function(size){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);this.updateBlocks();},updateRelativePosition:function(){this.padding=this.positionBlocks[this.relativePosition].padding;if(this.closeDiv){var contentDivPadding=this.getContentDivPadding();this.closeDiv.style.right=contentDivPadding.right+
+this.padding.right+"px";this.closeDiv.style.top=contentDivPadding.top+
+this.padding.top+"px";}
+this.updateBlocks();},calculateNewPx:function(px){var newPx=OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply(this,arguments);newPx=newPx.offset(this.positionBlocks[this.relativePosition].offset);return newPx;},createBlocks:function(){this.blocks=[];var position=this.positionBlocks[this.relativePosition];for(var i=0;i<position.blocks.length;i++){var block={};this.blocks.push(block);var divId=this.id+'_FrameDecorationDiv_'+i;block.div=OpenLayers.Util.createDiv(divId,null,null,null,"absolute",null,"hidden",null);var imgId=this.id+'_FrameDecorationImg_'+i;var imageCreator=(this.isAlphaImage)?OpenLayers.Util.createAlphaImageDiv:OpenLayers.Util.createImage;block.image=imageCreator(imgId,null,this.imageSize,this.imageSrc,"absolute",null,null,null);block.div.appendChild(block.image);this.groupDiv.appendChild(block.div);}},updateBlocks:function(){if(!this.blocks){this.createBlocks();}
+var position=this.positionBlocks[this.relativePosition];for(var i=0;i<position.blocks.length;i++){var positionBlock=position.blocks[i];var block=this.blocks[i];var l=positionBlock.anchor.left;var b=positionBlock.anchor.bottom;var r=positionBlock.anchor.right;var t=positionBlock.anchor.top;var w=(isNaN(positionBlock.size.w))?this.size.w-(r+l):positionBlock.size.w;var h=(isNaN(positionBlock.size.h))?this.size.h-(b+t):positionBlock.size.h;block.div.style.width=w+'px';block.div.style.height=h+'px';block.div.style.left=(l!=null)?l+'px':'';block.div.style.bottom=(b!=null)?b+'px':'';block.div.style.right=(r!=null)?r+'px':'';block.div.style.top=(t!=null)?t+'px':'';block.image.style.left=positionBlock.position.x+'px';block.image.style.top=positionBlock.position.y+'px';}
+this.contentDiv.style.left=this.padding.left+"px";this.contentDiv.style.top=this.padding.top+"px";},CLASS_NAME:"OpenLayers.Popup.Framed"});OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",MAX_PIXEL:15000,localResolution:null,initialize:function(containerID){if(!this.supported()){return;}
 OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments);},destroy:function(){OpenLayers.Renderer.Elements.prototype.destroy.apply(this,arguments);},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")));},inValidRange:function(x,y){return(x>=-this.MAX_PIXEL&&x<=this.MAX_PIXEL&&y>=-this.MAX_PIXEL&&y<=this.MAX_PIXEL);},setExtent:function(extent){OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments);var resolution=this.getResolution();if(!this.localResolution||resolution!=this.localResolution){this.left=-extent.left/resolution;this.top=extent.top/resolution;}
 var left=0;var top=0;if(this.localResolution&&resolution==this.localResolution){left=(this.left)-(-extent.left/resolution);top=(this.top)-(extent.top/resolution);}
 this.localResolution=resolution;var extentString=left+" "+top+" "+
@@ -597,13 +634,13 @@
 fill.setAttribute("opacity",style.fillOpacity);if(node._geometryClass=="OpenLayers.Geometry.Point"&&style.externalGraphic){if(style.graphicOpacity){fill.setAttribute("opacity",style.graphicOpacity);}
 fill.setAttribute("src",style.externalGraphic);fill.setAttribute("type","frame");node.style.flip="y";if(!(style.graphicWidth&&style.graphicHeight)){fill.aspect="atmost";}}
 if(fill.parentNode!=node){node.appendChild(fill);}}
-if(options.isStroked){node.setAttribute("strokecolor",style.strokeColor);node.setAttribute("strokeweight",style.strokeWidth);}else{node.setAttribute("stroked","false");}
+if(options.isStroked){node.setAttribute("strokecolor",style.strokeColor);node.setAttribute("strokeweight",style.strokeWidth+"px");}else{node.setAttribute("stroked","false");}
 var strokes=node.getElementsByTagName("stroke");var stroke=(strokes.length==0)?null:strokes[0];if(!options.isStroked){if(stroke){node.removeChild(stroke);}}else{if(!stroke){stroke=this.createNode('v:stroke',node.id+"_stroke");node.appendChild(stroke);}
 stroke.setAttribute("opacity",style.strokeOpacity);stroke.setAttribute("endcap",!style.strokeLinecap||style.strokeLinecap=='butt'?'flat':style.strokeLinecap);}
 if(style.cursor!=null){node.style.cursor=style.cursor;}
 return node;},postDraw:function(node){var fillColor=node._style.fillColor;var strokeColor=node._style.strokeColor;if(fillColor=="none"&&node.getAttribute("fillcolor")!=fillColor){node.setAttribute("fillcolor",fillColor);}
-if(strokeColor=="none"&&node.getAttribute("strokecolor")!=strokeColor){node.setAttribute("strokecolor",strokeColor)}},setNodeDimension:function(node,geometry){var bbox=geometry.getBounds();if(bbox){var resolution=this.getResolution();var scaledBox=new OpenLayers.Bounds((bbox.left/resolution).toFixed(),(bbox.bottom/resolution).toFixed(),(bbox.right/resolution).toFixed(),(bbox.top/resolution).toFixed());node.style.left=scaledBox.left;node.style.top=scaledBox.top;node.style.width=scaledBox.getWidth();node.style.height=scaledBox.getHeight();node.coordorigin=scaledBox.left+" "+scaledBox.top;node.coordsize=scaledBox.getWidth()+" "+scaledBox.getHeight();}},createNode:function(type,id){var node=document.createElement(type);if(id){node.setAttribute('id',id);}
-return node;},nodeTypeCompare:function(node,type){var subType=type;var splitIndex=subType.indexOf(":");if(splitIndex!=-1){subType=subType.substr(splitIndex+1);}
+if(strokeColor=="none"&&node.getAttribute("strokecolor")!=strokeColor){node.setAttribute("strokecolor",strokeColor);}},setNodeDimension:function(node,geometry){var bbox=geometry.getBounds();if(bbox){var resolution=this.getResolution();var scaledBox=new OpenLayers.Bounds((bbox.left/resolution).toFixed(),(bbox.bottom/resolution).toFixed(),(bbox.right/resolution).toFixed(),(bbox.top/resolution).toFixed());node.style.left=scaledBox.left;node.style.top=scaledBox.top;node.style.width=scaledBox.getWidth();node.style.height=scaledBox.getHeight();node.coordorigin=scaledBox.left+" "+scaledBox.top;node.coordsize=scaledBox.getWidth()+" "+scaledBox.getHeight();}},createNode:function(type,id){var node=document.createElement(type);if(id){node.setAttribute('id',id);}
+node.setAttribute('unselectable','on',0);node.onselectstart=function(){return(false);};return node;},nodeTypeCompare:function(node,type){var subType=type;var splitIndex=subType.indexOf(":");if(splitIndex!=-1){subType=subType.substr(splitIndex+1);}
 var nodeName=node.nodeName;splitIndex=nodeName.indexOf(":");if(splitIndex!=-1){nodeName=nodeName.substr(splitIndex+1);}
 return(subType==nodeName);},createRenderRoot:function(){return this.nodeFactory(this.container.id+"_vmlRoot","div");},createRoot:function(){return this.nodeFactory(this.container.id+"_root","v:group");},drawPoint:function(node,geometry){this.drawCircle(node,geometry,1);},drawCircle:function(node,geometry,radius){if(!isNaN(geometry.x)&&!isNaN(geometry.y)){var resolution=this.getResolution();node.style.left=(geometry.x/resolution).toFixed()-radius;node.style.top=(geometry.y/resolution).toFixed()-radius;var diameter=radius*2;node.style.width=diameter;node.style.height=diameter;}},drawLineString:function(node,geometry){this.drawLine(node,geometry,false);},drawLinearRing:function(node,geometry){this.drawLine(node,geometry,true);},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);y=(comp.y/resolution);parts[i]=" "+x.toFixed()+","+y.toFixed()+" l ";}
 var end=(closeLine)?" x e":" e";node.path="m"+parts.join("")+end;},drawPolygon:function(node,geometry){this.setNodeDimension(node,geometry);var resolution=this.getResolution();var path=[];var linearRing,i,comp,x,y;for(var j=0;j<geometry.components.length;j++){linearRing=geometry.components[j];path.push("m");for(i=0;i<linearRing.components.length;i++){comp=linearRing.components[i];x=comp.x/resolution;y=comp.y/resolution;path.push(" "+x.toFixed()+","+y.toFixed());if(i==0){path.push(" l");}}
@@ -626,7 +663,7 @@
 var ratio=1;if(this.backBufferTile.resolution){ratio=this.backBufferTile.resolution/this.layer.getResolution();}
 if(ratio!=this.lastRatio){if(this.layer.transitionEffect=='resize'){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{if(this.layer.singleTile){this.backBufferTile.show();}else{this.backBufferTile.hide();}}
-this.lastRatio=ratio;},show:function(){this.frame.style.display='';if(navigator.userAgent.toLowerCase().indexOf("gecko")!=-1){this.frame.scrollLeft=this.frame.scrollLeft;}},hide:function(){this.frame.style.display='none';},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Tile.Image.useBlankTile=(OpenLayers.Util.getBrowserName()=="safari"||OpenLayers.Util.getBrowserName()=="opera");OpenLayers.Tile.WFS=OpenLayers.Class(OpenLayers.Tile,{features:null,url:null,request:null,initialize:function(layer,position,bounds,url,size){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=url;this.features=[];},destroy:function(){OpenLayers.Tile.prototype.destroy.apply(this,arguments);this.destroyAllFeatures();this.features=null;this.url=null;if(this.request){this.request.abort();this.request=null;}},clear:function(){this.destroyAllFeatures();},draw:function(){if(OpenLayers.Tile.prototype.draw.apply(this,arguments)){if(this.isLoading){this.events.triggerEvent("reload");}else{this.isLoading=true;this.events.triggerEvent("loadstart");}
+this.lastRatio=ratio;},show:function(){this.frame.style.display='';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;}}},hide:function(){this.frame.style.display='none';},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Tile.Image.useBlankTile=(OpenLayers.Util.getBrowserName()=="safari"||OpenLayers.Util.getBrowserName()=="opera");OpenLayers.Tile.WFS=OpenLayers.Class(OpenLayers.Tile,{features:null,url:null,request:null,initialize:function(layer,position,bounds,url,size){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=url;this.features=[];},destroy:function(){OpenLayers.Tile.prototype.destroy.apply(this,arguments);this.destroyAllFeatures();this.features=null;this.url=null;if(this.request){this.request.abort();this.request=null;}},clear:function(){this.destroyAllFeatures();},draw:function(){if(OpenLayers.Tile.prototype.draw.apply(this,arguments)){if(this.isLoading){this.events.triggerEvent("reload");}else{this.isLoading=true;this.events.triggerEvent("loadstart");}
 this.loadFeaturesForRegion(this.requestSuccess);}},loadFeaturesForRegion:function(success,failure){if(this.request){this.request.abort();}
 this.request=OpenLayers.loadURL(this.url,null,this,success);},requestSuccess:function(request){if(this.features){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=OpenLayers.Format.XML.prototype.read(request.responseText);}
 if(this.layer.vectorMode){this.layer.addFeatures(this.layer.formatObject.read(doc));}else{var resultFeatures=OpenLayers.Ajax.getElementsByTagNameNS(doc,"http://www.opengis.net/gml","gml","featureMember");this.addResults(resultFeatures);}}
@@ -635,7 +672,7 @@
 this.handlers.click.destroy();this.mapDiv.removeChild(this.extentRectangle);this.extentRectangle=null;this.rectEvents.destroy();this.rectEvents=null;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);},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;}}
-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;this.extentRectangle.className=this.displayClass+'ExtentRectangle';this.mapDiv.appendChild(this.extentRectangle);this.element.appendChild(this.mapDiv);this.div.appendChild(this.element);if(!this.outsideViewport){this.div.className=this.displayClass+'Container';var imgLocation=OpenLayers.Util.getImagesLocation();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);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;i<eventsToStop.length;i++){OpenLayers.Event.observe(this.maximizeDiv,eventsToStop[i],OpenLayers.Event.stop);OpenLayers.Event.observe(this.minimizeDiv,eventsToStop[i],OpenLayers.Event.stop);}
+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;this.extentRectangle.className=this.displayClass+'ExtentRectangle';this.mapDiv.appendChild(this.extentRectangle);this.element.appendChild(this.mapDiv);this.div.appendChild(this.element);if(!this.outsideViewport){this.div.className+=" "+this.displayClass+'Container';var imgLocation=OpenLayers.Util.getImagesLocation();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);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;i<eventsToStop.length;i++){OpenLayers.Event.observe(this.maximizeDiv,eventsToStop[i],OpenLayers.Event.stop);OpenLayers.Event.observe(this.minimizeDiv,eventsToStop[i],OpenLayers.Event.stop);}
 this.minimizeControl();}else{this.element.style.display='';}
 if(this.map.getExtent()){this.update();}
 this.map.events.register('moveend',this,this.update);return this.div;},baseLayerDraw:function(){this.draw();this.map.events.unregister("changebaselayer",this,this.baseLayerDraw);},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();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));}},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();},maximizeControl:function(e){this.element.style.display='';this.showToggle(false);if(e!=null){OpenLayers.Event.stop(e);}},minimizeControl:function(e){this.element.style.display='none';this.showToggle(true);if(e!=null){OpenLayers.Event.stop(e);}},showToggle:function(minimize){this.maximizeDiv.style.display=minimize?'':'none';this.minimizeDiv.style.display=minimize?'none':'';},update:function(){if(this.ovmap==null){this.createMap();}
@@ -668,8 +705,7 @@
 var wmc=this.parser.write(obj,options);return wmc;},mapToContext:function(map){var context={bounds:map.getExtent(),maxExtent:map.maxExtent,projection:map.projection,layers:map.layers,size:map.getSize()};return context;},CLASS_NAME:"OpenLayers.Format.WMC"});OpenLayers.Format.WMC.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ol:"http://openlayers.org/context",wmc:"http://www.opengis.net/context",sld:"http://www.opengis.net/sld",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"",getNamespacePrefix:function(uri){var prefix=null;if(uri==null){prefix=this.namespaces[this.defaultPrefix];}else{for(prefix in this.namespaces){if(this.namespaces[prefix]==uri){break;}}}
 return prefix;},defaultPrefix:"wmc",rootPrefix:null,defaultStyleName:"",defaultStyleTitle:"Default",initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
 var root=data.documentElement;this.rootPrefix=root.prefix;var context={version:root.getAttribute("version")};this.runChildNodes(context,root);return context;},runChildNodes:function(obj,node){var children=node.childNodes;var childNode,processor,prefix,local;for(var i=0;i<children.length;++i){childNode=children[i];if(childNode.nodeType==1){prefix=this.getNamespacePrefix(childNode.namespaceURI);local=childNode.nodeName.split(":").pop();processor=this["read_"+prefix+"_"+local];if(processor){processor.apply(this,[obj,childNode]);}}}},read_wmc_General:function(context,node){this.runChildNodes(context,node);},read_wmc_BoundingBox:function(context,node){context.projection=node.getAttribute("SRS");context.bounds=new OpenLayers.Bounds(parseFloat(node.getAttribute("minx")),parseFloat(node.getAttribute("miny")),parseFloat(node.getAttribute("maxx")),parseFloat(node.getAttribute("maxy")));},read_wmc_LayerList:function(context,node){context.layers=[];this.runChildNodes(context,node);},read_wmc_Layer:function(context,node){var layerInfo={params:{},options:{visibility:(node.getAttribute("hidden")!="1")},queryable:(node.getAttribute("queryable")=="1"),formats:[],styles:[]};this.runChildNodes(layerInfo,node);layerInfo.params.layers=layerInfo.name;layerInfo.options.maxExtent=layerInfo.maxExtent;var layer=this.getLayerFromInfo(layerInfo);context.layers.push(layer);},getLayerFromInfo:function(layerInfo){var options=layerInfo.options;if(this.layerOptions){OpenLayers.Util.applyDefaults(options,this.layerOptions);}
-var layer=new OpenLayers.Layer.WMS(layerInfo.title,layerInfo.href,layerInfo.params,options);return layer;},read_wmc_Extension:function(obj,node){this.runChildNodes(obj,node);},read_ol_units:function(layerInfo,node){layerInfo.options.units=this.getChildValue(node);},read_ol_maxExtent:function(obj,node){var bounds=new OpenLayers.Bounds(node.getAttribute("minx"),node.getAttribute("miny"),node.getAttribute("maxx"),node.getAttribute("maxy"));obj.maxExtent=bounds;},read_ol_transparent:function(layerInfo,node){layerInfo.params.transparent=this.getChildValue(node);},read_ol_numZoomLevels:function(layerInfo,node){layerInfo.options.numZoomLevels=parseInt(this.getChildValue(node));},read_ol_opacity:function(layerInfo,node){layerInfo.options.opacity=parseFloat(this.getChildValue(node));},read_ol_singleTile:function(layerInfo,node){layerInfo.options.singleTile=(this.getChildValue(node)=="true");},read_ol_isBaseLayer:function(layerInfo,node){layerInfo.options.isBaseLayer=(this.getChildValue(node)=="true");},read_ol_displayInLayerSwitcher:function(layerInfo,node){layerInfo.options.displayInLayerSwitcher=(this.getChildValue(node)=="true");},read_wmc_Server:function(layerInfo,node){layerInfo.params.version=node.getAttribute("version");this.runChildNodes(layerInfo,node);},read_wmc_FormatList:function(layerInfo,node){this.runChildNodes(layerInfo,node);},read_wmc_Format:function(layerInfo,node){var format=this.getChildValue(node)
-layerInfo.formats.push(format);if(node.getAttribute("current")=="1"){layerInfo.params.format=format;}},read_wmc_StyleList:function(layerInfo,node){this.runChildNodes(layerInfo,node);},read_wmc_Style:function(layerInfo,node){var style={};this.runChildNodes(style,node);if(node.getAttribute("current")=="1"){if(style.href){layerInfo.params.sld=style.href;}else if(style.body){layerInfo.params.sld_body=style.body;}else{layerInfo.params.styles=style.name;}}
+var layer=new OpenLayers.Layer.WMS(layerInfo.title,layerInfo.href,layerInfo.params,options);return layer;},read_wmc_Extension:function(obj,node){this.runChildNodes(obj,node);},read_ol_units:function(layerInfo,node){layerInfo.options.units=this.getChildValue(node);},read_ol_maxExtent:function(obj,node){var bounds=new OpenLayers.Bounds(node.getAttribute("minx"),node.getAttribute("miny"),node.getAttribute("maxx"),node.getAttribute("maxy"));obj.maxExtent=bounds;},read_ol_transparent:function(layerInfo,node){layerInfo.params.transparent=this.getChildValue(node);},read_ol_numZoomLevels:function(layerInfo,node){layerInfo.options.numZoomLevels=parseInt(this.getChildValue(node));},read_ol_opacity:function(layerInfo,node){layerInfo.options.opacity=parseFloat(this.getChildValue(node));},read_ol_singleTile:function(layerInfo,node){layerInfo.options.singleTile=(this.getChildValue(node)=="true");},read_ol_isBaseLayer:function(layerInfo,node){layerInfo.options.isBaseLayer=(this.getChildValue(node)=="true");},read_ol_displayInLayerSwitcher:function(layerInfo,node){layerInfo.options.displayInLayerSwitcher=(this.getChildValue(node)=="true");},read_wmc_Server:function(layerInfo,node){layerInfo.params.version=node.getAttribute("version");this.runChildNodes(layerInfo,node);},read_wmc_FormatList:function(layerInfo,node){this.runChildNodes(layerInfo,node);},read_wmc_Format:function(layerInfo,node){var format=this.getChildValue(node);layerInfo.formats.push(format);if(node.getAttribute("current")=="1"){layerInfo.params.format=format;}},read_wmc_StyleList:function(layerInfo,node){this.runChildNodes(layerInfo,node);},read_wmc_Style:function(layerInfo,node){var style={};this.runChildNodes(style,node);if(node.getAttribute("current")=="1"){if(style.href){layerInfo.params.sld=style.href;}else if(style.body){layerInfo.params.sld_body=style.body;}else{layerInfo.params.styles=style.name;}}
 layerInfo.styles.push(style);},read_wmc_SLD:function(style,node){this.runChildNodes(style,node);},read_sld_StyledLayerDescriptor:function(sld,node){var xml=OpenLayers.Format.XML.prototype.write.apply(this,[node]);sld.body=xml;},read_wmc_OnlineResource:function(obj,node){obj.href=this.getAttributeNS(node,this.namespaces.xlink,"href");},read_wmc_Name:function(obj,node){var name=this.getChildValue(node);if(name){obj.name=name;}},read_wmc_Title:function(obj,node){var title=this.getChildValue(node);if(title){obj.title=title;}},read_wmc_Abstract:function(obj,node){var abst=this.getChildValue(node);if(abst){obj["abstract"]=abst;}},read_wmc_LatLonBoundingBox:function(layer,node){layer.llbbox=[parseFloat(node.getAttribute("minx")),parseFloat(node.getAttribute("miny")),parseFloat(node.getAttribute("maxx")),parseFloat(node.getAttribute("maxy"))];},read_wmc_LegendURL:function(style,node){var legend={width:node.getAttribute('width'),height:node.getAttribute('height')};var links=node.getElementsByTagName("OnlineResource");if(links.length>0){this.read_wmc_OnlineResource(legend,links[0]);}
 style.legend=legend;},write:function(context,options){var root=this.createElementDefaultNS("ViewContext");this.setAttributes(root,{version:this.VERSION,id:(options&&typeof options.id=="string")?options.id:OpenLayers.Util.createUniqueID("OpenLayers_Context_")});this.setAttributeNS(root,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);root.appendChild(this.write_wmc_General(context));root.appendChild(this.write_wmc_LayerList(context));return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},createElementDefaultNS:function(name,childValue,attributes){var node=this.createElementNS(this.namespaces[this.defaultPrefix],name);if(childValue){node.appendChild(this.createTextNode(childValue));}
 if(attributes){this.setAttributes(node,attributes);}
@@ -760,7 +796,7 @@
 return bounds;},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Marker.Box=OpenLayers.Class(OpenLayers.Marker,{bounds:null,div:null,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);},destroy:function(){this.bounds=null;this.div=null;OpenLayers.Marker.prototype.destroy.apply(this,arguments);},setBorder:function(color,width){if(!color){color="red";}
 if(!width){width=2;}
 this.div.style.border=width+"px solid "+color;},draw:function(px,sz){OpenLayers.Util.modifyDOMElement(this.div,null,px,sz);return this.div;},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsBounds(this.bounds,true,true);}
-return onScreen;},display:function(display){this.div.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Marker.Box"});OpenLayers.Control.DragFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,onStart:function(feature,pixel){},onDrag:function(feature,pixel){},onComplete:function(feature,pixel){},layer:null,feature:null,dragCallbacks:{},featureCallbacks:{},lastPixel:null,initialize:function(layer,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.layer=layer;this.handlers={drag:new OpenLayers.Handler.Drag(this,OpenLayers.Util.extend({down:this.downFeature,move:this.moveFeature,up:this.upFeature,out:this.cancel,done:this.doneDragging},this.dragCallbacks)),feature:new OpenLayers.Handler.Feature(this,this.layer,OpenLayers.Util.extend({over:this.overFeature,out:this.outFeature},this.featureCallbacks),{geometryTypes:this.geometryTypes})};},destroy:function(){this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[]);},activate:function(){return(this.handlers.feature.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments));},deactivate:function(){this.handlers.drag.deactivate();this.handlers.feature.deactivate();this.feature=null;this.dragging=false;this.lastPixel=null;return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},overFeature:function(feature){if(!this.handlers.drag.dragging){this.feature=feature;this.handlers.drag.activate();this.over=true;this.map.div.style.cursor="move";}else{if(this.feature.id==feature.id){this.over=true;}else{this.over=false;}}},downFeature:function(pixel){this.lastPixel=pixel;this.onStart(this.feature,pixel);},moveFeature:function(pixel){var res=this.map.getResolution();this.feature.geometry.move(res*(pixel.x-this.lastPixel.x),res*(this.lastPixel.y-pixel.y));this.layer.drawFeature(this.feature);this.lastPixel=pixel;this.onDrag(this.feature,pixel);},upFeature:function(pixel){if(!this.over){this.handlers.drag.deactivate();this.feature=null;this.map.div.style.cursor="default";}},doneDragging:function(pixel){this.onComplete(this.feature,pixel);},outFeature:function(feature){if(!this.handlers.drag.dragging){this.over=false;this.handlers.drag.deactivate();this.map.div.style.cursor="default";this.feature=null;}else{if(this.feature.id==feature.id){this.over=false;}}},cancel:function(){this.handlers.drag.deactivate();this.over=false;},setMap:function(map){this.handlers.drag.setMap(map);this.handlers.feature.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.DragFeature"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,draw:function(){this.handler=new OpenLayers.Handler.Drag(this,{"move":this.panMap,"done":this.panMapDone});},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});},panMapDone:function(xy){if(this.panned){this.panMap(xy);this.panned=false;}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Control.KeyboardDefaults=OpenLayers.Class(OpenLayers.Control,{slideFactor:75,initialize:function(){OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){if(this.handler){this.handler.destroy();}
+return onScreen;},display:function(display){this.div.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Marker.Box"});OpenLayers.Popup.FramedCloud=OpenLayers.Class(OpenLayers.Popup.Framed,{autoSize:true,panMapIfOutOfView:true,imageSize:new OpenLayers.Size(676,736),isAlphaImage:false,fixedRelativePosition:false,positionBlocks:{"tl":{'offset':new OpenLayers.Pixel(44,0),'padding':new OpenLayers.Bounds(8,40,8,9),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-638,0)},{size:new OpenLayers.Size('auto',21),anchor:new OpenLayers.Bounds(0,32,80,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-638,-629)},{size:new OpenLayers.Size(81,54),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(0,-668)}]},"tr":{'offset':new OpenLayers.Pixel(-45,0),'padding':new OpenLayers.Bounds(8,40,8,9),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-638,0)},{size:new OpenLayers.Size('auto',21),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-638,-629)},{size:new OpenLayers.Size(81,54),anchor:new OpenLayers.Bounds(0,0,null,null),position:new OpenLayers.Pixel(-215,-668)}]},"bl":{'offset':new OpenLayers.Pixel(45,0),'padding':new OpenLayers.Bounds(8,9,8,40),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-638,0)},{size:new OpenLayers.Size('auto',21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-638,-629)},{size:new OpenLayers.Size(81,54),anchor:new OpenLayers.Bounds(null,null,0,0),position:new OpenLayers.Pixel(-101,-674)}]},"br":{'offset':new OpenLayers.Pixel(-44,0),'padding':new OpenLayers.Bounds(8,9,8,40),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-638,0)},{size:new OpenLayers.Size('auto',21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-638,-629)},{size:new OpenLayers.Size(81,54),anchor:new OpenLayers.Bounds(0,null,null,0),position:new OpenLayers.Pixel(-311,-674)}]}},minSize:new OpenLayers.Size(105,10),maxSize:new OpenLayers.Size(600,660),initialize:function(id,lonlat,size,contentHTML,anchor,closeBox,closeBoxCallback){this.imageSrc=OpenLayers.Util.getImagesLocation()+'cloud-popup-relative.png';OpenLayers.Popup.Framed.prototype.initialize.apply(this,arguments);this.contentDiv.className="olFramedCloudPopupContent";},destroy:function(){OpenLayers.Popup.Framed.prototype.destroy.apply(this,arguments);},CLASS_NAME:"OpenLayers.Popup.FramedCloud"});OpenLayers.Control.DragFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,onStart:function(feature,pixel){},onDrag:function(feature,pixel){},onComplete:function(feature,pixel){},layer:null,feature:null,dragCallbacks:{},featureCallbacks:{},lastPixel:null,initialize:function(layer,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.layer=layer;this.handlers={drag:new OpenLayers.Handler.Drag(this,OpenLayers.Util.extend({down:this.downFeature,move:this.moveFeature,up:this.upFeature,out:this.cancel,done:this.doneDragging},this.dragCallbacks)),feature:new OpenLayers.Handler.Feature(this,this.layer,OpenLayers.Util.extend({over:this.overFeature,out:this.outFeature},this.featureCallbacks),{geometryTypes:this.geometryTypes})};},destroy:function(){this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[]);},activate:function(){return(this.handlers.feature.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments));},deactivate:function(){this.handlers.drag.deactivate();this.handlers.feature.deactivate();this.feature=null;this.dragging=false;this.lastPixel=null;return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},overFeature:function(feature){if(!this.handlers.drag.dragging){this.feature=feature;this.handlers.drag.activate();this.over=true;this.map.div.style.cursor="move";}else{if(this.feature.id==feature.id){this.over=true;}else{this.over=false;}}},downFeature:function(pixel){this.lastPixel=pixel;this.onStart(this.feature,pixel);},moveFeature:function(pixel){var res=this.map.getResolution();this.feature.geometry.move(res*(pixel.x-this.lastPixel.x),res*(this.lastPixel.y-pixel.y));this.layer.drawFeature(this.feature);this.lastPixel=pixel;this.onDrag(this.feature,pixel);},upFeature:function(pixel){if(!this.over){this.handlers.drag.deactivate();this.feature=null;this.map.div.style.cursor="default";}},doneDragging:function(pixel){this.onComplete(this.feature,pixel);},outFeature:function(feature){if(!this.handlers.drag.dragging){this.over=false;this.handlers.drag.deactivate();this.map.div.style.cursor="default";this.feature=null;}else{if(this.feature.id==feature.id){this.over=false;}}},cancel:function(){this.handlers.drag.deactivate();this.over=false;},setMap:function(map){this.handlers.drag.setMap(map);this.handlers.feature.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.DragFeature"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,draw:function(){this.handler=new OpenLayers.Handler.Drag(this,{"move":this.panMap,"done":this.panMapDone});},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});},panMapDone:function(xy){if(this.panned){this.panMap(xy);this.panned=false;}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Control.KeyboardDefaults=OpenLayers.Class(OpenLayers.Control,{slideFactor:75,initialize:function(){OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){if(this.handler){this.handler.destroy();}
 this.handler=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){this.handler=new OpenLayers.Handler.Keyboard(this,{"keypress":this.defaultKeyPress});this.activate();},defaultKeyPress:function(code){switch(code){case OpenLayers.Event.KEY_LEFT:this.map.pan(-this.slideFactor,0);break;case OpenLayers.Event.KEY_RIGHT:this.map.pan(this.slideFactor,0);break;case OpenLayers.Event.KEY_UP:this.map.pan(0,-this.slideFactor);break;case OpenLayers.Event.KEY_DOWN:this.map.pan(0,this.slideFactor);break;case 33:var size=this.map.getSize();this.map.pan(0,-0.75*size.h);break;case 34:var size=this.map.getSize();this.map.pan(0,0.75*size.h);break;case 35:var size=this.map.getSize();this.map.pan(0.75*size.w,0);break;case 36:var size=this.map.getSize();this.map.pan(-0.75*size.w,0);break;case 43:this.map.zoomIn();break;case 45:this.map.zoomOut();break;case 107:this.map.zoomIn();break;case 109:this.map.zoomOut();break;}},CLASS_NAME:"OpenLayers.Control.KeyboardDefaults"});OpenLayers.State={UNKNOWN:'Unknown',INSERT:'Insert',UPDATE:'Update',DELETE:'Delete'};OpenLayers.Feature.Vector=OpenLayers.Class(OpenLayers.Feature,{fid:null,geometry:null,attributes:null,state:null,style:null,renderIntent:"default",initialize:function(geometry,attributes,style){OpenLayers.Feature.prototype.initialize.apply(this,[null,null,attributes]);this.lonlat=null;this.geometry=geometry;this.state=null;this.attributes={};if(attributes){this.attributes=OpenLayers.Util.extend(this.attributes,attributes);}
 this.style=style?style:null;},destroy:function(){if(this.layer){this.layer.removeFeatures(this);this.layer=null;}
 this.geometry=null;OpenLayers.Feature.prototype.destroy.apply(this,arguments);},clone:function(){return new OpenLayers.Feature.Vector(this.geometry.clone(),this.attributes,this.style);},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);}}
@@ -863,7 +899,7 @@
 OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[size]);},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();},getTilesBounds:function(){var bounds=null;if(this.grid.length){var bottom=this.grid.length-1;var bottomLeftTile=this.grid[bottom][0];var right=this.grid[0].length-1;var topRightTile=this.grid[0][right];bounds=new OpenLayers.Bounds(bottomLeftTile.bounds.left,bottomLeftTile.bounds.bottom,topRightTile.bounds.right,topRightTile.bounds.top);}
 return bounds;},initSingleTile:function(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]=[];}
 var tile=this.grid[0][0];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);tile.draw();this.grid[0][0]=tile;}else{tile.moveTo(tileBounds,px);}
-this.removeExcessTiles(1,1);},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}},initGriddedTiles:function(bounds){var viewSize=this.map.getSize();var minRows=Math.ceil(viewSize.h/this.tileSize.h)+
+this.removeExcessTiles(1,1);},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};},initGriddedTiles:function(bounds){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.map.getMaxExtent();var resolution=this.map.getResolution();var tileLayout=this.calculateGridLayout(bounds,extent,resolution);var tileoffsetx=Math.round(tileLayout.tileoffsetx);var tileoffsety=Math.round(tileLayout.tileoffsety);var tileoffsetlon=tileLayout.tileoffsetlon;var tileoffsetlat=tileLayout.tileoffsetlat;var tilelon=tileLayout.tilelon;var tilelat=tileLayout.tilelat;this.origin=new OpenLayers.Pixel(tileoffsetx,tileoffsety);var startX=tileoffsetx;var startLon=tileoffsetlon;var rowidx=0;var layerContainerDivLeft=parseInt(this.map.layerContainerDiv.style.left);var layerContainerDivTop=parseInt(this.map.layerContainerDiv.style.top);do{var row=this.grid[rowidx++];if(!row){row=[];this.grid.push(row);}
 tileoffsetlon=startLon;tileoffsetx=startX;var colidx=0;do{var tileBounds=new OpenLayers.Bounds(tileoffsetlon,tileoffsetlat,tileoffsetlon+tilelon,tileoffsetlat+tilelat);var x=tileoffsetx;x-=layerContainerDivLeft;var y=tileoffsety;y-=layerContainerDivTop;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);}
@@ -873,8 +909,7 @@
 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)){tileQueue.unshift(tile);tile.queued=true;directionsTried=0;iRow=testRow;iCell=testCell;}else{direction=(direction+1)%4;directionsTried++;}}
 for(var i=0;i<tileQueue.length;i++){var tile=tileQueue[i];tile.draw();tile.queued=false;}},addTile:function(bounds,position){},addTileMonitoringHooks:function(tile){tile.onLoadStart=function(){if(this.numLoadingTiles==0){this.events.triggerEvent("loadstart");}
-this.numLoadingTiles++;};tile.events.register("loadstart",this,tile.onLoadStart);tile.onLoadEnd=function(){this.numLoadingTiles--;this.events.triggerEvent("tileloaded");if(this.numLoadingTiles==0){this.events.triggerEvent("loadend");}};tile.events.register("loadend",this,tile.onLoadEnd);tile.events.register("unload",this,tile.onLoadEnd);},removeTileMonitoringHooks:function(tile){tile.unload()
-tile.events.un({"loadstart":tile.onLoadStart,"loadend":tile.onLoadEnd,"unload":tile.onLoadEnd,scope:this});},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;}};},shiftRow:function(prepend){var modelRowIndex=(prepend)?0:(this.grid.length-1);var grid=this.grid;var modelRow=grid[modelRowIndex];var resolution=this.map.getResolution();var deltaY=(prepend)?-this.tileSize.h:this.tileSize.h;var deltaLat=resolution*-deltaY;var row=(prepend)?grid.pop():grid.shift();for(var i=0;i<modelRow.length;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);}
+this.numLoadingTiles++;};tile.events.register("loadstart",this,tile.onLoadStart);tile.onLoadEnd=function(){this.numLoadingTiles--;this.events.triggerEvent("tileloaded");if(this.numLoadingTiles==0){this.events.triggerEvent("loadend");}};tile.events.register("loadend",this,tile.onLoadEnd);tile.events.register("unload",this,tile.onLoadEnd);},removeTileMonitoringHooks:function(tile){tile.unload();tile.events.un({"loadstart":tile.onLoadStart,"loadend":tile.onLoadEnd,"unload":tile.onLoadEnd,scope:this});},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;}};},shiftRow:function(prepend){var modelRowIndex=(prepend)?0:(this.grid.length-1);var grid=this.grid;var modelRow=grid[modelRowIndex];var resolution=this.map.getResolution();var deltaY=(prepend)?-this.tileSize.h:this.tileSize.h;var deltaLat=resolution*-deltaY;var row=(prepend)?grid.pop():grid.shift();for(var i=0;i<modelRow.length;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);}
 if(prepend){grid.unshift(row);}else{grid.push(row);}},shiftColumn:function(prepend){var deltaX=(prepend)?-this.tileSize.w:this.tileSize.w;var resolution=this.map.getResolution();var deltaLon=resolution*deltaX;for(var i=0;i<this.grid.length;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);}else{row.push(tile);}}},removeExcessTiles:function(rows,columns){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();}}
 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();}}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize();}},getTileBounds:function(viewPortPx){var maxExtent=this.map.getMaxExtent();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-
@@ -896,7 +931,7 @@
 this.map.events.unregister("moveend",this,this.fixYahooEventPane);}},getWarningHTML:function(){return OpenLayers.i18n("getLayerWarning",{'layerType':'Yahoo','layerLib':'Yahoo'});},getOLZoomFromMapObjectZoom:function(moZoom){var zoom=null;if(moZoom!=null){zoom=OpenLayers.Layer.FixedZoomLevels.prototype.getOLZoomFromMapObjectZoom.apply(this,[moZoom]);zoom=18-zoom;}
 return zoom;},getMapObjectZoomFromOLZoom:function(olZoom){var zoom=null;if(olZoom!=null){zoom=OpenLayers.Layer.FixedZoomLevels.prototype.getMapObjectZoomFromOLZoom.apply(this,[olZoom]);zoom=18-zoom;}
 return zoom;},setMapObjectCenter:function(center,zoom){this.mapObject.drawZoomAndCenter(center,zoom);},getMapObjectCenter:function(){return this.mapObject.getCenterLatLon();},dragPanMapObject:function(dX,dY){this.mapObject.moveByXY({'x':-dX,'y':dY});},getMapObjectZoom:function(){return this.mapObject.getZoomLevel();},getMapObjectLonLatFromMapObjectPixel:function(moPixel){return this.mapObject.convertXYLatLon(moPixel);},getMapObjectPixelFromMapObjectLonLat:function(moLonLat){return this.mapObject.convertLatLonXY(moLonLat);},getLongitudeFromMapObjectLonLat:function(moLonLat){return this.sphericalMercator?this.forwardMercator(moLonLat.Lon,moLonLat.Lat).lon:moLonLat.Lon;},getLatitudeFromMapObjectLonLat:function(moLonLat){return this.sphericalMercator?this.forwardMercator(moLonLat.Lon,moLonLat.Lat).lat:moLonLat.Lat;},getMapObjectLonLatFromLonLat:function(lon,lat){var yLatLong;if(this.sphericalMercator){var lonlat=this.inverseMercator(lon,lat);yLatLong=new YGeoPoint(lonlat.lat,lonlat.lon);}else{yLatLong=new YGeoPoint(lat,lon);}
-return yLatLong;},getXFromMapObjectPixel:function(moPixel){return moPixel.x;},getYFromMapObjectPixel:function(moPixel){return moPixel.y;},getMapObjectPixelFromXY:function(x,y){return new YCoordPoint(x,y);},getMapObjectSizeFromOLSize:function(olSize){return new YSize(olSize.w,olSize.h);},CLASS_NAME:"OpenLayers.Layer.Yahoo"});OpenLayers.Style=OpenLayers.Class({name:null,layerName:null,isDefault:false,rules:null,context:null,defaultStyle:null,propertyStyles:null,initialize:function(style,options){this.rules=[];this.setDefaultStyle(style||OpenLayers.Feature.Vector.style["default"]);OpenLayers.Util.extend(this,options);},destroy:function(){for(var i=0;i<this.rules.length;i++){this.rules[i].destroy();this.rules[i]=null;}
+return yLatLong;},getXFromMapObjectPixel:function(moPixel){return moPixel.x;},getYFromMapObjectPixel:function(moPixel){return moPixel.y;},getMapObjectPixelFromXY:function(x,y){return new YCoordPoint(x,y);},getMapObjectSizeFromOLSize:function(olSize){return new YSize(olSize.w,olSize.h);},CLASS_NAME:"OpenLayers.Layer.Yahoo"});OpenLayers.Style=OpenLayers.Class({name:null,title:null,description:null,layerName:null,isDefault:false,rules:null,context:null,defaultStyle:null,propertyStyles:null,initialize:function(style,options){this.rules=[];this.setDefaultStyle(style||OpenLayers.Feature.Vector.style["default"]);OpenLayers.Util.extend(this,options);},destroy:function(){for(var i=0;i<this.rules.length;i++){this.rules[i].destroy();this.rules[i]=null;}
 this.rules=null;this.defaultStyle=null;},createSymbolizer:function(feature){var style=this.createLiterals(OpenLayers.Util.extend({},this.defaultStyle),feature);var rules=this.rules;var rule,context;var elseRules=[];var appliedRules=false;for(var i=0;i<rules.length;i++){rule=rules[i];var applies=rule.evaluate(feature);if(applies){if(rule instanceof OpenLayers.Rule&&rule.elseFilter){elseRules.push(rule);}else{appliedRules=true;this.applySymbolizer(rule,style,feature);}}}
 if(appliedRules==false&&elseRules.length>0){appliedRules=true;for(var i=0;i<elseRules.length;i++){this.applySymbolizer(elseRules[i],style,feature);}}
 if(rules.length>0&&appliedRules==false){style.display="none";}else{style.display="";}
@@ -904,8 +939,7 @@
 return style;},findPropertyStyles:function(){var propertyStyles={};var style=this.defaultStyle;this.addPropertyStyles(propertyStyles,style);var rules=this.rules;var symbolizer,value;for(var i=0;i<rules.length;i++){var symbolizer=rules[i].symbolizer;for(var key in symbolizer){value=symbolizer[key];if(typeof value=="object"){this.addPropertyStyles(propertyStyles,value);}else{this.addPropertyStyles(propertyStyles,symbolizer);break;}}}
 return propertyStyles;},addPropertyStyles:function(propertyStyles,symbolizer){var property;for(var key in symbolizer){property=symbolizer[key];if(typeof property=="string"&&property.match(/\$\{\w+\}/)){propertyStyles[key]=true;}}
 return propertyStyles;},addRules:function(rules){this.rules=this.rules.concat(rules);this.propertyStyles=this.findPropertyStyles();},setDefaultStyle:function(style){this.defaultStyle=style;this.propertyStyles=this.findPropertyStyles();},getSymbolizerPrefix:function(geometry){var prefixes=OpenLayers.Style.SYMBOLIZER_PREFIXES;for(var i=0;i<prefixes.length;i++){if(geometry.CLASS_NAME.indexOf(prefixes[i])!=-1){return prefixes[i];}}},CLASS_NAME:"OpenLayers.Style"});OpenLayers.Style.createLiteral=function(value,context,feature){if(typeof value=="string"&&value.indexOf("${")!=-1){value=OpenLayers.String.format(value,context,[feature]);value=(isNaN(value)||!value)?value:parseFloat(value);}
-return value;}
-OpenLayers.Style.SYMBOLIZER_PREFIXES=['Point','Line','Polygon'];OpenLayers.Control.ModifyFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,clickout:true,toggle:true,layer:null,feature:null,vertices:null,virtualVertices:null,selectControl:null,dragControl:null,handlers:null,deleteCodes:null,virtualStyle:null,mode:null,radiusHandle:null,dragHandle:null,onModificationStart:function(){},onModification:function(){},onModificationEnd:function(){},initialize:function(layer,options){this.layer=layer;this.vertices=[];this.virtualVertices=[];this.styleVirtual=OpenLayers.Util.extend({},this.layer.style||this.layer.styleMap.createSymbolizer());this.styleVirtual.fillOpacity=0.3;this.styleVirtual.strokeOpacity=0.3;this.deleteCodes=[46,100];this.mode=OpenLayers.Control.ModifyFeature.RESHAPE;OpenLayers.Control.prototype.initialize.apply(this,[options]);if(!(this.deleteCodes instanceof Array)){this.deleteCodes=[this.deleteCodes];}
+return value;};OpenLayers.Style.SYMBOLIZER_PREFIXES=['Point','Line','Polygon'];OpenLayers.Control.ModifyFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,clickout:true,toggle:true,layer:null,feature:null,vertices:null,virtualVertices:null,selectControl:null,dragControl:null,handlers:null,deleteCodes:null,virtualStyle:null,mode:null,radiusHandle:null,dragHandle:null,onModificationStart:function(){},onModification:function(){},onModificationEnd:function(){},initialize:function(layer,options){this.layer=layer;this.vertices=[];this.virtualVertices=[];this.styleVirtual=OpenLayers.Util.extend({},this.layer.style||this.layer.styleMap.createSymbolizer());this.styleVirtual.fillOpacity=0.3;this.styleVirtual.strokeOpacity=0.3;this.deleteCodes=[46,100];this.mode=OpenLayers.Control.ModifyFeature.RESHAPE;OpenLayers.Control.prototype.initialize.apply(this,[options]);if(!(this.deleteCodes instanceof Array)){this.deleteCodes=[this.deleteCodes];}
 var control=this;var selectOptions={geometryTypes:this.geometryTypes,clickout:this.clickout,toggle:this.toggle};this.selectControl=new OpenLayers.Control.SelectFeature(layer,selectOptions);this.layer.events.on({"featureselected":this.selectFeature,"featureunselected":this.unselectFeature,scope:this});var dragOptions={geometryTypes:["OpenLayers.Geometry.Point"],snappingOptions:this.snappingOptions,onStart:function(feature,pixel){control.dragStart.apply(control,[feature,pixel]);},onDrag:function(feature){control.dragVertex.apply(control,[feature]);},onComplete:function(feature){control.dragComplete.apply(control,[feature]);}};this.dragControl=new OpenLayers.Control.DragFeature(layer,dragOptions);var keyboardOptions={keypress:this.handleKeypress};this.handlers={keyboard:new OpenLayers.Handler.Keyboard(this,keyboardOptions)};},destroy:function(){this.layer.events.un({"featureselected":this.selectFeature,"featureunselected":this.unselectFeature,scope:this});this.layer=null;this.selectControl.destroy();this.dragControl.destroy();OpenLayers.Control.prototype.destroy.apply(this,[]);},activate:function(){return(this.selectControl.activate()&&this.handlers.keyboard.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments));},deactivate:function(){var deactivated=false;if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){this.layer.removeFeatures(this.vertices);this.layer.removeFeatures(this.virtualVertices);this.vertices=[];this.dragControl.deactivate();if(this.feature&&this.feature.geometry){this.selectControl.unselect.apply(this.selectControl,[this.feature]);}
 this.selectControl.deactivate();this.handlers.keyboard.deactivate();deactivated=true;}
 return deactivated;},selectFeature:function(object){this.feature=object.feature;this.resetVertices();this.dragControl.activate();this.onModificationStart(this.feature);this.layer.events.triggerEvent("beforefeaturemodified",{feature:this.feature});},unselectFeature:function(object){this.layer.removeFeatures(this.vertices);this.vertices=[];this.layer.destroyFeatures(this.virtualVertices);this.virtualVertices=[];if(this.dragHandle){this.layer.destroyFeatures([this.dragHandle]);delete this.dragHandle;}
@@ -924,17 +958,15 @@
 if((this.mode&OpenLayers.Control.ModifyFeature.RESHAPE)){this.collectVertices();}}},handleKeypress:function(code){if(this.feature&&OpenLayers.Util.indexOf(this.deleteCodes,code)!=-1){var vertex=this.dragControl.feature;if(vertex&&OpenLayers.Util.indexOf(this.vertices,vertex)!=-1&&!this.dragControl.handlers.drag.dragging&&vertex.geometry.parent){vertex.geometry.parent.removeComponent(vertex.geometry);this.layer.drawFeature(this.feature,this.selectControl.renderIntent);this.resetVertices();this.onModification(this.feature);this.layer.events.triggerEvent("featuremodified",{feature:this.feature});}}},collectVertices:function(){this.vertices=[];this.virtualVertices=[];var control=this;function collectComponentVertices(geometry){var i,vertex,component;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){vertex=new OpenLayers.Feature.Vector(geometry);control.vertices.push(vertex);}else{var numVert=geometry.components.length;if(geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){numVert-=1;}
 for(i=0;i<numVert;++i){component=geometry.components[i];if(component.CLASS_NAME=="OpenLayers.Geometry.Point"){vertex=new OpenLayers.Feature.Vector(component);control.vertices.push(vertex);}else{collectComponentVertices(component);}}
 if(geometry.CLASS_NAME!="OpenLayers.Geometry.MultiPoint"){for(i=0;i<geometry.components.length-1;++i){var prevVertex=geometry.components[i];var nextVertex=geometry.components[i+1];if(prevVertex.CLASS_NAME=="OpenLayers.Geometry.Point"&&nextVertex.CLASS_NAME=="OpenLayers.Geometry.Point"){var x=(prevVertex.x+nextVertex.x)/2;var y=(prevVertex.y+nextVertex.y)/2;var point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(x,y),null,control.styleVirtual);point.geometry.parent=geometry;point._index=i+1;control.virtualVertices.push(point);}}}}}
-collectComponentVertices.call(this,this.feature.geometry);this.layer.addFeatures(this.vertices,{silent:true});this.layer.addFeatures(this.virtualVertices,{silent:true});},collectDragHandle:function(){var geometry=this.feature.geometry;var center=geometry.getBounds().getCenterLonLat();var originGeometry=new OpenLayers.Geometry.Point(center.lon,center.lat);var origin=new OpenLayers.Feature.Vector(originGeometry);originGeometry.move=function(x,y){OpenLayers.Geometry.Point.prototype.move.call(this,x,y);geometry.move(x,y);}
-this.dragHandle=origin;this.layer.addFeatures([this.dragHandle],{silent:true});},collectRadiusHandle:function(){var geometry=this.feature.geometry;var bounds=geometry.getBounds();var center=bounds.getCenterLonLat();var originGeometry=new OpenLayers.Geometry.Point(center.lon,center.lat);var radiusGeometry=new OpenLayers.Geometry.Point(bounds.right,bounds.bottom);var radius=new OpenLayers.Feature.Vector(radiusGeometry);var resize=(this.mode&OpenLayers.Control.ModifyFeature.RESIZE);var rotate=(this.mode&OpenLayers.Control.ModifyFeature.ROTATE);radiusGeometry.move=function(x,y){OpenLayers.Geometry.Point.prototype.move.call(this,x,y);var dx1=this.x-originGeometry.x;var dy1=this.y-originGeometry.y;var dx0=dx1-x;var dy0=dy1-y;if(rotate){var a0=Math.atan2(dy0,dx0);var a1=Math.atan2(dy1,dx1);var angle=a1-a0;angle*=180/Math.PI;geometry.rotate(angle,originGeometry);}
-if(resize){var l0=Math.sqrt((dx0*dx0)+(dy0*dy0));var l1=Math.sqrt((dx1*dx1)+(dy1*dy1));geometry.resize(l1/l0,originGeometry);}}
-this.radiusHandle=radius;this.layer.addFeatures([this.radiusHandle],{silent:true});},setMap:function(map){this.selectControl.setMap(map);this.dragControl.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.ModifyFeature"});OpenLayers.Control.ModifyFeature.RESHAPE=1;OpenLayers.Control.ModifyFeature.RESIZE=2;OpenLayers.Control.ModifyFeature.ROTATE=4;OpenLayers.Control.ModifyFeature.DRAG=8;OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,zoomBox:null,zoomWheelEnabled:true,initialize:function(options){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){this.deactivate();if(this.dragPan){this.dragPan.destroy();}
+collectComponentVertices.call(this,this.feature.geometry);this.layer.addFeatures(this.vertices,{silent:true});this.layer.addFeatures(this.virtualVertices,{silent:true});},collectDragHandle:function(){var geometry=this.feature.geometry;var center=geometry.getBounds().getCenterLonLat();var originGeometry=new OpenLayers.Geometry.Point(center.lon,center.lat);var origin=new OpenLayers.Feature.Vector(originGeometry);originGeometry.move=function(x,y){OpenLayers.Geometry.Point.prototype.move.call(this,x,y);geometry.move(x,y);};this.dragHandle=origin;this.layer.addFeatures([this.dragHandle],{silent:true});},collectRadiusHandle:function(){var geometry=this.feature.geometry;var bounds=geometry.getBounds();var center=bounds.getCenterLonLat();var originGeometry=new OpenLayers.Geometry.Point(center.lon,center.lat);var radiusGeometry=new OpenLayers.Geometry.Point(bounds.right,bounds.bottom);var radius=new OpenLayers.Feature.Vector(radiusGeometry);var resize=(this.mode&OpenLayers.Control.ModifyFeature.RESIZE);var rotate=(this.mode&OpenLayers.Control.ModifyFeature.ROTATE);radiusGeometry.move=function(x,y){OpenLayers.Geometry.Point.prototype.move.call(this,x,y);var dx1=this.x-originGeometry.x;var dy1=this.y-originGeometry.y;var dx0=dx1-x;var dy0=dy1-y;if(rotate){var a0=Math.atan2(dy0,dx0);var a1=Math.atan2(dy1,dx1);var angle=a1-a0;angle*=180/Math.PI;geometry.rotate(angle,originGeometry);}
+if(resize){var l0=Math.sqrt((dx0*dx0)+(dy0*dy0));var l1=Math.sqrt((dx1*dx1)+(dy1*dy1));geometry.resize(l1/l0,originGeometry);}};this.radiusHandle=radius;this.layer.addFeatures([this.radiusHandle],{silent:true});},setMap:function(map){this.selectControl.setMap(map);this.dragControl.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.ModifyFeature"});OpenLayers.Control.ModifyFeature.RESHAPE=1;OpenLayers.Control.ModifyFeature.RESIZE=2;OpenLayers.Control.ModifyFeature.ROTATE=4;OpenLayers.Control.ModifyFeature.DRAG=8;OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,zoomBox:null,zoomWheelEnabled:true,initialize:function(options){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){this.deactivate();if(this.dragPan){this.dragPan.destroy();}
 this.dragPan=null;if(this.zoomBox){this.zoomBox.destroy();}
 this.zoomBox=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},activate:function(){this.dragPan.activate();if(this.zoomWheelEnabled){this.handlers.wheel.activate();}
 this.handlers.click.activate();this.zoomBox.activate();return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){this.zoomBox.deactivate();this.dragPan.deactivate();this.handlers.click.deactivate();this.handlers.wheel.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},draw:function(){this.handlers.click=new OpenLayers.Handler.Click(this,{'dblclick':this.defaultDblClick},{'double':true,'stopDouble':true});this.dragPan=new OpenLayers.Control.DragPan({map:this.map});this.zoomBox=new OpenLayers.Control.ZoomBox({map:this.map,keyMask:OpenLayers.Handler.MOD_SHIFT});this.dragPan.draw();this.zoomBox.draw();this.handlers.wheel=new OpenLayers.Handler.MouseWheel(this,{"up":this.wheelUp,"down":this.wheelDown});this.activate();},defaultDblClick:function(evt){var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom+1);},wheelChange:function(evt,deltaZ){var newZoom=this.map.getZoom()+deltaZ;if(!this.map.isValidZoomLevel(newZoom)){return;}
 var size=this.map.getSize();var deltaX=size.w/2-evt.xy.x;var deltaY=evt.xy.y-size.h/2;var newRes=this.map.baseLayer.getResolutionForZoom(newZoom);var zoomPoint=this.map.getLonLatFromPixel(evt.xy);var newCenter=new OpenLayers.LonLat(zoomPoint.lon+deltaX*newRes,zoomPoint.lat+deltaY*newRes);this.map.setCenter(newCenter,newZoom);},wheelUp:function(evt){this.wheelChange(evt,1);},wheelDown:function(evt){this.wheelChange(evt,-1);},disableZoomWheel:function(){this.zoomWheelEnabled=false;this.handlers.wheel.deactivate();},enableZoomWheel:function(){this.zoomWheelEnabled=true;if(this.active){this.handlers.wheel.activate();}},CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){this.id=null;this.bounds=null;},clone:function(){return new OpenLayers.Geometry();},setBounds:function(bounds){if(bounds){this.bounds=bounds.clone();}},clearBounds:function(){this.bounds=null;if(this.parent){this.parent.clearBounds();}},extendBounds:function(newBounds){var bounds=this.getBounds();if(!bounds){this.setBounds(newBounds);}else{this.bounds.extend(newBounds);}},getBounds:function(){if(this.bounds==null){this.calculateBounds();}
 return this.bounds;},calculateBounds:function(){},atPoint:function(lonlat,toleranceLon,toleranceLat){var atPoint=false;var bounds=this.getBounds();if((bounds!=null)&&(lonlat!=null)){var dX=(toleranceLon!=null)?toleranceLon:0;var dY=(toleranceLat!=null)?toleranceLat:0;var toleranceBounds=new OpenLayers.Bounds(this.bounds.left-dX,this.bounds.bottom-dY,this.bounds.right+dX,this.bounds.top+dY);atPoint=toleranceBounds.containsLonLat(lonlat);}
 return atPoint;},getLength:function(){return 0.0;},getArea:function(){return 0.0;},toString:function(){return OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this));},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.segmentsIntersect=function(seg1,seg2,point){var intersection=false;var x11_21=seg1.x1-seg2.x1;var y11_21=seg1.y1-seg2.y1;var x12_11=seg1.x2-seg1.x1;var y12_11=seg1.y2-seg1.y1;var y22_21=seg2.y2-seg2.y1;var x22_21=seg2.x2-seg2.x1;var d=(y22_21*x12_11)-(x22_21*y12_11);var n1=(x22_21*y11_21)-(y22_21*x11_21);var n2=(x12_11*y11_21)-(y12_11*x11_21);if(d==0){if(n1==0&&n2==0){intersection=true;}}else{var along1=n1/d;var along2=n2/d;if(along1>=0&&along1<=1&&along2>=0&&along2<=1){if(!point){intersection=true;}else{var x=seg1.x1+(along1*x12_11);var y=seg1.y1+(along1*y12_11);intersection=new OpenLayers.Geometry.Point(x,y);}}}
-return intersection;};OpenLayers.Layer.KaMap=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,units:null,resolution:OpenLayers.DOTS_PER_INCH,DEFAULT_PARAMS:{i:'jpeg',map:''},initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);this.params=(params?params:{});if(params){OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);}},getURL:function(bounds){bounds=this.adjustBounds(bounds);var mapRes=this.map.getResolution();var scale=Math.round((this.map.getScale()*10000))/10000;var pX=Math.round(bounds.left/mapRes);var pY=-Math.round(bounds.top/mapRes);return this.getFullRequestString({t:pY,l:pX,s:scale});},addTile:function(bounds,position){var url=this.getURL(bounds);return new OpenLayers.Tile.Image(this,position,bounds,url,this.tileSize);},calculateGridLayout:function(bounds,extent,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=tilecol*tilelon;var offsetlat=bounds.top;var tilerow=Math.ceil(offsetlat/tilelat)+this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=-(tilerowremain+1)*this.tileSize.h;var tileoffsetlat=tilerow*tilelat;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.KaMap(this.name,this.url,this.params,this.options);}
+return intersection;};OpenLayers.Layer.KaMap=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,units:null,resolution:OpenLayers.DOTS_PER_INCH,DEFAULT_PARAMS:{i:'jpeg',map:''},initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);this.params=(params?params:{});if(params){OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);}},getURL:function(bounds){bounds=this.adjustBounds(bounds);var mapRes=this.map.getResolution();var scale=Math.round((this.map.getScale()*10000))/10000;var pX=Math.round(bounds.left/mapRes);var pY=-Math.round(bounds.top/mapRes);return this.getFullRequestString({t:pY,l:pX,s:scale});},addTile:function(bounds,position){var url=this.getURL(bounds);return new OpenLayers.Tile.Image(this,position,bounds,url,this.tileSize);},calculateGridLayout:function(bounds,extent,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=tilecol*tilelon;var offsetlat=bounds.top;var tilerow=Math.ceil(offsetlat/tilelat)+this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=-(tilerowremain+1)*this.tileSize.h;var tileoffsetlat=tilerow*tilelat;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety};},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.KaMap(this.name,this.url,this.params,this.options);}
 obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);if(this.tileSize!=null){obj.tileSize=this.tileSize.clone();}
 obj.grid=[];return obj;},getTileBounds:function(viewPortPx){var resolution=this.getResolution();var tileMapWidth=resolution*this.tileSize.w;var tileMapHeight=resolution*this.tileSize.h;var mapPoint=this.getLonLatFromViewPortPx(viewPortPx);var tileLeft=tileMapWidth*Math.floor(mapPoint.lon/tileMapWidth);var tileBottom=tileMapHeight*Math.floor(mapPoint.lat/tileMapHeight);return new OpenLayers.Bounds(tileLeft,tileBottom,tileLeft+tileMapWidth,tileBottom+tileMapHeight);},CLASS_NAME:"OpenLayers.Layer.KaMap"});OpenLayers.Layer.MapGuide=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,singleTile:false,TILE_PARAMS:{operation:'GETTILEIMAGE',version:'1.2.0'},SINGLE_TILE_PARAMS:{operation:'GETMAPIMAGE',format:'PNG',locale:'en',clip:'1',version:'1.0.0'},defaultSize:new OpenLayers.Size(300,300),initialize:function(name,url,params,options){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.transparent!="true")&&(this.transparent!=true));}
 if(this.singleTile){OpenLayers.Util.applyDefaults(this.params,this.SINGLE_TILE_PARAMS);}else{OpenLayers.Util.applyDefaults(this.params,this.TILE_PARAMS);this.setTileSize(this.defaultSize);}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapGuide(this.name,this.url,this.params,this.options);}
@@ -943,7 +975,7 @@
 return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;if(typeof url=="object"){url=url[Math.floor(Math.random()*url.length)];}
 var requestString=url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getArgs(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
 var paramsString=OpenLayers.Util.getParameterString(allParams);paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
-return requestString;},calculateGridLayout:function(bounds,extent,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=extent.top-bounds.top+tilelat;var tilerow=Math.floor(offsetlat/tilelat)-this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=tilerowremain*this.tileSize.h;var tileoffsetlat=extent.top-tilelat*tilerow;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety}},CLASS_NAME:"OpenLayers.Layer.MapGuide"});OpenLayers.Layer.MapServer=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{mode:"map",map_imagetype:"png"},initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);if(arguments.length>0){OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);}
+return requestString;},calculateGridLayout:function(bounds,extent,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=extent.top-bounds.top+tilelat;var tilerow=Math.floor(offsetlat/tilelat)-this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=tilerowremain*this.tileSize.h;var tileoffsetlat=extent.top-tilelat*tilerow;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety};},CLASS_NAME:"OpenLayers.Layer.MapGuide"});OpenLayers.Layer.MapServer=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{mode:"map",map_imagetype:"png"},initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);if(arguments.length>0){OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);}
 if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.params.transparent!="true")&&(this.params.transparent!=true));}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapServer(this.name,this.url,this.params,this.options);}
 obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getURL:function(bounds){bounds=this.adjustBounds(bounds);var extent=[bounds.left,bounds.bottom,bounds.right,bounds.top];var imageSize=this.getImageSize();var url=this.getFullRequestString({mapext:extent,imgext:extent,map_size:[imageSize.w,imageSize.h],imgx:imageSize.w/2,imgy:imageSize.h/2,imgxy:[imageSize.w,imageSize.h]});return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var paramsString=OpenLayers.Util.getParameterString(allParams);if(url instanceof Array){url=this.selectUrl(paramsString,url);}
 var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
@@ -956,7 +988,7 @@
 var components=[this.layername,zeroPad(tileZ,2),zeroPad(parseInt(tileX/1000000),3),zeroPad((parseInt(tileX/1000)%1000),3),zeroPad((parseInt(tileX)%1000),3),zeroPad(parseInt(tileY/1000000),3),zeroPad((parseInt(tileY/1000)%1000),3),zeroPad((parseInt(tileY)%1000),3)+'.'+this.extension];var path=components.join('/');var url=this.url;if(url instanceof Array){url=this.selectUrl(path,url);}
 url=(url.charAt(url.length-1)=='/')?url:url+'/';return url+path;},addTile:function(bounds,position){var url=this.getURL(bounds);return new OpenLayers.Tile.Image(this,position,bounds,url,this.tileSize);},setMap:function(map){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);if(!this.tileOrigin){this.tileOrigin=new OpenLayers.LonLat(this.map.maxExtent.left,this.map.maxExtent.bottom);}},CLASS_NAME:"OpenLayers.Layer.TileCache"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",exceptions:"application/vnd.ogc.se_inimage",format:"image/jpeg"},reproject:false,isBaseLayer:true,encodeBBOX:false,initialize:function(name,url,params,options){var newArguments=[];params=OpenLayers.Util.upperCaseObject(params);newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));if(this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if((options==null)||(!options.isBaseLayer)){this.isBaseLayer=false;}
 if(this.params.FORMAT=="image/jpeg"){this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png";}}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var imageSize=this.getImageSize();var newParams={'BBOX':this.encodeBBOX?bounds.toBBOX():bounds.toArray(),'WIDTH':imageSize.w,'HEIGHT':imageSize.h};var requestString=this.getFullRequestString(newParams);return requestString;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},mergeNewParams:function(newParams){var upperParams=OpenLayers.Util.upperCaseObject(newParams);var newArguments=[upperParams];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,newArguments);},getFullRequestString:function(newParams,altUrl){var projectionCode=this.map.getProjection();this.params.SRS=(projectionCode=="none")?null:projectionCode;return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Layer.WorldWind=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{},isBaseLayer:true,lzd:null,zoomLevels:null,initialize:function(name,url,lzd,zoomLevels,params,options){this.lzd=lzd;this.zoomLevels=zoomLevels;var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);this.params=(params?params:{});if(params){OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);}},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getZoom:function(){var zoom=this.map.getZoom();var extent=this.map.getMaxExtent();zoom=zoom-Math.log(this.maxResolution/(this.lzd/512))/Math.log(2);return zoom;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var zoom=this.getZoom();var extent=this.map.getMaxExtent();var deg=this.lzd/Math.pow(2,this.getZoom());var x=Math.floor((bounds.left-extent.left)/deg);var y=Math.floor((bounds.bottom-extent.bottom)/deg);if(this.map.getResolution()<=(this.lzd/512)&&this.getZoom()<=this.zoomLevels){return this.getFullRequestString({L:zoom,X:x,Y:y});}else{return OpenLayers.Util.getImagesLocation()+"blank.gif";}},CLASS_NAME:"OpenLayers.Layer.WorldWind"});OpenLayers.Rule=OpenLayers.Class({name:'default',context:null,elseFilter:false,symbolizer:null,minScaleDenominator:null,maxScaleDenominator:null,initialize:function(options){this.symbolizer={};OpenLayers.Util.extend(this,options);},destroy:function(){for(var i in this.symbolizer){this.symbolizer[i]=null;}
+obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var imageSize=this.getImageSize();var newParams={'BBOX':this.encodeBBOX?bounds.toBBOX():bounds.toArray(),'WIDTH':imageSize.w,'HEIGHT':imageSize.h};var requestString=this.getFullRequestString(newParams);return requestString;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},mergeNewParams:function(newParams){var upperParams=OpenLayers.Util.upperCaseObject(newParams);var newArguments=[upperParams];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,newArguments);},getFullRequestString:function(newParams,altUrl){var projectionCode=this.map.getProjection();this.params.SRS=(projectionCode=="none")?null:projectionCode;return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Layer.WorldWind=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{},isBaseLayer:true,lzd:null,zoomLevels:null,initialize:function(name,url,lzd,zoomLevels,params,options){this.lzd=lzd;this.zoomLevels=zoomLevels;var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);this.params=(params?params:{});if(params){OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);}},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getZoom:function(){var zoom=this.map.getZoom();var extent=this.map.getMaxExtent();zoom=zoom-Math.log(this.maxResolution/(this.lzd/512))/Math.log(2);return zoom;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var zoom=this.getZoom();var extent=this.map.getMaxExtent();var deg=this.lzd/Math.pow(2,this.getZoom());var x=Math.floor((bounds.left-extent.left)/deg);var y=Math.floor((bounds.bottom-extent.bottom)/deg);if(this.map.getResolution()<=(this.lzd/512)&&this.getZoom()<=this.zoomLevels){return this.getFullRequestString({L:zoom,X:x,Y:y});}else{return OpenLayers.Util.getImagesLocation()+"blank.gif";}},CLASS_NAME:"OpenLayers.Layer.WorldWind"});OpenLayers.Rule=OpenLayers.Class({id:null,name:'default',title:null,description:null,context:null,elseFilter:false,symbolizer:null,minScaleDenominator:null,maxScaleDenominator:null,initialize:function(options){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");this.symbolizer={};OpenLayers.Util.extend(this,options);},destroy:function(){for(var i in this.symbolizer){this.symbolizer[i]=null;}
 this.symbolizer=null;},evaluate:function(feature){var context=this.getContext(feature);var applies=true;if(this.minScaleDenominator||this.maxScaleDenominator){var scale=feature.layer.map.getScale();}
 if(this.minScaleDenominator){applies=scale>=OpenLayers.Style.createLiteral(this.minScaleDenominator,context);}
 if(applies&&this.maxScaleDenominator){applies=scale<OpenLayers.Style.createLiteral(this.maxScaleDenominator,context);}
@@ -1005,52 +1037,22 @@
 var featureId=this.renderer.getFeatureIdFromEvent(evt);return this.getFeatureById(featureId);},getFeatureById:function(featureId){var feature=null;for(var i=0;i<this.features.length;++i){if(this.features[i].id==featureId){feature=this.features[i];break;}}
 return feature;},onFeatureInsert:function(feature){},preFeatureInsert:function(feature){},CLASS_NAME:"OpenLayers.Layer.Vector"});OpenLayers.Layer.WMS.Untiled=OpenLayers.Class(OpenLayers.Layer.WMS,{singleTile:true,initialize:function(name,url,params,options){OpenLayers.Layer.WMS.prototype.initialize.apply(this,arguments);var msg="The OpenLayers.Layer.WMS.Untiled class is deprecated and "+"will be removed in 3.0. Instead, you should use the "+"normal OpenLayers.Layer.WMS class, passing it the option "+"'singleTile' as true.";OpenLayers.Console.warn(msg);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMS.Untiled(this.name,this.url,this.params,this.options);}
 obj=OpenLayers.Layer.WMS.prototype.clone.apply(this,[obj]);return obj;},CLASS_NAME:"OpenLayers.Layer.WMS.Untiled"});OpenLayers.Rule.Comparison=OpenLayers.Class(OpenLayers.Rule,{type:null,property:null,value:null,lowerBoundary:null,upperBoundary:null,initialize:function(options){OpenLayers.Rule.prototype.initialize.apply(this,[options]);},evaluate:function(feature){if(!OpenLayers.Rule.prototype.evaluate.apply(this,arguments)){return false;}
-var context=this.getContext(feature);switch(this.type){case OpenLayers.Rule.Comparison.EQUAL_TO:case OpenLayers.Rule.Comparison.LESS_THAN:case OpenLayers.Rule.Comparison.GREATER_THAN:case OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO:case OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO:return this.binaryCompare(context,this.property,this.value);case OpenLayers.Rule.Comparison.BETWEEN:var result=context[this.property]>this.lowerBoundary;result=result&&context[this.property]<this.upperBoundary;return result;case OpenLayers.Rule.Comparison.LIKE:var regexp=new RegExp(this.value,"gi");return regexp.test(context[this.property]);}},value2regex:function(wildCard,singleChar,escapeChar){if(wildCard=="."){var msg="'.' is an unsupported wildCard character for "+"OpenLayers.Rule.Comparison";OpenLayers.Console.error(msg);return null;}
-wildCard=wildCard?wildCard:"*";singleChar=singleChar?singleChar:".";escapeChar=escapeChar?escapeChar:"!";this.value=this.value.replace(new RegExp("\\"+escapeChar,"g"),"\\");this.value=this.value.replace(new RegExp("\\"+singleChar,"g"),".");this.value=this.value.replace(new RegExp("\\"+wildCard,"g"),".*");this.value=this.value.replace(new RegExp("\\\\.\\*","g"),"\\"+wildCard);this.value=this.value.replace(new RegExp("\\\\\\.","g"),"\\"+singleChar);return this.value;},binaryCompare:function(context,property,value){switch(this.type){case OpenLayers.Rule.Comparison.EQUAL_TO:return context[property]==value;case OpenLayers.Rule.Comparison.NOT_EQUAL_TO:return context[property]!=value;case OpenLayers.Rule.Comparison.LESS_THAN:return context[property]<value;case OpenLayers.Rule.Comparison.GREATER_THAN:return context[property]>value;case OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO:return context[property]<=value;case OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO:return context[property]>=value;}},CLASS_NAME:"OpenLayers.Rule.Comparison"});OpenLayers.Rule.Comparison.EQUAL_TO="==";OpenLayers.Rule.Comparison.NOT_EQUAL_TO="!=";OpenLayers.Rule.Comparison.LESS_THAN="<";OpenLayers.Rule.Comparison.GREATER_THAN=">";OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO="<=";OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO=">=";OpenLayers.Rule.Comparison.BETWEEN="..";OpenLayers.Rule.Comparison.LIKE="~";OpenLayers.Rule.FeatureId=OpenLayers.Class(OpenLayers.Rule,{fids:null,initialize:function(options){this.fids=[];OpenLayers.Rule.prototype.initialize.apply(this,[options]);},evaluate:function(feature){if(!OpenLayers.Rule.prototype.evaluate.apply(this,arguments)){return false;}
+var context=this.getContext(feature);switch(this.type){case OpenLayers.Rule.Comparison.EQUAL_TO:case OpenLayers.Rule.Comparison.LESS_THAN:case OpenLayers.Rule.Comparison.GREATER_THAN:case OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO:case OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO:return this.binaryCompare(context,this.property,this.value);case OpenLayers.Rule.Comparison.BETWEEN:var result=context[this.property]>=this.lowerBoundary;result=result&&context[this.property]<=this.upperBoundary;return result;case OpenLayers.Rule.Comparison.LIKE:var regexp=new RegExp(this.value,"gi");return regexp.test(context[this.property]);}},value2regex:function(wildCard,singleChar,escapeChar){if(wildCard=="."){var msg="'.' is an unsupported wildCard character for "+"OpenLayers.Rule.Comparison";OpenLayers.Console.error(msg);return null;}
+wildCard=wildCard?wildCard:"*";singleChar=singleChar?singleChar:".";escapeChar=escapeChar?escapeChar:"!";this.value=this.value.replace(new RegExp("\\"+escapeChar,"g"),"\\");this.value=this.value.replace(new RegExp("\\"+singleChar,"g"),".");this.value=this.value.replace(new RegExp("\\"+wildCard,"g"),".*");this.value=this.value.replace(new RegExp("\\\\.\\*","g"),"\\"+wildCard);this.value=this.value.replace(new RegExp("\\\\\\.","g"),"\\"+singleChar);return this.value;},regex2value:function(){var value=this.value;value=value.replace(/!/g,"!!");value=value.replace(/(\\)?\\\./g,function($0,$1){return $1?$0:"!.";});value=value.replace(/(\\)?\\\*/g,function($0,$1){return $1?$0:"!*";});value=value.replace(/\\\\/g,"\\");value=value.replace(/\.\*/g,"*");return value;},binaryCompare:function(context,property,value){switch(this.type){case OpenLayers.Rule.Comparison.EQUAL_TO:return context[property]==value;case OpenLayers.Rule.Comparison.NOT_EQUAL_TO:return context[property]!=value;case OpenLayers.Rule.Comparison.LESS_THAN:return context[property]<value;case OpenLayers.Rule.Comparison.GREATER_THAN:return context[property]>value;case OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO:return context[property]<=value;case OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO:return context[property]>=value;}},CLASS_NAME:"OpenLayers.Rule.Comparison"});OpenLayers.Rule.Comparison.EQUAL_TO="==";OpenLayers.Rule.Comparison.NOT_EQUAL_TO="!=";OpenLayers.Rule.Comparison.LESS_THAN="<";OpenLayers.Rule.Comparison.GREATER_THAN=">";OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO="<=";OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO=">=";OpenLayers.Rule.Comparison.BETWEEN="..";OpenLayers.Rule.Comparison.LIKE="~";OpenLayers.Rule.FeatureId=OpenLayers.Class(OpenLayers.Rule,{fids:null,initialize:function(options){this.fids=[];OpenLayers.Rule.prototype.initialize.apply(this,[options]);},evaluate:function(feature){if(!OpenLayers.Rule.prototype.evaluate.apply(this,arguments)){return false;}
 for(var i=0;i<this.fids.length;i++){var fid=feature.fid||feature.id;if(fid==this.fids[i]){return true;}}
 return false;},CLASS_NAME:"OpenLayers.Rule.FeatureId"});OpenLayers.Rule.Logical=OpenLayers.Class(OpenLayers.Rule,{rules:null,type:null,initialize:function(options){this.rules=[];OpenLayers.Rule.prototype.initialize.apply(this,[options]);},destroy:function(){for(var i=0;i<this.rules.length;i++){this.rules[i].destroy();}
 this.rules=null;OpenLayers.Rule.prototype.destroy.apply(this,arguments);},evaluate:function(feature){if(!OpenLayers.Rule.prototype.evaluate.apply(this,arguments)){return false;}
 switch(this.type){case OpenLayers.Rule.Logical.AND:for(var i=0;i<this.rules.length;i++){if(this.rules[i].evaluate(feature)==false){return false;}}
 return true;case OpenLayers.Rule.Logical.OR:for(var i=0;i<this.rules.length;i++){if(this.rules[i].evaluate(feature)==true){return true;}}
-return false;case OpenLayers.Rule.Logical.NOT:return(!this.rules[0].evaluate(feature));}},CLASS_NAME:"OpenLayers.Rule.Logical"});OpenLayers.Rule.Logical.AND="&&";OpenLayers.Rule.Logical.OR="||";OpenLayers.Rule.Logical.NOT="!";OpenLayers.Format.SLD=OpenLayers.Class(OpenLayers.Format.XML,{sldns:"http://www.opengis.net/sld",ogcns:"http://www.opengis.net/ogc",gmlns:"http://www.opengis.net/gml",defaultStyle:{fillColor:"#808080",fillOpacity:1,strokeColor:"#000000",strokeOpacity:1,strokeWidth:1,pointRadius:6},withNamedLayer:false,overrideDefaultStyleKey:true,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data,options){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
-options=options||{};OpenLayers.Util.applyDefaults(options,{withNamedLayer:false,overrideDefaultStyleKey:true});var userStyles=this.getElementsByTagNameNS(data,this.sldns,"UserStyle");var result={};if(userStyles.length>0){var namedLayer={};var styles=new Array(userStyles.length);var styleName,userStyle,style;for(var i=0;i<userStyles.length;i++){userStyle=userStyles[i];styleName=this.parseProperty(userStyle,this.sldns,"Name");style=this.parseUserStyle(userStyle,styleName);if(options.overrideDefaultStyleKey&&style.isDefault==true){styleName="default";}
-if(!namedLayer[style.layerName]){namedLayer[style.layerName]={};}
-namedLayer[style.layerName][styleName]=style;styles[i]=style;}
-result=options.withNamedLayer?[styles,namedLayer]:styles;}
-return result;},parseUserStyle:function(xmlNode,name){var userStyle=new OpenLayers.Style(this.defaultStyle,{name:name});userStyle.isDefault=(this.parseProperty(xmlNode,this.sldns,"IsDefault")==1);var namedLayerNode=xmlNode.parentNode;var nameNodes=this.getElementsByTagNameNS(namedLayerNode,this.sldns,"Name");if(namedLayerNode.nodeName.indexOf("NamedLayer")!=-1&&nameNodes&&nameNodes.length>0&&nameNodes[0].parentNode==namedLayerNode){userStyle.layerName=this.getChildValue(nameNodes[0]);}
-var ruleNodes=this.getElementsByTagNameNS(xmlNode,this.sldns,"Rule");if(ruleNodes.length>0){var rules=userStyle.rules;var ruleName;for(var i=0;i<ruleNodes.length;i++){ruleName=this.parseProperty(ruleNodes[i],this.sldns,"Name");rules.push(this.parseRule(ruleNodes[i],ruleName));}}
-return userStyle;},parseRule:function(xmlNode,name){var filter=this.getElementsByTagNameNS(xmlNode,this.ogcns,"Filter");if(filter&&filter.length>0){var rule=this.parseFilter(filter[0]);}else{var rule=new OpenLayers.Rule();var elseFilter=this.getElementsByTagNameNS(xmlNode,this.ogcns,"ElseFilter");if(elseFilter&&elseFilter.length>0){rule.elseFilter=true;}}
-rule.name=name;var minScale=this.getElementsByTagNameNS(xmlNode,this.sldns,"MinScaleDenominator");if(minScale&&minScale.length>0){rule.minScaleDenominator=parseFloat(this.getChildValue(minScale[0]));}
-var maxScale=this.getElementsByTagNameNS(xmlNode,this.sldns,"MaxScaleDenominator");if(maxScale&&maxScale.length>0){rule.maxScaleDenominator=parseFloat(this.getChildValue(maxScale[0]));}
-var prefixes=OpenLayers.Style.SYMBOLIZER_PREFIXES;for(var s=0;s<prefixes.length;s++){var symbolizer=this.getElementsByTagNameNS(xmlNode,this.sldns,prefixes[s]+"Symbolizer");if(symbolizer&&symbolizer.length>0){var style={};var graphic=this.getElementsByTagNameNS(symbolizer[0],this.sldns,"Graphic");if(graphic&&graphic.length>0){style.externalGraphic=this.parseProperty(graphic[0],this.sldns,"OnlineResource","xlink:href");style.pointRadius=this.parseProperty(graphic[0],this.sldns,"Size");style.graphicOpacity=this.parseProperty(graphic[0],this.sldns,"Opacity");}
-var fill=this.getElementsByTagNameNS(symbolizer[0],this.sldns,"Fill");if(fill&&fill.length>0){style.fillColor=this.parseProperty(fill[0],this.sldns,"CssParameter","name","fill");style.fillOpacity=this.parseProperty(fill[0],this.sldns,"CssParameter","name","fill-opacity")||1;}
-var stroke=this.getElementsByTagNameNS(symbolizer[0],this.sldns,"Stroke");if(stroke&&stroke.length>0){style.strokeColor=this.parseProperty(stroke[0],this.sldns,"CssParameter","name","stroke");style.strokeOpacity=this.parseProperty(stroke[0],this.sldns,"CssParameter","name","stroke-opacity")||1;style.strokeWidth=this.parseProperty(stroke[0],this.sldns,"CssParameter","name","stroke-width");style.strokeLinecap=this.parseProperty(stroke[0],this.sldns,"CssParameter","name","stroke-linecap");}
-rule.symbolizer[prefixes[s]]=style;}}
-return rule;},parseFilter:function(xmlNode){var filter=this.getNodeOrChildrenByTagName(xmlNode,"FeatureId");if(filter){var rule=new OpenLayers.Rule.FeatureId();for(var i=0;i<filter.length;i++){rule.fids.push(filter[i].getAttribute("fid"));}
-return rule;}
-filter=this.getNodeOrChildrenByTagName(xmlNode,"And");if(filter){var rule=new OpenLayers.Rule.Logical({type:OpenLayers.Rule.Logical.AND});var filters=filter[0].childNodes;for(var i=0;i<filters.length;i++){if(filters[i].nodeType==1){rule.rules.push(this.parseFilter(filters[i]));}}
-return rule;}
-filter=this.getNodeOrChildrenByTagName(xmlNode,"Or");if(filter){var rule=new OpenLayers.Rule.Logical({type:OpenLayers.Rule.Logical.OR})
-var filters=filter[0].childNodes;for(var i=0;i<filters.length;i++){if(filters[i].nodeType==1){rule.rules.push(this.parseFilter(filters[i]));}}
-return rule;}
-filter=this.getNodeOrChildrenByTagName(xmlNode,"Not");if(filter){var rule=new OpenLayers.Rule.Logical({type:OpenLayers.Rule.Logical.NOT});var filters=filter[0].childNodes;for(var i=0;i<filters.length;i++){if(filters[i].nodeType==1){rule.rules.push(this.parseFilter(filters[i]));}}
-return rule;}
-for(var type in this.TYPES){var filter=this.getNodeOrChildrenByTagName(xmlNode,type);if(filter){filter=filter[0];var rule=new OpenLayers.Rule.Comparison({type:OpenLayers.Rule.Comparison[this.TYPES[type]],property:this.parseProperty(filter,this.ogcns,"PropertyName")});if(this.TYPES[type]=="BETWEEN"){rule.lowerBoundary=this.parseProperty(filter,this.ogcns,"LowerBoundary");rule.upperBoudary=this.parseProperty(filter,this.ogcns,"UpperBoundary");}else{rule.value=this.parseProperty(filter,this.ogcns,"Literal");if(this.TYPES[type]=="LIKE"){var wildCard=filter.getAttribute("wildCard");var singleChar=filter.getAttribute("singleChar");var escape=filter.getAttribute("escape");rule.value2regex(wildCard,singleChar,escape);}}
-return rule;}}
-return new OpenLayers.Rule();},getNodeOrChildrenByTagName:function(xmlNode,tagName){var nodeName=(xmlNode.prefix)?xmlNode.nodeName.split(":")[1]:xmlNode.nodeName;if(nodeName==tagName){return[xmlNode];}else{var nodelist=this.getElementsByTagNameNS(xmlNode,this.ogcns,tagName);}
-if(nodelist.length>0){var node;var list=[];for(var i=0;i<nodelist.length;i++){node=nodelist[i];if(node.parentNode==xmlNode){list.push(node);}}
-return list.length>0?list:null;}
-return null;},parseProperty:function(xmlNode,namespace,propertyName,attributeName,attributeValue){var result=null;var propertyNodeList=this.getElementsByTagNameNS(xmlNode,namespace,propertyName);if(propertyNodeList&&propertyNodeList.length>0){var propertyNode=attributeName?this.getNodeWithAttribute(propertyNodeList,attributeName):propertyNodeList[0];if(window.opera&&attributeName){var nsDelimiterPos=attributeName.indexOf(":");if(nsDelimiterPos!=-1){attributeName=attributeName.substring(++nsDelimiterPos);}}
-if(attributeName&&attributeValue){propertyNode=this.getNodeWithAttribute(propertyNodeList,attributeName,attributeValue);result=this.parseParameter(propertyNode);}
-if(attributeName&&!attributeValue){var propertyNode=this.getNodeWithAttribute(propertyNodeList,attributeName);result=propertyNode.getAttribute(attributeName);}
-if(!attributeName){var result=this.parseParameter(propertyNode);}}
-if(result){result=OpenLayers.String.trim(result);if(!isNaN(result)){result=parseFloat(result);}}
-return result;},parseParameter:function(xmlNode){if(!xmlNode){return null;}
-var childNodes=xmlNode.childNodes;if(!childNodes){return null;}
-var value=new Array(childNodes.length);for(var i=0;i<childNodes.length;i++){if(childNodes[i].nodeName.indexOf("Literal")!=-1){value[i]=this.getChildValue(childNodes[i]);}else
-if(childNodes[i].nodeName.indexOf("propertyName")!=-1){value[i]="${"+this.getChildValue(childNodes[i])+"}";}else
-if(childNodes[i].nodeType==3){value[i]=childNodes[i].text||childNodes[i].textContent;}}
-return value.join("");},getNodeWithAttribute:function(xmlNodeList,attributeName,attributeValue){for(var i=0;i<xmlNodeList.length;i++){var currentAttributeValue=xmlNodeList[i].getAttribute(attributeName);if(currentAttributeValue){if(!attributeValue){return xmlNodeList[i];}else if(currentAttributeValue==attributeValue){return xmlNodeList[i];}}}},TYPES:{'PropertyIsEqualTo':'EQUAL_TO','PropertyIsNotEqualTo':'NOT_EQUAL_TO','PropertyIsLessThan':'LESS_THAN','PropertyIsGreaterThan':'GREATER_THAN','PropertyIsLessThanOrEqualTo':'LESS_THAN_OR_EQUAL_TO','PropertyIsGreaterThanOrEqualTo':'GREATER_THAN_OR_EQUAL_TO','PropertyIsBetween':'BETWEEN','PropertyIsLike':'LIKE'},CLASS_NAME:"OpenLayers.Format.SLD"});OpenLayers.Format.Text=OpenLayers.Class(OpenLayers.Format,{initialize:function(options){OpenLayers.Format.prototype.initialize.apply(this,[options]);},read:function(text){var lines=text.split('\n');var columns;var features=[];for(var lcv=0;lcv<(lines.length-1);lcv++){var currLine=lines[lcv].replace(/^\s*/,'').replace(/\s*$/,'');if(currLine.charAt(0)!='#'){if(!columns){columns=currLine.split('\t');}else{var vals=currLine.split('\t');var geometry=new OpenLayers.Geometry.Point(0,0);var attributes={};var style={};var icon,iconSize,iconOffset,overflow;var set=false;for(var valIndex=0;valIndex<vals.length;valIndex++){if(vals[valIndex]){if(columns[valIndex]=='point'){var coords=vals[valIndex].split(',');geometry.y=parseFloat(coords[0]);geometry.x=parseFloat(coords[1]);set=true;}else if(columns[valIndex]=='lat'){geometry.y=parseFloat(vals[valIndex]);set=true;}else if(columns[valIndex]=='lon'){geometry.x=parseFloat(vals[valIndex]);set=true;}else if(columns[valIndex]=='title')
+return false;case OpenLayers.Rule.Logical.NOT:return(!this.rules[0].evaluate(feature));}},CLASS_NAME:"OpenLayers.Rule.Logical"});OpenLayers.Rule.Logical.AND="&&";OpenLayers.Rule.Logical.OR="||";OpenLayers.Rule.Logical.NOT="!";OpenLayers.Format.SLD=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:"1.0.0",version:null,parser:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},write:function(sld,options){var version=(options&&options.version)||this.version||this.defaultVersion;if(!this.parser||this.parser.VERSION!=version){var format=OpenLayers.Format.SLD["v"+version.replace(/\./g,"_")];if(!format){throw"Can't find a SLD parser for version "+
+version;}
+this.parser=new format(this.options);}
+var root=this.parser.write(sld);return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},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;}}
+if(!this.parser||this.parser.VERSION!=version){var format=OpenLayers.Format.SLD["v"+version.replace(/\./g,"_")];if(!format){throw"Can't find a SLD parser for version "+
+version;}
+this.parser=new format(this.options);}
+var sld=this.parser.read(data);return sld;},CLASS_NAME:"OpenLayers.Format.SLD"});OpenLayers.Format.Text=OpenLayers.Class(OpenLayers.Format,{initialize:function(options){OpenLayers.Format.prototype.initialize.apply(this,[options]);},read:function(text){var lines=text.split('\n');var columns;var features=[];for(var lcv=0;lcv<(lines.length-1);lcv++){var currLine=lines[lcv].replace(/^\s*/,'').replace(/\s*$/,'');if(currLine.charAt(0)!='#'){if(!columns){columns=currLine.split('\t');}else{var vals=currLine.split('\t');var geometry=new OpenLayers.Geometry.Point(0,0);var attributes={};var style={};var icon,iconSize,iconOffset,overflow;var set=false;for(var valIndex=0;valIndex<vals.length;valIndex++){if(vals[valIndex]){if(columns[valIndex]=='point'){var coords=vals[valIndex].split(',');geometry.y=parseFloat(coords[0]);geometry.x=parseFloat(coords[1]);set=true;}else if(columns[valIndex]=='lat'){geometry.y=parseFloat(vals[valIndex]);set=true;}else if(columns[valIndex]=='lon'){geometry.x=parseFloat(vals[valIndex]);set=true;}else if(columns[valIndex]=='title')
 attributes['title']=vals[valIndex];else if(columns[valIndex]=='image'||columns[valIndex]=='icon')
 style['externalGraphic']=vals[valIndex];else if(columns[valIndex]=='iconSize'){var size=vals[valIndex].split(',');style['graphicWidth']=parseFloat(size[0]);style['graphicHeight']=parseFloat(size[1]);}else if(columns[valIndex]=='iconOffset'){var offset=vals[valIndex].split(',');style['graphicXOffset']=parseFloat(offset[0]);style['graphicYOffset']=parseFloat(offset[1]);}else if(columns[valIndex]=='description'){attributes['description']=vals[valIndex];}else if(columns[valIndex]=='overflow'){attributes['overflow']=vals[valIndex];}}}
 if(set){if(this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection);}
@@ -1100,14 +1102,64 @@
 return obj;},getFullRequestString:function(newParams,altUrl){var projectionCode=this.map.getProjection();this.params.SRS=(projectionCode=="none")?null:projectionCode;return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},commit:function(){if(!this.writer){var options={};if(this.map&&!this.projection.equals(this.map.getProjectionObject())){options.externalProjection=this.projection;options.internalProjection=this.map.getProjectionObject();}
 this.writer=new OpenLayers.Format.WFS(options,this);}
 var data=this.writer.write(this.features);var url=this.url;var success=OpenLayers.Function.bind(this.commitSuccess,this);var failure=OpenLayers.Function.bind(this.commitFailure,this);new OpenLayers.Ajax.Request(url,{method:'post',postBody:data,onComplete:success,onFailure:failure});},commitSuccess:function(request){var response=request.responseText;if(response.indexOf('SUCCESS')!=-1){this.commitReport(OpenLayers.i18n("commitSuccess",{'response':response}));for(var i=0;i<this.features.length;i++){this.features[i].state=null;}}else if(response.indexOf('FAILED')!=-1||response.indexOf('Exception')!=-1){this.commitReport(OpenLayers.i18n("commitFailed",{'response':response}));}},commitFailure:function(request){},commitReport:function(string,response){alert(string);},refresh:function(){if(this.tile){if(this.vectorMode){this.renderer.clear();this.features.length=0;}else{this.clearMarkers();this.markers.length=0;}
-this.tile.draw();}},CLASS_NAME:"OpenLayers.Layer.WFS"});OpenLayers.Geometry.Curve=OpenLayers.Class(OpenLayers.Geometry.MultiPoint,{componentTypes:["OpenLayers.Geometry.Point"],initialize:function(points){OpenLayers.Geometry.MultiPoint.prototype.initialize.apply(this,arguments);},getLength:function(){var length=0.0;if(this.components&&(this.components.length>1)){for(var i=1;i<this.components.length;i++){length+=this.components[i-1].distanceTo(this.components[i]);}}
-return length;},CLASS_NAME:"OpenLayers.Geometry.Curve"});OpenLayers.Geometry.LineString=OpenLayers.Class(OpenLayers.Geometry.Curve,{initialize:function(points){OpenLayers.Geometry.Curve.prototype.initialize.apply(this,arguments);},removeComponent:function(point){if(this.components&&(this.components.length>2)){OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);}},intersects:function(geometry){var intersect=false;var type=geometry.CLASS_NAME;if(type=="OpenLayers.Geometry.LineString"||type=="OpenLayers.Geometry.LinearRing"||type=="OpenLayers.Geometry.Point"){var segs1=this.getSortedSegments();var segs2;if(type=="OpenLayers.Geometry.Point"){segs2=[{x1:geometry.x,y1:geometry.y,x2:geometry.x,y2:geometry.y}];}else{segs2=geometry.getSortedSegments();}
+this.tile.draw();}},CLASS_NAME:"OpenLayers.Layer.WFS"});OpenLayers.Format.SLD.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{sld:"http://www.opengis.net/sld",ogc:"http://www.opengis.net/ogc",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"sld",schemaLocation:null,defaultSymbolizer:{fillColor:"#808080",fillOpacity:1,strokeColor:"#000000",strokeOpacity:1,strokeWidth:1,pointRadius:6},initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){var sld={namedLayers:{}};this.readChildNodes(data,sld);return sld;},readers:{"sld":{"StyledLayerDescriptor":function(node,sld){sld.version=node.getAttribute("version");this.readChildNodes(node,sld);},"Name":function(node,obj){obj.name=this.getChildValue(node);},"Title":function(node,obj){obj.title=this.getChildValue(node);},"Abstract":function(node,obj){obj.description=this.getChildValue(node);},"NamedLayer":function(node,sld){var layer={userStyles:[],namedStyles:[]};this.readChildNodes(node,layer);for(var i=0;i<layer.userStyles.length;++i){layer.userStyles[i].layerName=layer.name;}
+sld.namedLayers[layer.name]=layer;},"NamedStyle":function(node,layer){layer.namedStyles.push(this.getChildName(node.firstChild));},"UserStyle":function(node,layer){var style=new OpenLayers.Style(this.defaultSymbolizer);this.readChildNodes(node,style);layer.userStyles.push(style);},"IsDefault":function(node,style){if(this.getChildValue(node)=="1"){style.isDefault=true;}},"FeatureTypeStyle":function(node,style){var obj={rules:[]};this.readChildNodes(node,obj);style.rules=obj.rules;},"Rule":function(node,obj){var config={rules:[],symbolizer:{}};this.readChildNodes(node,config);var rule;if(config.rules.length==0){delete config.rules;rule=new OpenLayers.Rule(config);}else{rule=config.rules[0];delete config.rules;OpenLayers.Util.extend(rule,config);}
+obj.rules.push(rule);},"ElseFilter":function(node,rule){rule.elseFilter=true;},"MinScaleDenominator":function(node,rule){rule.minScaleDenominator=this.getChildValue(node);},"MaxScaleDenominator":function(node,rule){rule.maxScaleDenominator=this.getChildValue(node);},"LineSymbolizer":function(node,rule){var symbolizer=rule.symbolizer["Line"]||{};this.readChildNodes(node,symbolizer);rule.symbolizer["Line"]=symbolizer;},"PolygonSymbolizer":function(node,rule){var symbolizer=rule.symbolizer["Polygon"]||{};this.readChildNodes(node,symbolizer);rule.symbolizer["Polygon"]=symbolizer;},"PointSymbolizer":function(node,rule){var symbolizer=rule.symbolizer["Point"]||{};this.readChildNodes(node,symbolizer);rule.symbolizer["Point"]=symbolizer;},"Stroke":function(node,symbolizer){this.readChildNodes(node,symbolizer);},"Fill":function(node,symbolizer){this.readChildNodes(node,symbolizer);},"CssParameter":function(node,symbolizer){var cssProperty=node.getAttribute("name");var symProperty=this.cssMap[cssProperty];if(symProperty){var value=this.readOgcExpression(node);if(value){symbolizer[symProperty]=value;}}},"Graphic":function(node,symbolizer){var graphic={};this.readChildNodes(node,graphic);var properties=["strokeColor","strokeWidth","strokeOpacity","strokeLinecap","fillColor","fillOpacity","graphicName","rotation","graphicFormat"];var prop,value;for(var i=0;i<properties.length;++i){prop=properties[i];value=graphic[prop];if(value!=undefined){symbolizer[prop]=value;}}
+if(graphic.opacity!=undefined){symbolizer.graphicOpacity=graphic.opacity;}
+if(graphic.size!=undefined){symbolizer.pointRadius=graphic.size;}
+if(graphic.href!=undefined){symbolizer.externalGraphic=graphic.href;}},"ExternalGraphic":function(node,graphic){this.readChildNodes(node,graphic);},"Mark":function(node,graphic){this.readChildNodes(node,graphic);},"WellKnownName":function(node,graphic){graphic.graphicName=this.getChildValue(node);},"Opacity":function(node,obj){var opacity=this.getChildValue(node);if(opacity){obj.opacity=opacity;}},"Size":function(node,obj){var size=this.getChildValue(node);if(size){obj.size=size;}},"Rotation":function(node,obj){var rotation=this.getChildValue(node);if(rotation){obj.rotation=rotation;}},"OnlineResource":function(node,obj){obj.href=this.getAttributeNS(node,this.namespaces.xlink,"href");},"Format":function(node,graphic){graphic.graphicFormat=this.getChildValue(node);}},"ogc":{"Filter":function(node,rule){var filter={fids:[],rules:[]};this.readChildNodes(node,filter);if(filter.fids.length>0){rule.rules.push(new OpenLayers.Rule.FeatureId({fids:filter.fids}));}
+if(filter.rules.length>0){rule.rules=rule.rules.concat(filter.rules);}},"FeatureId":function(node,filter){var fid=node.getAttribute("fid");if(fid){filter.fids.push(fid);}},"And":function(node,filter){var rule=new OpenLayers.Rule.Logical({type:OpenLayers.Rule.Logical.AND});rule.fids=[];this.readChildNodes(node,rule);if(rule.fids.length>0){rule.rules.push(new OpenLayers.Rule.FeatureId({fids:rule.fids}));}
+delete rule.fids;filter.rules.push(rule);},"Or":function(node,filter){var rule=new OpenLayers.Rule.Logical({type:OpenLayers.Rule.Logical.OR});rule.fids=[];this.readChildNodes(node,rule);if(rule.fids.length>0){rule.rules.push(new OpenLayers.Rule.FeatureId({fids:rule.fids}));}
+delete rule.fids;filter.rules.push(rule);},"Not":function(node,filter){var rule=new OpenLayers.Rule.Logical({type:OpenLayers.Rule.Logical.NOT});rule.fids=[];this.readChildNodes(node,rule);if(rule.fids.length>0){rule.rules.push(new OpenLayers.Rule.FeatureId({fids:rule.fids}));}
+delete rule.fids;filter.rules.push(rule);},"PropertyIsEqualTo":function(node,filter){var rule=new OpenLayers.Rule.Comparison({type:OpenLayers.Rule.Comparison.EQUAL_TO});this.readChildNodes(node,rule);filter.rules.push(rule);},"PropertyIsNotEqualTo":function(node,filter){var rule=new OpenLayers.Rule.Comparison({type:OpenLayers.Rule.Comparison.NOT_EQUAL_TO});this.readChildNodes(node,rule);filter.rules.push(rule);},"PropertyIsLessThan":function(node,filter){var rule=new OpenLayers.Rule.Comparison({type:OpenLayers.Rule.Comparison.LESS_THAN});this.readChildNodes(node,rule);filter.rules.push(rule);},"PropertyIsGreaterThan":function(node,filter){var rule=new OpenLayers.Rule.Comparison({type:OpenLayers.Rule.Comparison.GREATER_THAN});this.readChildNodes(node,rule);filter.rules.push(rule);},"PropertyIsLessThanOrEqualTo":function(node,filter){var rule=new OpenLayers.Rule.Comparison({type:OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO});this.readChildNodes(node,rule);filter.rules.push(rule);},"PropertyIsGreaterThanOrEqualTo":function(node,filter){var rule=new OpenLayers.Rule.Comparison({type:OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO});this.readChildNodes(node,rule);filter.rules.push(rule);},"PropertyIsBetween":function(node,filter){var rule=new OpenLayers.Rule.Comparison({type:OpenLayers.Rule.Comparison.BETWEEN});this.readChildNodes(node,rule);filter.rules.push(rule);},"PropertyIsLike":function(node,filter){var rule=new OpenLayers.Rule.Comparison({type:OpenLayers.Rule.Comparison.LIKE});this.readChildNodes(node,rule);var wildCard=node.getAttribute("wildCard");var singleChar=node.getAttribute("singleChar");var esc=node.getAttribute("escape");rule.value2regex(wildCard,singleChar,esc);filter.rules.push(rule);},"Literal":function(node,obj){obj.value=this.getChildValue(node);},"PropertyName":function(node,rule){rule.property=this.getChildValue(node);},"LowerBoundary":function(node,rule){rule.lowerBoundary=this.readOgcExpression(node);},"UpperBoundary":function(node,rule){rule.upperBoundary=this.readOgcExpression(node);}}},readOgcExpression:function(node){var obj={};this.readChildNodes(node,obj);var value=obj.value;if(!value){value=this.getChildValue(node);}
+return value;},cssMap:{"stroke":"strokeColor","stroke-opacity":"strokeOpacity","stroke-width":"strokeWidth","stroke-linecap":"strokeLinecap","fill":"fillColor","fill-opacity":"fillOpacity"},getCssProperty:function(sym){var css=null;for(var prop in this.cssMap){if(this.cssMap[prop]==sym){css=prop;break;}}
+return css;},getGraphicFormat:function(href){var format,regex;for(var key in this.graphicFormats){if(this.graphicFormats[key].test(href)){format=key;break;}}
+return format||this.defautlGraphicFormat;},defaultGraphicFormat:"image/png",graphicFormats:{"image/jpeg":/\.jpe?g$/i,"image/gif":/\.gif$/i,"image/png":/\.png$/i},write:function(sld){return this.writers.sld.StyledLayerDescriptor.apply(this,[sld]);},writers:{"sld":{"StyledLayerDescriptor":function(sld){var root=this.createElementNSPlus("StyledLayerDescriptor",{attributes:{"version":this.VERSION,"xsi:schemaLocation":this.schemaLocation}});if(sld.name){this.writeNode(root,"Name",sld.name);}
+if(sld.title){this.writeNode(root,"Title",sld.title);}
+if(sld.description){this.writeNode(root,"Abstract",sld.description);}
+for(var name in sld.namedLayers){this.writeNode(root,"NamedLayer",sld.namedLayers[name]);}
+return root;},"Name":function(name){return this.createElementNSPlus("Name",{value:name});},"Title":function(title){return this.createElementNSPlus("Title",{value:title});},"Abstract":function(description){return this.createElementNSPlus("Abstract",{value:description});},"NamedLayer":function(layer){var node=this.createElementNSPlus("NamedLayer");this.writeNode(node,"Name",layer.name);if(layer.namedStyles){for(var i=0;i<layer.namedStyles.length;++i){this.writeNode(node,"NamedStyle",layer.namedStyles[i]);}}
+if(layer.userStyles){for(var i=0;i<layer.userStyles.length;++i){this.writeNode(node,"UserStyle",layer.userStyles[i]);}}
+return node;},"NamedStyle":function(name){var node=this.createElementNSPlus("NamedStyle");this.writeNode(node,"Name",name);return node;},"UserStyle":function(style){var node=this.createElementNSPlus("UserStyle");if(style.name){this.writeNode(node,"Name",style.name);}
+if(style.title){this.writeNode(node,"Title",style.title);}
+if(style.description){this.writeNode(node,"Abstract",style.description);}
+if(style.isDefault){this.writeNode(node,"IsDefault",style.isDefault);}
+this.writeNode(node,"FeatureTypeStyle",style);return node;},"IsDefault":function(bool){return this.createElementNSPlus("IsDefault",{value:(bool)?"1":"0"});},"FeatureTypeStyle":function(style){var node=this.createElementNSPlus("FeatureTypeStyle");for(var i=0;i<style.rules.length;++i){this.writeNode(node,"Rule",style.rules[i]);}
+return node;},"Rule":function(rule){var node=this.createElementNSPlus("Rule");if(rule.name){this.writeNode(node,"Name",rule.name);}
+if(rule.title){this.writeNode(node,"Title",rule.title);}
+if(rule.description){this.writeNode(node,"Abstract",rule.description);}
+if(rule.elseFilter){this.writeNode(node,"ElseFilter");}else if(rule.CLASS_NAME!="OpenLayers.Rule"){this.writeNode(node,"ogc:Filter",rule);}
+if(rule.minScaleDenominator!=undefined){this.writeNode(node,"MinScaleDenominator",rule.minScaleDenominator);}
+if(rule.maxScaleDenominator!=undefined){this.writeNode(node,"MaxScaleDenominator",rule.maxScaleDenominator);}
+var types=OpenLayers.Style.SYMBOLIZER_PREFIXES;var type,symbolizer;for(var i=0;i<types.length;++i){type=types[i];symbolizer=rule.symbolizer[type];if(symbolizer){this.writeNode(node,type+"Symbolizer",symbolizer);}}
+return node;},"ElseFilter":function(){return this.createElementNSPlus("ElseFilter");},"MinScaleDenominator":function(scale){return this.createElementNSPlus("MinScaleDenominator",{value:scale});},"MaxScaleDenominator":function(scale){return this.createElementNSPlus("MaxScaleDenominator",{value:scale});},"LineSymbolizer":function(symbolizer){var node=this.createElementNSPlus("LineSymbolizer");this.writeNode(node,"Stroke",symbolizer);return node;},"Stroke":function(symbolizer){var node=this.createElementNSPlus("Stroke");if(symbolizer.strokeColor!=undefined){this.writeNode(node,"CssParameter",{symbolizer:symbolizer,key:"strokeColor"});}
+if(symbolizer.strokeOpacity!=undefined){this.writeNode(node,"CssParameter",{symbolizer:symbolizer,key:"strokeOpacity"});}
+if(symbolizer.strokeWidth!=undefined){this.writeNode(node,"CssParameter",{symbolizer:symbolizer,key:"strokeWidth"});}
+return node;},"CssParameter":function(obj){return this.createElementNSPlus("CssParameter",{attributes:{name:this.getCssProperty(obj.key)},value:obj.symbolizer[obj.key]});},"PolygonSymbolizer":function(symbolizer){var node=this.createElementNSPlus("PolygonSymbolizer");this.writeNode(node,"Fill",symbolizer);this.writeNode(node,"Stroke",symbolizer);return node;},"Fill":function(symbolizer){var node=this.createElementNSPlus("Fill");if(symbolizer.fillColor){this.writeNode(node,"CssParameter",{symbolizer:symbolizer,key:"fillColor"});}
+if(symbolizer.fillOpacity){this.writeNode(node,"CssParameter",{symbolizer:symbolizer,key:"fillOpacity"});}
+return node;},"PointSymbolizer":function(symbolizer){var node=this.createElementNSPlus("PointSymbolizer");this.writeNode(node,"Graphic",symbolizer);return node;},"Graphic":function(symbolizer){var node=this.createElementNSPlus("Graphic");if(symbolizer.externalGraphic!=undefined){this.writeNode(node,"ExternalGraphic",symbolizer);}else if(symbolizer.graphicName){this.writeNode(node,"Mark",symbolizer);}
+if(symbolizer.graphicOpacity!=undefined){this.writeNode(node,"Opacity",symbolizer.graphicOpacity);}
+if(symbolizer.pointRadius!=undefined){this.writeNode(node,"Size",symbolizer.pointRadius);}
+if(symbolizer.rotation!=undefined){this.writeNode(node,"Rotation",symbolizer.rotation);}
+return node;},"ExternalGraphic":function(symbolizer){var node=this.createElementNSPlus("ExternalGraphic");this.writeNode(node,"OnlineResource",symbolizer.externalGraphic);var format=symbolizer.graphicFormat||this.getGraphicFormat(symbolizer.externalGraphic);this.writeNode(node,"Format",format);return node;},"Mark":function(symbolizer){var node=this.createElementNSPlus("Mark");this.writeNode(node,"WellKnownName",symbolizer.graphicName);this.writeNode(node,"Fill",symbolizer);this.writeNode(node,"Stroke",symbolizer);return node;},"WellKnownName":function(name){return this.createElementNSPlus("WellKnownName",{value:name});},"Opacity":function(value){return this.createElementNSPlus("Opacity",{value:value});},"Size":function(value){return this.createElementNSPlus("Size",{value:value});},"Rotation":function(value){return this.createElementNSPlus("Rotation",{value:value});},"OnlineResource":function(href){return this.createElementNSPlus("OnlineResource",{attributes:{"xlink:type":"simple","xlink:href":href}});},"Format":function(format){return this.createElementNSPlus("Format",{value:format});}},"ogc":{"Filter":function(rule){var node=this.createElementNSPlus("ogc:Filter");var sub=rule.CLASS_NAME.split(".").pop();if(sub=="FeatureId"){for(var i=0;i<rule.fids.length;++i){this.writeNode(node,"FeatureId",rule.fids[i]);}}else{this.writeNode(node,this.getFilterType(rule),rule);}
+return node;},"FeatureId":function(fid){return this.createElementNSPlus("ogc:FeatureId",{attributes:{fid:fid}});},"And":function(rule){var node=this.createElementNSPlus("ogc:And");var childRule;for(var i=0;i<rule.rules.length;++i){childRule=rule.rules[i];this.writeNode(node,this.getFilterType(childRule),childRule);}
+return node;},"Or":function(rule){var node=this.createElementNSPlus("ogc:Or");var childRule;for(var i=0;i<rule.rules.length;++i){childRule=rule.rules[i];this.writeNode(node,this.getFilterType(childRule),childRule);}
+return node;},"Not":function(rule){var node=this.createElementNSPlus("ogc:Not");var childRule=rule.rules[0];this.writeNode(node,this.getFilterType(childRule),childRule);return node;},"PropertyIsEqualTo":function(rule){var node=this.createElementNSPlus("ogc:PropertyIsEqualTo");this.writeNode(node,"PropertyName",rule);this.writeNode(node,"Literal",rule);return node;},"PropertyIsNotEqualTo":function(rule){var node=this.createElementNSPlus("ogc:PropertyIsNotEqualTo");this.writeNode(node,"PropertyName",rule);this.writeNode(node,"Literal",rule);return node;},"PropertyIsLessThan":function(rule){var node=this.createElementNSPlus("ogc:PropertyIsLessThan");this.writeNode(node,"PropertyName",rule);this.writeNode(node,"Literal",rule);return node;},"PropertyIsGreaterThan":function(rule){var node=this.createElementNSPlus("ogc:PropertyIsGreaterThan");this.writeNode(node,"PropertyName",rule);this.writeNode(node,"Literal",rule);return node;},"PropertyIsLessThanOrEqualTo":function(rule){var node=this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");this.writeNode(node,"PropertyName",rule);this.writeNode(node,"Literal",rule);return node;},"PropertyIsGreaterThanOrEqualTo":function(rule){var node=this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");this.writeNode(node,"PropertyName",rule);this.writeNode(node,"Literal",rule);return node;},"PropertyIsBetween":function(rule){var node=this.createElementNSPlus("ogc:PropertyIsBetween");this.writeNode(node,"PropertyName",rule);this.writeNode(node,"LowerBoundary",rule);this.writeNode(node,"UpperBoundary",rule);return node;},"PropertyIsLike":function(rule){var node=this.createElementNSPlus("ogc:PropertyIsLike",{attributes:{wildCard:"*",singleChar:".",escape:"!"}});this.writeNode(node,"PropertyName",rule);this.writeNode(node,"Literal",{value:rule.regex2value()});return node;},"PropertyName":function(rule){return this.createElementNSPlus("ogc:PropertyName",{value:rule.property});},"Literal":function(rule){return this.createElementNSPlus("ogc:Literal",{value:rule.value});},"LowerBoundary":function(rule){var node=this.createElementNSPlus("ogc:LowerBoundary");this.writeNode(node,"Literal",rule.lowerBoundary);return node;},"UpperBoundary":function(rule){var node=this.createElementNSPlus("ogc:UpperBoundary");this.writeNode(node,"Literal",rule.upperBoundary);return node;}}},getFilterType:function(rule){var filterType=this.filterMap[rule.type];if(!filterType){throw"SLD writing not supported for rule type: "+rule.type;}
+return filterType;},filterMap:{"&&":"And","||":"Or","!":"Not","==":"PropertyIsEqualTo","!=":"PropertyIsNotEqualTo","<":"PropertyIsLessThan",">":"PropertyIsGreaterThan","<=":"PropertyIsLessThanOrEqualTo",">=":"PropertyIsGreaterThanOrEqualTo","..":"PropertyIsBetween","~":"PropertyIsLike"},getNamespacePrefix:function(uri){var prefix=null;if(uri==null){prefix=this.namespaces[this.defaultPrefix];}else{var gotPrefix=false;for(prefix in this.namespaces){if(this.namespaces[prefix]==uri){gotPrefix=true;break;}}
+if(!gotPrefix){prefix=null;}}
+return prefix;},readChildNodes:function(node,obj){var children=node.childNodes;var child,group,reader,prefix,local;for(var i=0;i<children.length;++i){child=children[i];if(child.nodeType==1){prefix=this.getNamespacePrefix(child.namespaceURI);local=child.nodeName.split(":").pop();group=this.readers[prefix];if(group){reader=group[local];if(reader){reader.apply(this,[child,obj]);}}}}},writeNode:function(parent,name,obj){var prefix,local;var split=name.indexOf(":");if(split>0){prefix=name.substring(0,split);local=name.substring(split+1);}else{prefix=this.getNamespacePrefix(parent.namespaceURI);local=name;}
+var child=this.writers[prefix][local].apply(this,[obj]);parent.appendChild(child);return child;},createElementNSPlus:function(name,options){options=options||{};var loc=name.indexOf(":");var uri=options.uri||this.namespaces[options.prefix];if(!uri){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);}
+if(options.value){node.appendChild(this.createTextNode(options.value));}
+return node;},setAttributes:function(node,obj){var value,loc,alias,uri;for(var name in obj){value=obj[name].toString();uri=this.namespaces[name.substring(0,name.indexOf(":"))]||null;this.setAttributeNS(node,uri,name,value);}},CLASS_NAME:"OpenLayers.Format.SLD.v1"});OpenLayers.Geometry.Curve=OpenLayers.Class(OpenLayers.Geometry.MultiPoint,{componentTypes:["OpenLayers.Geometry.Point"],initialize:function(points){OpenLayers.Geometry.MultiPoint.prototype.initialize.apply(this,arguments);},getLength:function(){var length=0.0;if(this.components&&(this.components.length>1)){for(var i=1;i<this.components.length;i++){length+=this.components[i-1].distanceTo(this.components[i]);}}
+return length;},CLASS_NAME:"OpenLayers.Geometry.Curve"});OpenLayers.Format.SLD.v1_0_0=OpenLayers.Class(OpenLayers.Format.SLD.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd",initialize:function(options){OpenLayers.Format.SLD.v1.prototype.initialize.apply(this,[options]);},CLASS_NAME:"OpenLayers.Format.SLD.v1_0_0"});OpenLayers.Geometry.LineString=OpenLayers.Class(OpenLayers.Geometry.Curve,{initialize:function(points){OpenLayers.Geometry.Curve.prototype.initialize.apply(this,arguments);},removeComponent:function(point){if(this.components&&(this.components.length>2)){OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);}},intersects:function(geometry){var intersect=false;var type=geometry.CLASS_NAME;if(type=="OpenLayers.Geometry.LineString"||type=="OpenLayers.Geometry.LinearRing"||type=="OpenLayers.Geometry.Point"){var segs1=this.getSortedSegments();var segs2;if(type=="OpenLayers.Geometry.Point"){segs2=[{x1:geometry.x,y1:geometry.y,x2:geometry.x,y2:geometry.y}];}else{segs2=geometry.getSortedSegments();}
 var seg1,seg1x1,seg1x2,seg1y1,seg1y2,seg2,seg2y1,seg2y2;outer:for(var i=0;i<segs1.length;++i){seg1=segs1[i];seg1x1=seg1.x1;seg1x2=seg1.x2;seg1y1=seg1.y1;seg1y2=seg1.y2;inner:for(var j=0;j<segs2.length;++j){seg2=segs2[j];if(seg2.x1>seg1x2){break;}
 if(seg2.x2<seg1x1){continue;}
 seg2y1=seg2.y1;seg2y2=seg2.y2;if(Math.min(seg2y1,seg2y2)>Math.max(seg1y1,seg1y2)){continue;}
 if(Math.max(seg2y1,seg2y2)<Math.min(seg1y1,seg1y2)){continue;}
 if(OpenLayers.Geometry.segmentsIntersect(seg1,seg2)){intersect=true;break outer;}}}}else{intersect=geometry.intersects(this);}
-return intersect;},getSortedSegments:function(){var numSeg=this.components.length-1;var segments=new Array(numSeg);for(var i=0;i<numSeg;++i){point1=this.components[i];point2=this.components[i+1];if(point1.x<point2.x){segments[i]={x1:point1.x,y1:point1.y,x2:point2.x,y2:point2.y}}else{segments[i]={x1:point2.x,y1:point2.y,x2:point1.x,y2:point1.y}}}
+return intersect;},getSortedSegments:function(){var numSeg=this.components.length-1;var segments=new Array(numSeg);for(var i=0;i<numSeg;++i){point1=this.components[i];point2=this.components[i+1];if(point1.x<point2.x){segments[i]={x1:point1.x,y1:point1.y,x2:point2.x,y2:point2.y};}else{segments[i]={x1:point2.x,y1:point2.y,x2:point1.x,y2:point1.y};}}
 function byX1(seg1,seg2){return seg1.x1-seg2.x1;}
 return segments.sort(byX1);},CLASS_NAME:"OpenLayers.Geometry.LineString"});OpenLayers.Format.GML=OpenLayers.Class(OpenLayers.Format.XML,{featureNS:"http://mapserver.gis.umn.edu/mapserver",featurePrefix:"feature",featureName:"featureMember",layerName:"features",geometryName:"geometry",collectionName:"FeatureCollection",gmlns:"http://www.opengis.net/gml",extractAttributes:true,xy:true,initialize:function(options){this.regExes={trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)};OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
 var featureNodes=this.getElementsByTagNameNS(data.documentElement,this.gmlns,this.featureName);var features=[];for(var i=0;i<featureNodes.length;i++){var feature=this.parseFeature(featureNodes[i]);if(feature){features.push(feature);}}
@@ -1261,8 +1313,7 @@
 return line;},polygon:function(node){var nodeList=this.getElementsByTagNameNS(node,this.internalns,"LinearRing");var numRings=nodeList.length;var components=new Array(numRings);if(numRings>0){var ring;for(var i=0;i<nodeList.length;++i){ring=this.parseGeometry.linestring.apply(this,[nodeList[i],true]);if(ring){components[i]=ring;}else{throw"Bad LinearRing geometry: "+i;}}}
 return new OpenLayers.Geometry.Polygon(components);},multigeometry:function(node){var child,parser;var parts=[];var children=node.childNodes;for(var i=0;i<children.length;++i){child=children[i];if(child.nodeType==1){var type=(child.prefix)?child.nodeName.split(":")[1]:child.nodeName;var parser=this.parseGeometry[type.toLowerCase()];if(parser){parts.push(parser.apply(this,[child]));}}}
 return new OpenLayers.Geometry.Collection(parts);}},parseAttributes:function(node){var attributes={};var child,grandchildren,grandchild;var children=node.childNodes;for(var i=0;i<children.length;++i){child=children[i];if(child.nodeType==1){grandchildren=child.childNodes;if(grandchildren.length==1||grandchildren.length==3){var grandchild;switch(grandchildren.length){case 1:grandchild=grandchildren[0];break;case 3:default:grandchild=grandchildren[1];break;}
-if(grandchild.nodeType==3||grandchild.nodeType==4){var name=(child.prefix)?child.nodeName.split(":")[1]:child.nodeName;var value=OpenLayers.Util.getXmlNodeValue(grandchild)
-if(value){value=value.replace(this.regExes.trimSpace,"");attributes[name]=value;}}}}}
+if(grandchild.nodeType==3||grandchild.nodeType==4){var name=(child.prefix)?child.nodeName.split(":")[1]:child.nodeName;var value=OpenLayers.Util.getXmlNodeValue(grandchild);if(value){value=value.replace(this.regExes.trimSpace,"");attributes[name]=value;}}}}}
 return attributes;},parseProperty:function(xmlNode,namespace,tagName){var value;var nodeList=this.getElementsByTagNameNS(xmlNode,namespace,tagName);try{value=OpenLayers.Util.getXmlNodeValue(nodeList[0]);}catch(e){value=null;}
 return value;},write:function(features){if(!(features instanceof Array)){features=[features];}
 var kml=this.createElementNS(this.kmlns,"kml");var folder=this.createFolderXML();for(var i=0;i<features.length;++i){folder.appendChild(this.createPlacemarkXML(features[i]));}
@@ -1293,8 +1344,7 @@
 if(this.checkTags){for(var key in way.tags){if(this.areaTags[key]){poly_tags=true;break;}}}
 return poly_shaped&&(this.checkTags?poly_tags:true);},write:function(features){if(!(features instanceof Array)){features=[features];}
 this.osm_id=1;this.created_nodes={};var root_node=this.createElementNS(null,"osm");root_node.setAttribute("version","0.5");root_node.setAttribute("generator","OpenLayers "+OpenLayers.VERSION_NUMBER);for(var i=features.length-1;i>=0;i--){var nodes=this.createFeatureNodes(features[i]);for(var j=0;j<nodes.length;j++){root_node.appendChild(nodes[j]);}}
-return OpenLayers.Format.XML.prototype.write.apply(this,[root_node]);},createFeatureNodes:function(feature){var nodes=[];var className=feature.geometry.CLASS_NAME;var type=className.substring(className.lastIndexOf(".")+1)
-type=type.toLowerCase();var builder=this.createXML[type];if(builder){nodes=builder.apply(this,[feature]);}
+return OpenLayers.Format.XML.prototype.write.apply(this,[root_node]);},createFeatureNodes:function(feature){var nodes=[];var className=feature.geometry.CLASS_NAME;var type=className.substring(className.lastIndexOf(".")+1);type=type.toLowerCase();var builder=this.createXML[type];if(builder){nodes=builder.apply(this,[feature]);}
 return nodes;},createXML:{'point':function(point){var id=null;var geometry=point.geometry?point.geometry:point;var already_exists=false;if(point.osm_id){id=point.osm_id;if(this.created_nodes[id]){already_exists=true;}}else{id=-this.osm_id;this.osm_id++;}
 if(already_exists){node=this.created_nodes[id];}else{var node=this.createElementNS(null,"node");}
 this.created_nodes[id]=node;node.setAttribute("id",id);node.setAttribute("lon",geometry.x);node.setAttribute("lat",geometry.y);if(point.attributes){this.serializeTags(point,node);}

Modified: sandbox/olcore/lib/OpenLayers/OpenLayersUncompressed.js
===================================================================
--- sandbox/olcore/lib/OpenLayers/OpenLayersUncompressed.js	2008-03-31 21:04:04 UTC (rev 1356)
+++ sandbox/olcore/lib/OpenLayers/OpenLayersUncompressed.js	2008-04-01 19:16:04 UTC (rev 1357)
@@ -182,6 +182,8 @@
             "OpenLayers/Layer/TileCache.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",
@@ -255,6 +257,8 @@
             "OpenLayers/Format/WKT.js",
             "OpenLayers/Format/OSM.js",
             "OpenLayers/Format/SLD.js",
+            "OpenLayers/Format/SLD/v1.js",
+            "OpenLayers/Format/SLD/v1_0_0.js",
             "OpenLayers/Format/Text.js",
             "OpenLayers/Format/JSON.js",
             "OpenLayers/Format/GeoJSON.js",
@@ -298,7 +302,7 @@
 /**
  * Constant: VERSION_NUMBER
  */
-OpenLayers.VERSION_NUMBER="$Revision: 6368 $";
+OpenLayers.VERSION_NUMBER="$Revision: 6718 $";
 /* ======================================================================
     OpenLayers/BaseTypes.js
    ====================================================================== */
@@ -1798,7 +1802,7 @@
 };
 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;		
+OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
 
 /** 
  * Constant: DOTS_PER_INCH
@@ -2202,6 +2206,137 @@
     
     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:
+ * 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.
+ * 
+ * Returns:
+ * {OpenLayers.Size}
+ */
+OpenLayers.Util.getRenderedDimensions = function(contentHTML, size) {
+    
+    var w = h = null;
+    
+    // create temp container div with restricted size
+    var container = document.createElement("div");
+    container.style.overflow= "";
+    container.style.position = "absolute";
+    container.style.left = "-9999px";
+        
+    //fix a dimension, if specified.
+    if (size) {
+        if (size.w) {
+            w = container.style.width = size.w;
+        } else if (size.h) {
+            h = container.style.height = size.h;
+        }
+    }
+    
+    // create temp content div and assign content
+    var content = document.createElement("div");
+    content.innerHTML = contentHTML;
+    
+    // add content to restricted container 
+    container.appendChild(content);
+    
+    // append container to body for rendering
+    document.body.appendChild(container);
+    
+    // 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);
+    document.body.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;
+};
 /* ======================================================================
     Rico/Corner.js
    ====================================================================== */
@@ -2971,7 +3106,7 @@
      */
     getStatus: function() {
         try {
-        	return this.transport.status || 0;
+            return this.transport.status || 0;
         } catch (e) {
             return 0;
         }
@@ -4699,6 +4834,15 @@
     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. 
@@ -4860,6 +5004,11 @@
         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 = function() { return(false); }; 
+            }    
             if (this.title != "") {
                 this.div.title = this.title;
             }
@@ -5218,7 +5367,7 @@
                 'Failed to find OpenLayers.Lang.' + parts.join("-") +
                 ' dictionary, falling back to default language'
             );
-            lang = OpenLayers.Lang.defaultCode
+            lang = OpenLayers.Lang.defaultCode;
         }
         
         OpenLayers.Lang.code = lang;
@@ -5362,7 +5511,8 @@
     
     /** 
      * Property: groupDiv 
-     * {DOMElement} the parent of <OpenLayers.Popup.contentDiv> 
+     * {DOMElement} First and only child of 'div'. The group Div contains the
+     *     'contentDiv' and the 'closeDiv'.
      */
     groupDiv: null,
 
@@ -5373,12 +5523,64 @@
     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.
+     */
+    minSize: null,
+
+    /**
+     * APIProperty: maxSize
+     * {<OpenLayers.Size>} Maximum size allowed for the popup's contents.
+     */
+    maxSize: null,
+
+    /** 
      * Property: padding 
-     * {int} the internal padding of the content div.
+     * {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: 5,
+    padding: 0,
 
+    /** 
+     * 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,
+    
     /** 
      * Property: map 
      * {<OpenLayers.Map>} this gets set in Map.js when the popup is added to the map
@@ -5423,38 +5625,22 @@
                                              null, null, null, "hidden");
         this.div.className = 'olPopup';
         
-        this.groupDiv = OpenLayers.Util.createDiv(null, null, null, 
+        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.size.clone(), 
-                                                    null, "relative", null,
-                                                    "hidden");
+                                                    null, "relative");
         this.contentDiv.className = 'olPopupContent';                                            
         this.groupDiv.appendChild(this.contentDiv);
         this.div.appendChild(this.groupDiv);
 
         if (closeBox) {
-           // close icon
-            var closeSize = new OpenLayers.Size(17,17);
-            var img = OpenLayers.Util.getImagesLocation() + "close.gif";
-            this.closeDiv = OpenLayers.Util.createAlphaImageDiv(
-                this.id + "_close", null, closeSize, img
-            );
-            this.closeDiv.style.right = this.padding + "px";
-            this.closeDiv.style.top = this.padding + "px";
-            this.groupDiv.appendChild(this.closeDiv);
+            this.addCloseBox(closeBoxCallback);
+        } 
 
-            var closePopup = closeBoxCallback || function(e) {
-                this.hide();
-                OpenLayers.Event.stop(e);
-            };
-            OpenLayers.Event.observe(this.closeDiv, "click", 
-                    OpenLayers.Function.bindAsEventListener(closePopup, this));
-
-        }
-
         this.registerEvents();
     },
 
@@ -5463,13 +5649,39 @@
      * 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;
+        
+        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.events.destroy();
-        this.events = null;
+        this.map = null;
         this.div = null;
+        
+        this.autoSize = null;
+        this.minSize = null;
+        this.maxSize = null;
+        this.padding = null;
+        this.panMapIfOutOfView = null;
     },
 
     /** 
@@ -5489,12 +5701,39 @@
             }
         }
         
-        this.setSize();
+        //listen to movestart, moveend to disable overflow (FF bug)
+        if (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.setSize(this.size);
+        }
         this.setBackgroundColor();
         this.setOpacity();
         this.setBorder();
         this.setContentHTML();
-        this.moveTo(px);
+        
+        if (this.panMapIfOutOfView) {
+            this.panIntoView();
+        }    
 
         return this.div;
     },
@@ -5541,7 +5780,11 @@
      * Toggles visibility of the popup.
      */
     toggle: function() {
-        OpenLayers.Element.toggle(this.div);
+        if (this.visible()) {
+            this.hide();
+        } else {
+            this.show();
+        }
     },
 
     /**
@@ -5550,6 +5793,10 @@
      */
     show: function() {
         OpenLayers.Element.show(this.div);
+
+        if (this.panMapIfOutOfView) {
+            this.panIntoView();
+        }    
     },
 
     /**
@@ -5565,30 +5812,61 @@
      * Used to adjust the size of the popup. 
      *
      * Parameters:
-     * size - {<OpenLayers.Size>} the new size of the popup in pixels.
+     * size - {<OpenLayers.Size>} the new size of the popup's contents div
+     *     (in pixels).
      */
     setSize:function(size) { 
-        if (size != undefined) {
-            this.size = size; 
+        this.size = size; 
+
+        var contentSize = this.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;
+
+        // 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") {
+            contentSize.w += contentDivPadding.left + contentDivPadding.right;
+            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 = this.size.w + "px";
-            this.contentDiv.style.height = this.size.h + "px";
+            this.contentDiv.style.width = contentSize.w + "px";
+            this.contentDiv.style.height = contentSize.h + "px";
         }
     },  
 
     /**
-    * Method: setBackgroundColor
-    * Sets the background color of the popup.
-    *
-    * Parameters:
-    * color - {String} the background color.  eg "#FFBBBB"
-    */
+     * 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; 
@@ -5649,13 +5927,256 @@
             this.contentHTML = contentHTML;
         }
         
+        if (this.autoSize) {
+
+            // determine actual render dimensions of the contents
+            var realSize = 
+                 OpenLayers.Util.getRenderedDimensions(this.contentHTML);
+
+            // 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(
+                        this.contentHTML, fixedSize
+                    );
+                    
+                    //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);     
+        }        
+
         if (this.contentDiv != null) {
             this.contentDiv.innerHTML = this.contentHTML;
         }    
     },
     
 
+    /**
+     * 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) {
+
+            // Note that there *was* a reference to a
+            // 'OpenLayers.Popup.SCROLL_BAR_WIDTH' constant here, with special
+            // tolerance for it and everything... but it was never defined in
+            // the first place, so I don't know what to think.
+          
+            var maxY = this.map.size.h - 
+                this.map.paddingForPopups.top - 
+                this.map.paddingForPopups.bottom - 
+                hPadding;
     
+            var maxX = this.map.size.w - 
+                this.map.paddingForPopups.left - 
+                this.map.paddingForPopups.right - 
+                wPadding;
+    
+            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. 
+     *
+     *     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>}
+     */
+    getContentDivPadding: function() {
+
+        //use cached value if we have it
+        var contentDivPadding = this._contentDivPadding;
+        if (!contentDivPadding) {
+            //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;
+    
+            //remove the div from the page and make it visible again
+            document.body.removeChild(this.div);
+            this.div.style.display = "";
+        }
+        return contentDivPadding;
+    },
+
+    /**
+     * 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.
@@ -6314,7 +6835,7 @@
      */
     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;
+        return -c/2 * ((--t)*(t-2) - 1) + b;
     },
 
     CLASS_NAME: "OpenLayers.Easing.Quad"
@@ -7965,7 +8486,6 @@
         if (!this.element) {
             this.div.left = "";
             this.div.top = "";
-            this.div.className = this.displayClass;
             this.element = this.div;
         }
         
@@ -9046,7 +9566,6 @@
         OpenLayers.Control.prototype.draw.apply(this, arguments);
           
         if (!this.element) {
-            this.div.className = this.displayClass;
             this.element = document.createElement("a");
             this.element.innerHTML = OpenLayers.i18n("permalink");
             this.element.href="";
@@ -9160,7 +9679,6 @@
         OpenLayers.Control.prototype.draw.apply(this, arguments);
         if (!this.element) {
             this.element = document.createElement("div");
-            this.div.className = this.displayClass;
             this.div.appendChild(this.element);
         }
         this.map.events.register( 'moveend', this, this.updateScale);
@@ -9278,7 +9796,6 @@
     draw: function() {
         OpenLayers.Control.prototype.draw.apply(this, arguments);
         if (!this.eTop) {
-            this.div.className = this.displayClass;
             this.div.style.display = "block";
             this.div.style.position = "absolute";
             
@@ -10441,66 +10958,59 @@
                                            offset: new OpenLayers.Pixel(0,0)};
     },
 
-    /** 
-     * Method: draw
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     * 
-     * Returns: 
-     * {DOMElement} Reference to a div that contains the drawn popup.
+    /**
+     * APIMethod: destroy
      */
-    draw: function(px) {
-        if (px == null) {
-            if ((this.lonlat != null) && (this.map != null)) {
-                px = this.map.getLayerPxFromLonLat(this.lonlat);
-            }
-        }
+    destroy: function() {
+        this.anchor = null;
+        this.relativePosition = null;
         
-        //calculate relative position
-        this.relativePosition = this.calculateRelativePosition(px);
-        
-        return OpenLayers.Popup.prototype.draw.apply(this, arguments);
+        OpenLayers.Popup.prototype.destroy.apply(this, arguments);        
     },
-    
-    /** 
-     * Method: calculateRelativePosition
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     * 
-     * Returns:
-     * {String} The relative position ("br" "tr" "tl "bl") at which the popup
-     *     should be placed.
+
+    /**
+     * 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)
      */
-    calculateRelativePosition:function(px) {
-        var lonlat = this.map.getLonLatFromLayerPx(px);        
-        
-        var extent = this.map.getExtent();
-        var quadrant = extent.determineQuadrant(lonlat);
-        
-        return OpenLayers.Bounds.oppositeQuadrant(quadrant);
-    }, 
+    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.
+     *     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();
+        }
     },
-    
+
     /**
-     * Method: setSize
+     * APIMethod: setSize
      * 
      * Parameters:
      * size - {<OpenLayers.Size>}
@@ -10515,6 +11025,39 @@
     },  
     
     /** 
+     * 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);
+    }, 
+
+    /**
+     * 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:
@@ -10870,9 +11413,9 @@
             node = this.drawGeometryNode(node, geometry);
             
             // append the node to root (but only if it's new)
-	        if (node.parentNode != this.root) { 
-	            this.root.appendChild(node); 
-	        }
+            if (node.parentNode != this.root) { 
+                this.root.appendChild(node); 
+            }
             this.postDraw(node);
         } else {
             node = OpenLayers.Util.getElement(geometry.id);
@@ -13490,7 +14033,7 @@
     layerContainerDiv: null,
 
     /**
-     * Property: layers
+     * APIProperty: layers
      * {Array(<OpenLayers.Layer>)} Ordered list of layers in the map
      */
     layers: null,
@@ -13691,6 +14234,13 @@
     panMethod: OpenLayers.Easing.Expo.easeOut,
     
     /**
+     * Property: paddingForPopups
+     * {<OpenLayers.Bounds>} Outside margin of the popup. Used to prevent 
+     *     the popup from getting too close to the map border.
+     */
+    paddingForPopups : null,
+    
+    /**
      * Constructor: OpenLayers.Map
      * Constructor for a new OpenLayers.Map instance.
      *
@@ -13721,6 +14271,8 @@
                                             OpenLayers.Map.TILE_HEIGHT);
         
         this.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
+        
+        this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);
 
         this.theme = OpenLayers._getScriptLocation() + 
                              'theme/default/style.css'; 
@@ -13862,6 +14414,8 @@
         } else {
             this.events.unregister("resize", this, this.updateSize);
         }    
+        
+        this.paddingForPopups = null;    
 
         if (this.controls != null) {
             for (var i = this.controls.length - 1; i>=0; --i) {
@@ -15724,6 +16278,11 @@
      */
     initialize:function(id, lonlat, size, 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);
     },
 
@@ -15750,17 +16309,12 @@
     },
 
     /**
-     * Method: moveTo
-     * The popup may have been moved to a new relative location, in which case
+     * Method: updateRelativePosition
+     * The popup has been moved to a new relative location, in which case
      *     we will want to re-do the rico corners.
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
      */
-    moveTo: function(px) {
-        OpenLayers.Popup.Anchored.prototype.moveTo.apply(this, arguments);
-        this.setRicoCorners(!this.rounded);
-        this.rounded = true;
+    updateRelativePosition: function() {
+        this.setRicoCorners();
     },
 
     /**
@@ -15771,22 +16325,8 @@
      */
     setSize:function(size) { 
         OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments);
-        
-        if (this.contentDiv != null) {
 
-            var contentSize = this.size.clone();
-            contentSize.h -= (2 * OpenLayers.Popup.AnchoredBubble.CORNER_SIZE);
-            contentSize.h -= (2 * this.padding);
-    
-            this.contentDiv.style.height = contentSize.h + "px";
-            this.contentDiv.style.width  = contentSize.w + "px";
-            
-            if (this.map) {
-                //size has changed - must redo corners        
-                this.setRicoCorners(!this.rounded);
-                this.rounded = true;
-            }    
-        }
+        this.setRicoCorners();
     },  
 
     /**
@@ -15803,7 +16343,7 @@
         if (this.div != null) {
             if (this.contentDiv != null) {
                 this.div.style.background = "transparent";
-                OpenLayers.Rico.Corner.changeColor(this.contentDiv, 
+                OpenLayers.Rico.Corner.changeColor(this.groupDiv, 
                                                    this.backgroundColor);
             }
         }
@@ -15840,11 +16380,8 @@
     /** 
      * Method: setRicoCorners
      * Update RICO corners according to the popup's current relative postion.
-     *  
-     * Parameters:
-     * firstTime - {Boolean} This the first time the corners are being rounded.
      */
-    setRicoCorners:function(firstTime) {
+    setRicoCorners:function() {
     
         var corners = this.getCornersToRound(this.relativePosition);
         var options = {corners: corners,
@@ -15852,8 +16389,9 @@
                        bgColor: "transparent",
                          blend: false};
 
-        if (firstTime) {
+        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
@@ -15889,6 +16427,341 @@
 OpenLayers.Popup.AnchoredBubble.CORNER_SIZE = 5;
 
 /* ======================================================================
+    OpenLayers/Popup/Framed.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Popup/Anchored.js
+ */
+
+/**
+ * Class: OpenLayers.Popup.Framed
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Popup.Anchored>
+ */
+OpenLayers.Popup.Framed =
+  OpenLayers.Class(OpenLayers.Popup.Anchored, {
+
+    /**
+     * Property: imageSrc
+     * {String} location of the image to be used as the popup frame
+     */
+    imageSrc: null,
+
+    /**
+     * Property: imageSize
+     * {<OpenLayers.Size>} Size (measured in pixels) of the image located
+     *     by the 'imageSrc' property.
+     */
+    imageSize: null,
+
+    /**
+     * APIProperty: isAlphaImage
+     * {Boolean} The image has some alpha and thus needs to use the alpha 
+     *     image hack. Note that setting this to true will have no noticeable
+     *     effect in FF or IE7 browsers, but will all but crush the ie6 
+     *     browser. 
+     *     Default is false.
+     */
+    isAlphaImage: false,
+
+    /**
+     * Property: positionBlocks
+     * {Object} Hash of different position blocks (Object/Hashs). Each block 
+     *     will be keyed by a two-character 'relativePosition' 
+     *     code string (ie "tl", "tr", "bl", "br"). Block properties are 
+     *     'offset', 'padding' (self-explanatory), and finally the 'blocks'
+     *     parameter, which is an array of the block objects. 
+     * 
+     *     Each block object must have 'size', 'anchor', and 'position' 
+     *     properties.
+     * 
+     *     Note that positionBlocks should never be modified at runtime.
+     */
+    positionBlocks: null,
+
+    /**
+     * Property: blocks
+     * {Array[Object]} Array of objects, each of which is one "block" of the 
+     *     popup. Each block has a 'div' and an 'image' property, both of 
+     *     which are DOMElements, and the latter of which is appended to the 
+     *     former. These are reused as the popup goes changing positions for
+     *     great economy and elegance.
+     */
+    blocks: null,
+
+    /** 
+     * APIProperty: fixedRelativePosition
+     * {Boolean} We want the framed popup to work dynamically placed relative
+     *     to its anchor but also in just one fixed position. A well designed
+     *     framed popup will have the pixels and logic to display itself in 
+     *     any of the four relative positions, but (understandably), this will
+     *     not be the case for all of them. By setting this property to 'true', 
+     *     framed popup will not recalculate for the best placement each time
+     *     it's open, but will always open the same way. 
+     *     Note that if this is set to true, it is generally advisable to also
+     *     set the 'panIntoView' property to true so that the popup can be 
+     *     scrolled into view (since it will often be offscreen on open)
+     *     Default is false.
+     */
+    fixedRelativePosition: false,
+
+    /** 
+     * Constructor: OpenLayers.Popup.Framed
+     * 
+     * Parameters:
+     * id - {String}
+     * lonlat - {<OpenLayers.LonLat>}
+     * size - {<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, size, contentHTML, anchor, closeBox, 
+                        closeBoxCallback) {
+
+        OpenLayers.Popup.Anchored.prototype.initialize.apply(this, arguments);
+
+        if (this.fixedRelativePosition) {
+            //based on our decided relativePostion, set the current padding
+            // this keeps us from getting into trouble 
+            this.updateRelativePosition();
+            
+            //make calculateRelativePosition always returnt the specified
+            // fiexed position.
+            this.calculateRelativePosition = function(px) {
+                return this.relativePosition;
+            };
+        }
+
+        this.contentDiv.style.position = "absolute";
+        this.contentDiv.style.zIndex = 1;
+
+        if (closeBox) {
+            this.closeDiv.style.zIndex = 1;
+        }
+
+        this.groupDiv.style.position = "absolute";
+        this.groupDiv.style.top = "0px";
+        this.groupDiv.style.left = "0px";
+        this.groupDiv.style.height = "100%";
+        this.groupDiv.style.width = "100%";
+    },
+
+    /** 
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        this.imageSrc = null;
+        this.imageSize = null;
+        this.isAlphaImage = null;
+
+        this.fixedRelativePosition = false;
+        this.positionBlocks = null;
+
+        //remove our blocks
+        for(var i = 0; i < this.blocks.length; i++) {
+            var block = this.blocks[i];
+
+            if (block.image) {
+                block.div.removeChild(block.image);
+            }
+            block.image = null;
+
+            if (block.div) {
+                this.groupDiv.removeChild(block.div);
+            }
+            block.div = null;
+        }
+        this.blocks = null;
+
+        OpenLayers.Popup.Anchored.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
+     * APIMethod: setBackgroundColor
+     */
+    setBackgroundColor:function(color) {
+        //does nothing since the framed popup's entire scheme is based on a 
+        // an image -- changing the background color makes no sense. 
+    },
+
+    /**
+     * APIMethod: setBorder
+     */
+    setBorder:function() {
+        //does nothing since the framed popup's entire scheme is based on a 
+        // an image -- changing the popup's border makes no sense. 
+    },
+
+    /**
+     * Method: setOpacity
+     * Sets the opacity of the popup.
+     * 
+     * Parameters:
+     * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid).   
+     */
+    setOpacity:function(opacity) {
+        //does nothing since we suppose that we'll never apply an opacity
+        // to a framed popup
+    },
+
+    /**
+     * APIMethod: setSize
+     * Overridden here, because we need to update the blocks whenever the size
+     *     of the popup has changed.
+     * 
+     * Parameters:
+     * size - {<OpenLayers.Size>}
+     */
+    setSize:function(size) { 
+        OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments);
+
+        this.updateBlocks();
+    },
+
+    /**
+     * Method: updateRelativePosition
+     * When the relative position changes, we need to set the new padding 
+     *     BBOX on the popup, reposition the close div, and update the blocks.
+     */
+    updateRelativePosition: function() {
+
+        //update the padding
+        this.padding = this.positionBlocks[this.relativePosition].padding;
+
+        //update the position of our close box to new padding
+        if (this.closeDiv) {
+            // 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 + 
+                                        this.padding.right + "px";
+            this.closeDiv.style.top = contentDivPadding.top + 
+                                      this.padding.top + "px";
+        }
+
+        this.updateBlocks();
+    },
+
+    /** 
+     * Method: calculateNewPx
+     * Besides the standard offset as determined by the Anchored class, our 
+     *     Framed popups have a special 'offset' property for each of their 
+     *     positions, which is used to offset the popup relative to its anchor.
+     * 
+     * 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 = OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply(
+            this, arguments
+        );
+
+        newPx = newPx.offset(this.positionBlocks[this.relativePosition].offset);
+
+        return newPx;
+    },
+
+    /**
+     * Method: createBlocks
+     */
+    createBlocks: function() {
+        this.blocks = [];
+
+        var position = this.positionBlocks[this.relativePosition];
+        for (var i = 0; i < position.blocks.length; i++) {
+
+            var block = {};
+            this.blocks.push(block);
+
+            var divId = this.id + '_FrameDecorationDiv_' + i;
+            block.div = OpenLayers.Util.createDiv(divId, 
+                null, null, null, "absolute", null, "hidden", null
+            );
+
+            var imgId = this.id + '_FrameDecorationImg_' + i;
+            var imageCreator = 
+                (this.isAlphaImage) ? OpenLayers.Util.createAlphaImageDiv
+                                    : OpenLayers.Util.createImage;
+
+            block.image = imageCreator(imgId, 
+                null, this.imageSize, this.imageSrc, 
+                "absolute", null, null, null
+            );
+
+            block.div.appendChild(block.image);
+            this.groupDiv.appendChild(block.div);
+        }
+    },
+
+    /**
+     * Method: updateBlocks
+     * Internal method, called on initialize and when the popup's relative
+     *     position has changed. This function takes care of re-positioning
+     *     the popup's blocks in their appropropriate places.
+     */
+    updateBlocks: function() {
+
+        if (!this.blocks) {
+            this.createBlocks();
+        }
+
+        var position = this.positionBlocks[this.relativePosition];
+        for (var i = 0; i < position.blocks.length; i++) {
+
+            var positionBlock = position.blocks[i];
+            var block = this.blocks[i];
+
+            // adjust sizes
+            var l = positionBlock.anchor.left;
+            var b = positionBlock.anchor.bottom;
+            var r = positionBlock.anchor.right;
+            var t = positionBlock.anchor.top;
+
+            //note that we use the isNaN() test here because if the 
+            // size object is initialized with a "auto" parameter, the 
+            // size constructor calls parseFloat() on the string, 
+            // which will turn it into NaN
+            //
+            var w = (isNaN(positionBlock.size.w)) ? this.size.w - (r + l) 
+                                                  : positionBlock.size.w;
+
+            var h = (isNaN(positionBlock.size.h)) ? this.size.h - (b + t) 
+                                                  : positionBlock.size.h;
+
+            block.div.style.width = w + 'px';
+            block.div.style.height = h + 'px';
+
+            block.div.style.left = (l != null) ? l + 'px' : '';
+            block.div.style.bottom = (b != null) ? b + 'px' : '';
+            block.div.style.right = (r != null) ? r + 'px' : '';            
+            block.div.style.top = (t != null) ? t + 'px' : '';
+
+            block.image.style.left = positionBlock.position.x + 'px';
+            block.image.style.top = positionBlock.position.y + 'px';
+        }
+
+        this.contentDiv.style.left = this.padding.left + "px";
+        this.contentDiv.style.top = this.padding.top + "px";
+    },
+
+    CLASS_NAME: "OpenLayers.Popup.Framed"
+});
+/* ======================================================================
     OpenLayers/Renderer/SVG.js
    ====================================================================== */
 
@@ -16631,7 +17504,7 @@
         // stroke 
         if (options.isStroked) { 
             node.setAttribute("strokecolor", style.strokeColor); 
-            node.setAttribute("strokeweight", style.strokeWidth); 
+            node.setAttribute("strokeweight", style.strokeWidth + "px"); 
         } else { 
             node.setAttribute("stroked", "false"); 
         }
@@ -16675,7 +17548,7 @@
         }
         if (strokeColor == "none" &&
                 node.getAttribute("strokecolor") != strokeColor) {
-            node.setAttribute("strokecolor", strokeColor)
+            node.setAttribute("strokecolor", strokeColor);
         }
     },
 
@@ -16728,6 +17601,12 @@
         if (id) {
             node.setAttribute('id', id);
         }
+        
+        // IE hack to make elements unselectable, to prevent 'blue flash'
+        // while dragging vectors; #1410
+        node.setAttribute('unselectable', 'on', 0);
+        node.onselectstart = function() { return(false); };
+        
         return node;    
     },
     
@@ -17362,9 +18241,12 @@
         this.frame.style.display = '';
         // Force a reflow on gecko based browsers to actually show the element
         // before continuing execution.
-        if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) { 
-            this.frame.scrollLeft = this.frame.scrollLeft; 
-        } 
+        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; 
+            } 
+        }
     },
     
     /** 
@@ -17778,7 +18660,7 @@
         // Optionally add min/max buttons if the control will go in the
         // map viewport.
         if(!this.outsideViewport) {
-            this.div.className = this.displayClass + 'Container';
+            this.div.className += " " + this.displayClass + 'Container';
             var imgLocation = OpenLayers.Util.getImagesLocation();
             // maximize button div
             var img = imgLocation + 'layer-switcher-maximize.png';
@@ -18956,7 +19838,7 @@
      * Method: read_wmc_Format
      */
     read_wmc_Format: function(layerInfo, node) {
-        var format = this.getChildValue(node)
+        var format = this.getChildValue(node);
         layerInfo.formats.push(format);
         if(node.getAttribute("current") == "1") {
             layerInfo.params.format = format;
@@ -22138,6 +23020,234 @@
 });
 
 /* ======================================================================
+    OpenLayers/Popup/FramedCloud.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Popup/Framed.js
+ * @requires OpenLayers/Util.js
+ */
+
+/**
+ * Class: OpenLayers.Popup.FramedCloud
+ * 
+ * Inherits from: 
+ *  - <OpenLayers.Popup.Framed>
+ */
+OpenLayers.Popup.FramedCloud = 
+  OpenLayers.Class(OpenLayers.Popup.Framed, {
+
+    /**
+     * APIProperty: autoSize
+     * {Boolean} Framed Cloud is autosizing by default.
+     */
+    autoSize: true,
+
+    /**
+     * APIProperty: panMapIfOutOfView
+     * {Boolean} Framed Cloud does pan into view by default.
+     */
+    panMapIfOutOfView: true,
+
+    /**
+     * APIProperty: imageSize
+     * {<OpenLayers.Size>}
+     */
+    imageSize: new OpenLayers.Size(676, 736),
+
+    /**
+     * APIProperty: isAlphaImage
+     * {Boolean} The FramedCloud does not use an alpha image (in honor of the 
+     *     good ie6 folk out there)
+     */
+    isAlphaImage: false,
+
+    /** 
+     * APIProperty: fixedRelativePosition
+     * {Boolean} The Framed Cloud popup works in just one fixed position.
+     */
+    fixedRelativePosition: false,
+
+    /**
+     * Property: positionBlocks
+     * {Object} Hash of differen position blocks, keyed by relativePosition
+     *     two-character code string (ie "tl", "tr", "bl", "br")
+     */
+    positionBlocks: {
+        "tl": {
+            'offset': new OpenLayers.Pixel(44, 0),
+            'padding': new OpenLayers.Bounds(8, 40, 8, 9),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 51, 22, 0),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 50, 0, 0),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 21),
+                    anchor: new OpenLayers.Bounds(0, 32, 80, null),
+                    position: new OpenLayers.Pixel(0, -629)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 21),
+                    anchor: new OpenLayers.Bounds(null, 32, 0, null),
+                    position: new OpenLayers.Pixel(-638, -629)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 54),
+                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
+                    position: new OpenLayers.Pixel(0, -668)
+                }
+            ]
+        },
+        "tr": {
+            'offset': new OpenLayers.Pixel(-45, 0),
+            'padding': new OpenLayers.Bounds(8, 40, 8, 9),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 51, 22, 0),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 50, 0, 0),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 21),
+                    anchor: new OpenLayers.Bounds(0, 32, 22, null),
+                    position: new OpenLayers.Pixel(0, -629)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 21),
+                    anchor: new OpenLayers.Bounds(null, 32, 0, null),
+                    position: new OpenLayers.Pixel(-638, -629)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 54),
+                    anchor: new OpenLayers.Bounds(0, 0, null, null),
+                    position: new OpenLayers.Pixel(-215, -668)
+                }
+            ]
+        },
+        "bl": {
+            'offset': new OpenLayers.Pixel(45, 0),
+            'padding': new OpenLayers.Bounds(8, 9, 8, 40),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 21, 22, 32),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 21, 0, 32),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 21),
+                    anchor: new OpenLayers.Bounds(0, 0, 22, null),
+                    position: new OpenLayers.Pixel(0, -629)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 21),
+                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
+                    position: new OpenLayers.Pixel(-638, -629)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 54),
+                    anchor: new OpenLayers.Bounds(null, null, 0, 0),
+                    position: new OpenLayers.Pixel(-101, -674)
+                }
+            ]
+        },
+        "br": {
+            'offset': new OpenLayers.Pixel(-44, 0),
+            'padding': new OpenLayers.Bounds(8, 9, 8, 40),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 21, 22, 32),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 21, 0, 32),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 21),
+                    anchor: new OpenLayers.Bounds(0, 0, 22, null),
+                    position: new OpenLayers.Pixel(0, -629)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 21),
+                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
+                    position: new OpenLayers.Pixel(-638, -629)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 54),
+                    anchor: new OpenLayers.Bounds(0, null, null, 0),
+                    position: new OpenLayers.Pixel(-311, -674)
+                }
+            ]
+        }
+    },
+
+    /**
+     * APIProperty: minSize
+     * {<OpenLayers.Size>}
+     */
+    minSize: new OpenLayers.Size(105, 10),
+
+    /**
+     * APIProperty: maxSize
+     * {<OpenLayers.Size>}
+     */
+    maxSize: new OpenLayers.Size(600, 660),
+
+    /** 
+     * Constructor: OpenLayers.Popup.FramedCloud
+     * 
+     * Parameters:
+     * id - {String}
+     * lonlat - {<OpenLayers.LonLat>}
+     * size - {<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, size, contentHTML, anchor, closeBox, 
+                        closeBoxCallback) {
+
+        this.imageSrc = OpenLayers.Util.getImagesLocation() + 'cloud-popup-relative.png';
+        OpenLayers.Popup.Framed.prototype.initialize.apply(this, arguments);
+        this.contentDiv.className = "olFramedCloudPopupContent";
+    },
+
+    /** 
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        OpenLayers.Popup.Framed.prototype.destroy.apply(this, arguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Popup.FramedCloud"
+});
+/* ======================================================================
     OpenLayers/Control/DragFeature.js
    ====================================================================== */
 
@@ -27306,7 +28416,7 @@
           tilelon: tilelon, tilelat: tilelat,
           tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
           tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
-        }  
+        };
 
     },
 
@@ -27533,7 +28643,7 @@
      * tile - {<OpenLayers.Tile>}
      */
     removeTileMonitoringHooks: function(tile) {
-        tile.unload()
+        tile.unload();
         tile.events.un({
             "loadstart": tile.onLoadStart,
             "loadend": tile.onLoadEnd,
@@ -29039,6 +30149,18 @@
     name: null,
     
     /**
+     * Property: title
+     * {String} Title of this style (set if included in SLD)
+     */
+    title: null,
+    
+    /**
+     * Property: description
+     * {String} Description of this style (set if abstract is included in SLD)
+     */
+    description: null,
+
+    /**
      * APIProperty: layerName
      * {<String>} name of the layer that this style belongs to, usually
      * according to the NamedLayer attribute of an SLD document.
@@ -29351,7 +30473,7 @@
         value = (isNaN(value) || !value) ? value : parseFloat(value);
     }
     return value;
-}
+};
     
 /**
  * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES
@@ -29959,7 +31081,7 @@
         originGeometry.move = function(x, y) {
             OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
             geometry.move(x, y);
-        }
+        };
         this.dragHandle = origin;
         this.layer.addFeatures([this.dragHandle], {silent: true});
     },
@@ -29999,7 +31121,7 @@
                 var l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1));
                 geometry.resize(l1 / l0, originGeometry);
             }
-        }
+        };
         this.radiusHandle = radius;
         this.layer.addFeatures([this.radiusHandle], {silent: true});
     },
@@ -30671,7 +31793,7 @@
           tilelon: tilelon, tilelat: tilelat,
           tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
           tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
-        }  
+        };
     },    
 
     /**
@@ -31065,7 +32187,7 @@
           tilelon: tilelon, tilelat: tilelat,
           tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
           tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
-        }  
+        };
     },
     
     CLASS_NAME: "OpenLayers.Layer.MapGuide"
@@ -31980,12 +33102,30 @@
 OpenLayers.Rule = OpenLayers.Class({
     
     /**
+     * Property: id
+     * {String} A unique id for this session.
+     */
+    id: null,
+    
+    /**
      * APIProperty: name
      * {String} name of this rule
      */
     name: 'default',
     
     /**
+     * Property: title
+     * {String} Title of this rule (set if included in SLD)
+     */
+    title: null,
+    
+    /**
+     * Property: description
+     * {String} Description of this rule (set if abstract is included in SLD)
+     */
+    description: null,
+
+    /**
      * Property: context
      * {Object} An optional object with properties that the rule should be
      * evaluatad against. If no context is specified, feature.attributes will
@@ -32038,6 +33178,7 @@
      * {<OpenLayers.Rule>}
      */
     initialize: function(options) {
+        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
         this.symbolizer = {};
 
         OpenLayers.Util.extend(this, options);
@@ -33805,9 +34946,9 @@
             
             case OpenLayers.Rule.Comparison.BETWEEN:
                 var result =
-                        context[this.property] > this.lowerBoundary;
+                        context[this.property] >= this.lowerBoundary;
                 result = result &&
-                        context[this.property] < this.upperBoundary;
+                        context[this.property] <= this.upperBoundary;
                 return result;
             case OpenLayers.Rule.Comparison.LIKE:
                 var regexp = new RegExp(this.value,
@@ -33862,6 +35003,41 @@
     },
     
     /**
+     * Method: regex2value
+     * Convert the value of this rule from a regular expression string into an
+     *     ogc literal string using a wildCard of *, a singleChar of ., and an
+     *     escape of !.  Leaves the <value> property unmodified.
+     * 
+     * Returns:
+     * {String} A string value.
+     */
+    regex2value: function() {
+        
+        var value = this.value;
+        
+        // replace ! with !!
+        value = value.replace(/!/g, "!!");
+
+        // replace \. with !. (watching out for \\.)
+        value = value.replace(/(\\)?\\\./g, function($0, $1) {
+            return $1 ? $0 : "!.";
+        });
+        
+        // replace \* with #* (watching out for \\*)
+        value = value.replace(/(\\)?\\\*/g, function($0, $1) {
+            return $1 ? $0 : "!*";
+        });
+        
+        // replace \\ with \
+        value = value.replace(/\\\\/g, "\\");
+
+        // convert .* to * (the sequence #.* is not allowed)
+        value = value.replace(/\.\*/g, "*");
+        
+        return value;
+    },
+
+    /**
      * Function: binaryCompare
      * Compares a feature property to a rule value
      * 
@@ -34110,60 +35286,24 @@
 OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML, {
     
     /**
-     * APIProperty: sldns
-     * Namespace used for sld.
+     * APIProperty: defaultVersion
+     * {String} Version number to assume if none found.  Default is "1.0.0".
      */
-    sldns: "http://www.opengis.net/sld",
+    defaultVersion: "1.0.0",
     
     /**
-     * APIProperty: ogcns
-     * Namespace used for ogc.
+     * APIProperty: version
+     * {String} Specify a version string if one is known.
      */
-    ogcns: "http://www.opengis.net/ogc",
+    version: null,
     
     /**
-     * APIProperty: gmlns
-     * Namespace used for gml.
+     * Property: parser
+     * {Object} Instance of the versioned parser.  Cached for multiple read and
+     *     write calls of the same version.
      */
-    gmlns: "http://www.opengis.net/gml",
-    
-    /**
-     * APIProperty: defaultStyle.
-     * {Object}
-     * A simple style, preset with the SLD defaults.
-     */
-    defaultStyle: {
-            fillColor: "#808080",
-            fillOpacity: 1,
-            strokeColor: "#000000",
-            strokeOpacity: 1,
-            strokeWidth: 1,
-            pointRadius: 6
-    },
-    
-    /**
-     * Property: withNamedLayer
-     * {Boolean} Option set during <read>.  Default is false.  If true, the
-     *     return from <read> will be a two item array ([styles, namedLayer]): 
-     *         - styles - {Array(<OpenLayers.Style>)}
-     *         - namedLayer - {Object} hash of userStyles, keyed by
-     *             sld:NamedLayer/Name, each again keyed by 
-     *             sld:UserStyle/Name. Each entry of namedLayer is a
-     *             StyleMap for a layer, with the userStyle names as style
-     *             keys.
-     */
-    withNamedLayer: false,
-     
-    /**
-     * APIProperty: overrideDefaultStyleKey
-     * {Boolean} Store styles with key of "default" instead of user style name.
-     *     If true, userStyles with sld:IsDefault==1 will be stored with
-     *     key "default" instead of the sld:UserStyle/Name in the style map.
-     *     Default is true.
-     */
-    overrideDefaultStyleKey: true,
+    parser: null,
 
-
     /**
      * Constructor: OpenLayers.Format.SLD
      * Create a new parser for SLD.
@@ -34177,517 +35317,68 @@
     },
 
     /**
-     * APIMethod: read
-     * Read data from a string, and return a list of features. 
-     * 
-     * Parameters:
-     * data - {String} or {XMLNode} data to read/parse.
-     * options - {Object} Object that sets optional read configuration values.
-     *     These include <withNamedLayer>, and <overrideDefaultStyleKey>.
+     * APIMethod: write
+     * Write a SLD document given a list of styles.
      *
-     * Returns:
-     * {Array(<OpenLayers.Style>)} List of styles.  If <withNamedLayer> is
-     *     true, return will be a two item array where the first item is
-     *     a list of styles and the second is the namedLayer object.
-     */
-    read: function(data, options) {
-        if (typeof data == "string") { 
-            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
-        }
-        
-        options = options || {};
-        OpenLayers.Util.applyDefaults(options, {
-            withNamedLayer: false,
-            overrideDefaultStyleKey: true
-        });
-        
-        var userStyles = this.getElementsByTagNameNS(
-            data, this.sldns, "UserStyle"
-        );
-        var result = {};
-        if (userStyles.length > 0) {
-            var namedLayer = {};
-            var styles = new Array(userStyles.length);
-            var styleName, userStyle, style;
-            for (var i=0; i<userStyles.length; i++) {
-                userStyle = userStyles[i];
-                styleName = this.parseProperty(
-                    userStyle, this.sldns, "Name"
-                );
-                style = this.parseUserStyle(userStyle, styleName);
-    
-                if (options.overrideDefaultStyleKey && style.isDefault == true) {
-                    styleName = "default";
-                }
-    
-                if (!namedLayer[style.layerName]) {
-                    namedLayer[style.layerName] = {};
-                }
-                namedLayer[style.layerName][styleName] = style;
-                styles[i] = style;
-            }
-            result = options.withNamedLayer ? [styles, namedLayer] : styles;
-        }
-        return result;
-    },
-
-    /**
-     * Method: parseUserStyle
-     * parses a sld userStyle for rules
-     * 
      * Parameters:
-     * xmlNode - {DOMElement} xml node to read the style from
-     * name - {String} name of the style
-     * 
-     * Returns:
-     * {<OpenLayers.Style>}
-     */
-    parseUserStyle: function(xmlNode, name) {
-        var userStyle = new OpenLayers.Style(this.defaultStyle, {name: name});
-        
-        userStyle.isDefault = (
-            this.parseProperty(xmlNode, this.sldns, "IsDefault") == 1
-        );
-        
-        // get the name of the layer if we have a NamedLayer
-        var namedLayerNode = xmlNode.parentNode;
-        var nameNodes = this.getElementsByTagNameNS(
-            namedLayerNode, this.sldns, "Name"
-        );
-        if (namedLayerNode.nodeName.indexOf("NamedLayer") != -1 &&
-                nameNodes &&
-                nameNodes.length > 0 &&
-                nameNodes[0].parentNode == namedLayerNode) {
-            userStyle.layerName = this.getChildValue(nameNodes[0]);
-        }
-         
-        var ruleNodes = this.getElementsByTagNameNS(
-            xmlNode, this.sldns, "Rule"
-        );
-
-        if (ruleNodes.length > 0) {
-            var rules = userStyle.rules;
-            var ruleName;
-            for (var i=0; i<ruleNodes.length; i++) {
-                ruleName = this.parseProperty(ruleNodes[i], this.sldns, "Name");
-                rules.push(this.parseRule(ruleNodes[i], ruleName));
-            }
-        }
-
-        return userStyle;
-    },        
-    
-    /**
-     * Method: parseRule
-     * This function is the core of the SLD parsing code in OpenLayers.
-     *     It creates the rule with its constraints and symbolizers.
+     * sld - {Object} An object representing the SLD.
+     * options - {Object} Optional configuration object.
      *
-     * Parameters:
-     * xmlNode - {<DOMElement>}
-     * 
      * Returns:
-     * {Object} Hash of rule properties
+     * {String} An SLD document string.
      */
-    parseRule: function(xmlNode, name) {
-
-        // FILTERS
-        
-        var filter = this.getElementsByTagNameNS(xmlNode, this.ogcns, "Filter");
-        if (filter && filter.length > 0) {
-            var rule = this.parseFilter(filter[0]);
-        } else {
-            // start with an empty rule that always applies
-            var rule = new OpenLayers.Rule();
-            // and check if the rule is an ElseFilter
-            var elseFilter = this.getElementsByTagNameNS(xmlNode, this.ogcns,
-                "ElseFilter");
-            if (elseFilter && elseFilter.length > 0) {
-                rule.elseFilter = true;
+    write: function(sld, options) {
+        var version = (options && options.version) ||
+                      this.version || this.defaultVersion;
+        if(!this.parser || this.parser.VERSION != version) {
+            var format = OpenLayers.Format.SLD[
+                "v" + version.replace(/\./g, "_")
+            ];
+            if(!format) {
+                throw "Can't find a SLD parser for version " +
+                      version;
             }
+            this.parser = new format(this.options);
         }
-        
-        rule.name = name;
-        
-        // SCALE DENOMINATORS
-        
-        // MinScaleDenominator
-        var minScale = this.getElementsByTagNameNS(
-            xmlNode, this.sldns, "MinScaleDenominator"
-        );
-        if (minScale && minScale.length > 0) {
-            rule.minScaleDenominator = 
-                parseFloat(this.getChildValue(minScale[0]));
-        }
-        
-        // MaxScaleDenominator
-        var maxScale = this.getElementsByTagNameNS(
-            xmlNode, this.sldns, "MaxScaleDenominator"
-        );
-        if (maxScale && maxScale.length > 0) {
-            rule.maxScaleDenominator =
-                parseFloat(this.getChildValue(maxScale[0]));
-        }
-        
-        // STYLES
-        
-        // walk through all symbolizers
-        var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;
-        for (var s=0; s<prefixes.length; s++) {
-            
-            // symbolizer type
-            var symbolizer = this.getElementsByTagNameNS(
-                xmlNode, this.sldns, prefixes[s]+"Symbolizer"
-            );
-            
-            if (symbolizer && symbolizer.length > 0) {
-            
-                var style = {};
-            
-                // externalGraphic
-                var graphic = this.getElementsByTagNameNS(
-                    symbolizer[0], this.sldns, "Graphic"
-                );
-                if (graphic && graphic.length > 0) {
-                    style.externalGraphic = this.parseProperty(
-                        graphic[0], this.sldns, "OnlineResource", "xlink:href"
-                    );
-                    style.pointRadius = this.parseProperty(
-                        graphic[0], this.sldns, "Size"
-                    );
-                    style.graphicOpacity = this.parseProperty(
-                        graphic[0], this.sldns, "Opacity"
-                    );
-                }
-                
-                // fill
-                var fill = this.getElementsByTagNameNS(
-                    symbolizer[0], this.sldns, "Fill"
-                );
-                if (fill && fill.length > 0) {
-                    style.fillColor = this.parseProperty(
-                        fill[0], this.sldns, "CssParameter", "name", "fill"
-                    );
-                    style.fillOpacity = this.parseProperty(
-                        fill[0], this.sldns, "CssParameter",
-                        "name", "fill-opacity"
-                    ) || 1;
-                }
-            
-                // stroke
-                var stroke = this.getElementsByTagNameNS(
-                    symbolizer[0], this.sldns, "Stroke"
-                );
-                if (stroke && stroke.length > 0) {
-                    style.strokeColor = this.parseProperty(
-                        stroke[0], this.sldns, "CssParameter", "name", "stroke"
-                    );
-                    style.strokeOpacity = this.parseProperty(
-                        stroke[0], this.sldns, "CssParameter",
-                        "name", "stroke-opacity"
-                    ) || 1;
-                    style.strokeWidth = this.parseProperty(
-                        stroke[0], this.sldns, "CssParameter",
-                        "name", "stroke-width"
-                    );
-                    style.strokeLinecap = this.parseProperty(
-                        stroke[0], this.sldns, "CssParameter",
-                        "name", "stroke-linecap"
-                    );
-                }
-                
-                // set the [point|line|polygon]Symbolizer property of the rule
-                rule.symbolizer[prefixes[s]] = style;
-            }
-        }
-
-        return rule;
+        var root = this.parser.write(sld);
+        return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
     },
     
     /**
-     * Method: parseFilter
-     * Parses ogc fiters.
+     * APIMethod: read
+     * Read and SLD doc and return an object representing the SLD.
      *
      * Parameters:
-     * xmlNode - {<DOMElement>}
-     * 
-     * Returns:
-     * {<OpenLayers.Rule>} rule representing the filter
-     */
-    parseFilter: function(xmlNode) {
-        // ogc:FeatureId filter
-        var filter = this.getNodeOrChildrenByTagName(xmlNode, "FeatureId");
-        if (filter) {
-            var rule = new OpenLayers.Rule.FeatureId();
-            for (var i=0; i<filter.length; i++) {
-                rule.fids.push(filter[i].getAttribute("fid"));
-            }
-            return rule;
-        }
-        
-        // ogc:And filter
-        filter = this.getNodeOrChildrenByTagName(xmlNode, "And");
-        if (filter) {
-            var rule = new OpenLayers.Rule.Logical(
-                    {type: OpenLayers.Rule.Logical.AND});
-            var filters = filter[0].childNodes; 
-            for (var i=0; i<filters.length; i++) {
-                if (filters[i].nodeType == 1) {
-                    rule.rules.push(this.parseFilter(filters[i]));
-                }
-            }
-            return rule;
-        }
-
-        // ogc:Or filter
-        filter = this.getNodeOrChildrenByTagName(xmlNode, "Or");
-        if (filter) {
-            var rule = new OpenLayers.Rule.Logical(
-                    {type: OpenLayers.Rule.Logical.OR})
-            var filters = filter[0].childNodes; 
-            for (var i=0; i<filters.length; i++) {
-                if (filters[i].nodeType == 1) {
-                    rule.rules.push(this.parseFilter(filters[i]));
-                }
-            }
-            return rule;
-        }
-
-        // ogc:Not filter
-        filter = this.getNodeOrChildrenByTagName(xmlNode, "Not");
-        if (filter) {
-            var rule = new OpenLayers.Rule.Logical(
-                    {type: OpenLayers.Rule.Logical.NOT});
-            var filters = filter[0].childNodes; 
-            for (var i=0; i<filters.length; i++) {
-                if (filters[i].nodeType == 1) {
-                    rule.rules.push(this.parseFilter(filters[i]));
-                }
-            }
-            return rule;
-        }
-        
-        // Comparison filters
-        for (var type in this.TYPES) {
-            var filter = this.getNodeOrChildrenByTagName(xmlNode, type);
-            if (filter) {
-                filter = filter[0];
-                var rule = new OpenLayers.Rule.Comparison({
-                        type: OpenLayers.Rule.Comparison[this.TYPES[type]],
-                        property: this.parseProperty(
-                                filter, this.ogcns, "PropertyName")});
-                // ogc:PropertyIsBetween
-                if (this.TYPES[type] == "BETWEEN") {
-                    rule.lowerBoundary = this.parseProperty(
-                            filter, this.ogcns, "LowerBoundary");
-                    rule.upperBoudary = this.parseProperty(
-                            filter, this.ogcns, "UpperBoundary");
-                } else {
-                    rule.value = this.parseProperty(
-                            filter, this.ogcns, "Literal");
-                    // ogc:PropertyIsLike
-                    if (this.TYPES[type] == "LIKE") {
-                        var wildCard = filter.getAttribute("wildCard");
-                        var singleChar = filter.getAttribute("singleChar");
-                        var escape = filter.getAttribute("escape");
-                        rule.value2regex(wildCard, singleChar, escape);
-                    }
-                }
-                return rule;
-            }
-        }
-        
-        // if we get here, the filter was empty
-        return new OpenLayers.Rule();
-    },
-    
-    /**
-     * Method: getNodeOrChildrenByTagName
-     * Convenience method to get a node or its child nodes, but only
-     *     those matching a tag name.
-     * 
-     * Returns:
-     * {Array(<DOMElement>)} or null if no matching content is found
-     */
-    getNodeOrChildrenByTagName: function(xmlNode, tagName) {
-        var nodeName = (xmlNode.prefix) ?
-               xmlNode.nodeName.split(":")[1] :
-               xmlNode.nodeName;
-
-        if (nodeName == tagName) {
-            return [xmlNode];
-        } else {
-            var nodelist = this.getElementsByTagNameNS(
-                    xmlNode, this.ogcns, tagName);
-        }
-
-        // make a new list which only contains matching child nodes
-        if (nodelist.length > 0) {
-            var node;
-            var list = [];
-            for (var i=0; i<nodelist.length; i++) {
-                node = nodelist[i];
-                if (node.parentNode == xmlNode) {
-                    list.push(node);
-                }
-            }
-            return list.length > 0 ? list : null;
-        }
-        
-        return null;
-    },
-    
-    /**
-     * Method: parseProperty
-     * Convenience method to parse the different kinds of properties
-     *     found in the sld and ogc namespace.
+     * data - {String | DOMElement} Data to read.
      *
-     * Parses an ogc node that can either contain a value directly,
-     *     or inside a <Literal> property. The parsing can also be limited
-     *     to nodes with certain attribute names and/or values.
-     *
-     * Parameters:
-     * xmlNode        - {<DOMElement>}
-     * namespace      - {String} namespace of the node to find
-     * propertyName   - {String} name of the property to parse
-     * attributeName  - {String} optional name of the property to match
-     * attributeValue - {String} optional value of the specified attribute
-     * 
      * Returns:
-     * {String} The value for the requested property.
-     */    
-    parseProperty: function(xmlNode, namespace, propertyName, attributeName,
-                                                              attributeValue) {
-        var result = null;
-        var propertyNodeList = this.getElementsByTagNameNS(
-                xmlNode, namespace, propertyName);
-                
-        if (propertyNodeList && propertyNodeList.length > 0) {
-            var propertyNode = attributeName ?
-                    this.getNodeWithAttribute(propertyNodeList, 
-                            attributeName) :
-                    propertyNodeList[0];
-
-            // strip namespace from attribute name for Opera browsers
-            if (window.opera && attributeName) {
-                var nsDelimiterPos = attributeName.indexOf(":");
-                if (nsDelimiterPos != -1) {
-                    attributeName = attributeName.substring(++nsDelimiterPos);
-                }
-            }
-            
-            // get the property value from the node matching attributeName
-            // and attributeValue, eg.:
-            // <CssParameter name="stroke">
-            //     <ogc:Literal>red</ogc:Literal>
-            // </CssParameter>
-            // or:
-            // <CssParameter name="stroke">red</CssParameter>
-            if (attributeName && attributeValue) {
-                propertyNode = this.getNodeWithAttribute(propertyNodeList,
-                        attributeName, attributeValue);
-                result = this.parseParameter(propertyNode);
-            }
-
-            // get the attribute value and use it as result, eg.:
-            // <sld:OnlineResource xlink:href="../img/marker.png"/>
-            if (attributeName && !attributeValue) {
-                var propertyNode = this.getNodeWithAttribute(propertyNodeList,
-                        attributeName);
-                result = propertyNode.getAttribute(attributeName);                
-            }
-            
-            // get the property value directly or from an ogc:propertyName,
-            // ogc:Literal or any other property at the level of the property
-            // node, eg.:
-            // <sld:Opacity>0.5</sld:Opacity>
-            if (!attributeName) {
-                var result = this.parseParameter(propertyNode);
-            }
-        }
-        
-        // adjust the result to be a trimmed string or a number
-        if (result) {
-            result = OpenLayers.String.trim(result);
-            if (!isNaN(result)) {
-                result = parseFloat(result);
-            }
-        }
-        
-        return result;
-    },
-    
-    /**
-     * Method: parseParameter
-     * parses a property for propertyNames, Literals and textContent and
-     * creates the according value string.
-     * 
-     * Parameters:
-     * xmlNode - {<DOMElement>}
-     * 
-     * Returns:
-     * {String} a string holding a value suitable for OpenLayers.Style.value
+     * {Object} An object representing the SLD.
      */
-    parseParameter: function(xmlNode) {
-        if (!xmlNode) {
-            return null;
+    read: function(data) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
         }
-        var childNodes = xmlNode.childNodes;
-        if (!childNodes) {
-            return null;
-        }
-
-        var value = new Array(childNodes.length);
-        for (var i=0; i<childNodes.length; i++) {
-            if (childNodes[i].nodeName.indexOf("Literal") != -1) {
-                value[i] = this.getChildValue(childNodes[i]);
-            } else
-            if (childNodes[i].nodeName.indexOf("propertyName") != -1) {
-                value[i] = "${" + this.getChildValue(childNodes[i]) + "}";
-            } else
-            if (childNodes[i].nodeType == 3) {
-                value[i] = childNodes[i].text || childNodes[i].textContent;
+        var root = data.documentElement;
+        var version = this.version;
+        if(!version) {
+            version = root.getAttribute("version");
+            if(!version) {
+                version = this.defaultVersion;
             }
         }
-        return value.join("");
-    },
-        
-    /**
-     * Method: getNodeWithAttribute
-     * Walks through a list of xml nodes and returns the fist node that has an
-     * attribute with the name and optional value specified.
-     * 
-     * Parameters:
-     * xmlNodeList    - {Array(<DOMElement>)} list to search
-     * attributeName  - {String} name of the attribute to match
-     * attributeValue - {String} optional value of the attribute
-     */
-    getNodeWithAttribute: function(xmlNodeList, attributeName, attributeValue) {
-        for (var i=0; i<xmlNodeList.length; i++) {
-            var currentAttributeValue =
-                    xmlNodeList[i].getAttribute(attributeName);
-            if (currentAttributeValue) {
-                if (!attributeValue) {
-                    return xmlNodeList[i];
-                } else if (currentAttributeValue == attributeValue) {
-                    return xmlNodeList[i];
-                }
+        if(!this.parser || this.parser.VERSION != version) {
+            var format = OpenLayers.Format.SLD[
+                "v" + version.replace(/\./g, "_")
+            ];
+            if(!format) {
+                throw "Can't find a SLD parser for version " +
+                      version;
             }
+            this.parser = new format(this.options);
         }
+        var sld = this.parser.read(data);
+        return sld;
     },
-    
-    /**
-     * Constant: TYPES
-     * {Object} Mapping between SLD rule names and rule type constants.
-     * 
-     */
-    TYPES: {'PropertyIsEqualTo': 'EQUAL_TO',
-            'PropertyIsNotEqualTo': 'NOT_EQUAL_TO',
-            'PropertyIsLessThan': 'LESS_THAN',
-            'PropertyIsGreaterThan': 'GREATER_THAN',
-            'PropertyIsLessThanOrEqualTo': 'LESS_THAN_OR_EQUAL_TO',
-            'PropertyIsGreaterThanOrEqualTo': 'GREATER_THAN_OR_EQUAL_TO',
-            'PropertyIsBetween': 'BETWEEN',
-            'PropertyIsLike': 'LIKE'},
 
     CLASS_NAME: "OpenLayers.Format.SLD" 
 });
@@ -36292,6 +36983,1196 @@
     CLASS_NAME: "OpenLayers.Layer.WFS"
 });
 /* ======================================================================
+    OpenLayers/Format/SLD/v1.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/SLD.js
+ */
+
+/**
+ * Class: OpenLayers.Format.SLD.v1
+ * Superclass for SLD version 1 parsers.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * Property: namespaces
+     * {Object} Mapping of namespace aliases to namespace URIs.
+     */
+    namespaces: {
+        sld: "http://www.opengis.net/sld",
+        ogc: "http://www.opengis.net/ogc",
+        xlink: "http://www.w3.org/1999/xlink",
+        xsi: "http://www.w3.org/2001/XMLSchema-instance"
+    },
+    
+    /**
+     * Property: defaultPrefix
+     */
+    defaultPrefix: "sld",
+
+    /**
+     * Property: schemaLocation
+     * {String} Schema location for a particular minor version.
+     */
+    schemaLocation: null,
+
+    /**
+     * APIProperty: defaultSymbolizer.
+     * {Object} A symbolizer with the SLD defaults.
+     */
+    defaultSymbolizer: {
+        fillColor: "#808080",
+        fillOpacity: 1,
+        strokeColor: "#000000",
+        strokeOpacity: 1,
+        strokeWidth: 1,
+        pointRadius: 6
+    },
+    
+    /**
+     * Constructor: OpenLayers.Format.SLD.v1
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.SLD> constructor instead.
+     *
+     * 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]);
+    },
+    
+    /**
+     * Method: read
+     *
+     * Parameters:
+     * data - {DOMElement} An SLD document element.
+     *
+     * Returns:
+     * {Object} An object representing the SLD.
+     */
+    read: function(data) {        
+        var sld = {
+            namedLayers: {}
+        };
+        this.readChildNodes(data, sld);
+        return sld;
+    },
+    
+    /**
+     * 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: {
+        "sld": {
+            "StyledLayerDescriptor": function(node, sld) {
+                sld.version = node.getAttribute("version");
+                this.readChildNodes(node, sld);
+            },
+            "Name": function(node, obj) {
+                obj.name = this.getChildValue(node);
+            },
+            "Title": function(node, obj) {
+                obj.title = this.getChildValue(node);
+            },
+            "Abstract": function(node, obj) {
+                obj.description = this.getChildValue(node);
+            },
+            "NamedLayer": function(node, sld) {
+                var layer = {
+                    userStyles: [],
+                    namedStyles: []
+                };
+                this.readChildNodes(node, layer);
+                // give each of the user styles this layer name
+                for(var i=0; i<layer.userStyles.length; ++i) {
+                    layer.userStyles[i].layerName = layer.name;
+                }
+                sld.namedLayers[layer.name] = layer;
+            },
+            "NamedStyle": function(node, layer) {
+                layer.namedStyles.push(
+                    this.getChildName(node.firstChild)
+                );
+            },
+            "UserStyle": function(node, layer) {
+                var style = new OpenLayers.Style(this.defaultSymbolizer);
+                this.readChildNodes(node, style);
+                layer.userStyles.push(style);
+            },
+            "IsDefault": function(node, style) {
+                if(this.getChildValue(node) == "1") {
+                    style.isDefault = true;
+                }
+            },
+            "FeatureTypeStyle": function(node, style) {
+                // OpenLayers doesn't have a place for FeatureTypeStyle
+                // Name, Title, Abstract, FeatureTypeName, or
+                // SemanticTypeIdentifier so, we make a temporary object
+                // and later just use the Rule(s).
+                var obj = {
+                    rules: []
+                };
+                this.readChildNodes(node, obj);
+                style.rules = obj.rules;
+            },
+            "Rule": function(node, obj) {
+                // Rule elements are represented as OpenLayers.Rule instances.
+                // Filter elements are represented as instances of
+                // OpenLayers.Rule subclasses.
+                var config = {
+                    rules: [],
+                    symbolizer: {}
+                };
+                this.readChildNodes(node, config);
+                // Now we've either got zero or one rules (from filters)
+                var rule;
+                if(config.rules.length == 0) {
+                    delete config.rules;
+                    rule = new OpenLayers.Rule(config);
+                } else {
+                    rule = config.rules[0];
+                    delete config.rules;
+                    OpenLayers.Util.extend(rule, config);
+                }
+                obj.rules.push(rule);
+            },
+            "ElseFilter": function(node, rule) {
+                rule.elseFilter = true;
+            },
+            "MinScaleDenominator": function(node, rule) {
+                rule.minScaleDenominator = this.getChildValue(node);
+            },
+            "MaxScaleDenominator": function(node, rule) {
+                rule.maxScaleDenominator = this.getChildValue(node);
+            },
+            "LineSymbolizer": function(node, rule) {
+                // OpenLayers doens't do painter's order, instead we extend
+                var symbolizer = rule.symbolizer["Line"] || {};
+                this.readChildNodes(node, symbolizer);
+                // in case it didn't exist before
+                rule.symbolizer["Line"] = symbolizer;
+            },
+            "PolygonSymbolizer": function(node, rule) {
+                // OpenLayers doens't do painter's order, instead we extend
+                var symbolizer = rule.symbolizer["Polygon"] || {};
+                this.readChildNodes(node, symbolizer);
+                // in case it didn't exist before
+                rule.symbolizer["Polygon"] = symbolizer;
+            },
+            "PointSymbolizer": function(node, rule) {
+                // OpenLayers doens't do painter's order, instead we extend
+                var symbolizer = rule.symbolizer["Point"] || {};
+                this.readChildNodes(node, symbolizer);
+                // in case it didn't exist before
+                rule.symbolizer["Point"] = symbolizer;
+            },
+            "Stroke": function(node, symbolizer) {
+                this.readChildNodes(node, symbolizer);
+            },
+            "Fill": function(node, symbolizer) {
+                this.readChildNodes(node, symbolizer);
+            },
+            "CssParameter": function(node, symbolizer) {
+                var cssProperty = node.getAttribute("name");
+                var symProperty = this.cssMap[cssProperty];
+                if(symProperty) {
+                    // Limited support for parsing of OGC expressions
+                    var value = this.readOgcExpression(node);
+                    // always string, could be an empty string
+                    if(value) {
+                        symbolizer[symProperty] = value;
+                    }
+                }
+            },
+            "Graphic": function(node, symbolizer) {
+                var graphic = {};
+                // painter's order not respected here, clobber previous with next
+                this.readChildNodes(node, graphic);
+                // directly properties with names that match symbolizer properties
+                var properties = [
+                    "strokeColor", "strokeWidth", "strokeOpacity",
+                    "strokeLinecap", "fillColor", "fillOpacity",
+                    "graphicName", "rotation", "graphicFormat"
+                ];
+                var prop, value;
+                for(var i=0; i<properties.length; ++i) {
+                    prop = properties[i];
+                    value = graphic[prop];
+                    if(value != undefined) {
+                        symbolizer[prop] = value;
+                    }
+                }
+                // set other generic properties with specific graphic property names
+                if(graphic.opacity != undefined) {
+                    symbolizer.graphicOpacity = graphic.opacity;
+                }
+                if(graphic.size != undefined) {
+                    symbolizer.pointRadius = graphic.size;
+                }
+                if(graphic.href != undefined) {
+                    symbolizer.externalGraphic = graphic.href;
+                }
+            },
+            "ExternalGraphic": function(node, graphic) {
+                this.readChildNodes(node, graphic);
+            },
+            "Mark": function(node, graphic) {
+                this.readChildNodes(node, graphic);
+            },
+            "WellKnownName": function(node, graphic) {
+                graphic.graphicName = this.getChildValue(node);
+            },
+            "Opacity": function(node, obj) {
+                // No support for parsing of OGC expressions
+                var opacity = this.getChildValue(node);
+                // always string, could be empty string
+                if(opacity) {
+                    obj.opacity = opacity;
+                }
+            },
+            "Size": function(node, obj) {
+                // No support for parsing of OGC expressions
+                var size = this.getChildValue(node);
+                // always string, could be empty string
+                if(size) {
+                    obj.size = size;
+                }
+            },
+            "Rotation": function(node, obj) {
+                // No support for parsing of OGC expressions
+                var rotation = this.getChildValue(node);
+                // always string, could be empty string
+                if(rotation) {
+                    obj.rotation = rotation;
+                }
+            },
+            "OnlineResource": function(node, obj) {
+                obj.href = this.getAttributeNS(
+                    node, this.namespaces.xlink, "href"
+                );
+            },
+            "Format": function(node, graphic) {
+                graphic.graphicFormat = this.getChildValue(node);
+            }
+        },
+        "ogc": {
+            "Filter": function(node, rule) {
+                // Filters correspond to subclasses of OpenLayers.Rule.
+                // Since they contain information we don't persist, we
+                // create a temporary object and then pass on the rules
+                // (ogc:Filter) to the parent rule (sld:Rule).
+                var filter = {
+                    fids: [],
+                    rules: []
+                };
+                this.readChildNodes(node, filter);
+                if(filter.fids.length > 0) {
+                    rule.rules.push(new OpenLayers.Rule.FeatureId({
+                        fids: filter.fids
+                    }));
+                }
+                if(filter.rules.length > 0) {
+                    rule.rules = rule.rules.concat(filter.rules);
+                }
+            },
+            "FeatureId": function(node, filter) {
+                var fid = node.getAttribute("fid");
+                if(fid) {
+                    filter.fids.push(fid);
+                }
+            },
+            "And": function(node, filter) {
+                var rule = new OpenLayers.Rule.Logical({
+                    type: OpenLayers.Rule.Logical.AND
+                });
+                // since FeatureId rules may be nested here, make room for them
+                rule.fids = [];
+                this.readChildNodes(node, rule);
+                if(rule.fids.length > 0) {
+                    rule.rules.push(new OpenLayers.Rule.FeatureId({
+                        fids: rule.fids
+                    }));
+                }
+                delete rule.fids;
+                filter.rules.push(rule);
+            },
+            "Or": function(node, filter) {
+                var rule = new OpenLayers.Rule.Logical({
+                    type: OpenLayers.Rule.Logical.OR
+                });
+                // since FeatureId rules may be nested here, make room for them
+                rule.fids = [];
+                this.readChildNodes(node, rule);
+                if(rule.fids.length > 0) {
+                    rule.rules.push(new OpenLayers.Rule.FeatureId({
+                        fids: rule.fids
+                    }));
+                }
+                delete rule.fids;
+                filter.rules.push(rule);
+            },
+            "Not": function(node, filter) {
+                var rule = new OpenLayers.Rule.Logical({
+                    type: OpenLayers.Rule.Logical.NOT
+                });
+                // since FeatureId rules may be nested here, make room for them
+                rule.fids = [];
+                this.readChildNodes(node, rule);
+                if(rule.fids.length > 0) {
+                    rule.rules.push(new OpenLayers.Rule.FeatureId({
+                        fids: rule.fids
+                    }));
+                }
+                delete rule.fids;
+                filter.rules.push(rule);
+            },
+            "PropertyIsEqualTo": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.EQUAL_TO
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsNotEqualTo": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.NOT_EQUAL_TO
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsLessThan": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.LESS_THAN
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsGreaterThan": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.GREATER_THAN
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsLessThanOrEqualTo": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsGreaterThanOrEqualTo": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsBetween": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.BETWEEN
+                });
+                this.readChildNodes(node, rule);
+                filter.rules.push(rule);
+            },
+            "PropertyIsLike": function(node, filter) {
+                var rule = new OpenLayers.Rule.Comparison({
+                    type: OpenLayers.Rule.Comparison.LIKE
+                });
+                this.readChildNodes(node, rule);
+                var wildCard = node.getAttribute("wildCard");
+                var singleChar = node.getAttribute("singleChar");
+                var esc = node.getAttribute("escape");
+                rule.value2regex(wildCard, singleChar, esc);
+                filter.rules.push(rule);
+            },
+            "Literal": function(node, obj) {
+                obj.value = this.getChildValue(node);
+            },
+            "PropertyName": function(node, rule) {
+                rule.property = this.getChildValue(node);
+            },
+            "LowerBoundary": function(node, rule) {
+                rule.lowerBoundary = this.readOgcExpression(node);
+            },
+            "UpperBoundary": function(node, rule) {
+                rule.upperBoundary = this.readOgcExpression(node);
+            }
+        }
+    },
+    
+    /**
+     * Method: readOgcExpression
+     * Limited support for OGC expressions.
+     *
+     * Parameters:
+     * node - {DOMElement} A DOM element that contains an ogc:expression.
+     *
+     * Returns:
+     * {String} A value to be used in a symbolizer.
+     */
+    readOgcExpression: function(node) {
+        var obj = {};
+        this.readChildNodes(node, obj);
+        var value = obj.value;
+        if(!value) {
+            value = this.getChildValue(node);
+        }
+        return value;
+    },
+    
+    /**
+     * Property: cssMap
+     * {Object} Object mapping supported css property names to OpenLayers
+     *     symbolizer property names.
+     */
+    cssMap: {
+        "stroke": "strokeColor",
+        "stroke-opacity": "strokeOpacity",
+        "stroke-width": "strokeWidth",
+        "stroke-linecap": "strokeLinecap",
+        "fill": "fillColor",
+        "fill-opacity": "fillOpacity"
+    },
+    
+    /**
+     * Method: getCssProperty
+     * Given a symbolizer property, get the corresponding CSS property
+     *     from the <cssMap>.
+     *
+     * Parameters:
+     * sym - {String} A symbolizer property name.
+     *
+     * Returns:
+     * {String} A CSS property name or null if none found.
+     */
+    getCssProperty: function(sym) {
+        var css = null;
+        for(var prop in this.cssMap) {
+            if(this.cssMap[prop] == sym) {
+                css = prop;
+                break;
+            }
+        }
+        return css;
+    },
+    
+    /**
+     * Method: getGraphicFormat
+     * Given a href for an external graphic, try to determine the mime-type.
+     *     This method doesn't try too hard, and will fall back to
+     *     <defautlGraphicFormat> if one of the known <graphicFormats> is not
+     *     the file extension of the provided href.
+     *
+     * Parameters:
+     * href - {String}
+     *
+     * Returns:
+     * {String} The graphic format.
+     */
+    getGraphicFormat: function(href) {
+        var format, regex;
+        for(var key in this.graphicFormats) {
+            if(this.graphicFormats[key].test(href)) {
+                format = key;
+                break;
+            }
+        }
+        return format || this.defautlGraphicFormat;
+    },
+    
+    /**
+     * Property: defaultGraphicFormat
+     * {String} If none other can be determined from <getGraphicFormat>, this
+     *     default will be returned.
+     */
+    defaultGraphicFormat: "image/png",
+    
+    /**
+     * Property: graphicFormats
+     * {Object} Mapping of image mime-types to regular extensions matching 
+     *     well-known file extensions.
+     */
+    graphicFormats: {
+        "image/jpeg": /\.jpe?g$/i,
+        "image/gif": /\.gif$/i,
+        "image/png": /\.png$/i
+    },
+
+    /**
+     * Method: write
+     *
+     * Parameters:
+     * sld - {Object} An object representing the SLD.
+     *
+     * Returns:
+     * {DOMElement} The root of an SLD document.
+     */
+    write: function(sld) {
+        return this.writers.sld.StyledLayerDescriptor.apply(this, [sld]);
+    },
+    
+    /**
+     * 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: {
+        "sld": {
+            "StyledLayerDescriptor": function(sld) {
+                var root = this.createElementNSPlus(
+                    "StyledLayerDescriptor",
+                    {attributes: {
+                        "version": this.VERSION,
+                        "xsi:schemaLocation": this.schemaLocation
+                    }}
+                );
+                // add in optional name
+                if(sld.name) {
+                    this.writeNode(root, "Name", sld.name);
+                }
+                // add in optional title
+                if(sld.title) {
+                    this.writeNode(root, "Title", sld.title);
+                }
+                // add in optional description
+                if(sld.description) {
+                    this.writeNode(root, "Abstract", sld.description);
+                }
+                // add in named layers
+                for(var name in sld.namedLayers) {
+                    this.writeNode(root, "NamedLayer", sld.namedLayers[name]);
+                }
+                return root;
+            },
+            "Name": function(name) {
+                return this.createElementNSPlus("Name", {value: name});
+            },
+            "Title": function(title) {
+                return this.createElementNSPlus("Title", {value: title});
+            },
+            "Abstract": function(description) {
+                return this.createElementNSPlus(
+                    "Abstract", {value: description}
+                );
+            },
+            "NamedLayer": function(layer) {
+                var node = this.createElementNSPlus("NamedLayer");
+
+                // add in required name
+                this.writeNode(node, "Name", layer.name);
+
+                // optional sld:LayerFeatureConstraints here
+
+                // add in named styles
+                if(layer.namedStyles) {
+                    for(var i=0; i<layer.namedStyles.length; ++i) {
+                        this.writeNode(
+                            node, "NamedStyle", layer.namedStyles[i]
+                        );
+                    }
+                }
+                
+                // add in user styles
+                if(layer.userStyles) {
+                    for(var i=0; i<layer.userStyles.length; ++i) {
+                        this.writeNode(
+                            node, "UserStyle", layer.userStyles[i]
+                        );
+                    }
+                }
+                
+                return node;
+            },
+            "NamedStyle": function(name) {
+                var node = this.createElementNSPlus("NamedStyle");
+                this.writeNode(node, "Name", name);
+                return node;
+            },
+            "UserStyle": function(style) {
+                var node = this.createElementNSPlus("UserStyle");
+
+                // add in optional name
+                if(style.name) {
+                    this.writeNode(node, "Name", style.name);
+                }
+                // add in optional title
+                if(style.title) {
+                    this.writeNode(node, "Title", style.title);
+                }
+                // add in optional description
+                if(style.description) {
+                    this.writeNode(node, "Abstract", style.description);
+                }
+                
+                // add isdefault
+                if(style.isDefault) {
+                    this.writeNode(node, "IsDefault", style.isDefault);
+                }
+                
+                // add FeatureTypeStyles
+                this.writeNode(node, "FeatureTypeStyle", style);
+                
+                return node;
+            },
+            "IsDefault": function(bool) {
+                return this.createElementNSPlus(
+                    "IsDefault", {value: (bool) ? "1" : "0"}
+                );
+            },
+            "FeatureTypeStyle": function(style) {
+                var node = this.createElementNSPlus("FeatureTypeStyle");
+                
+                // OpenLayers currently stores no Name, Title, Abstract,
+                // FeatureTypeName, or SemanticTypeIdentifier information
+                // related to FeatureTypeStyle
+                
+                // add in rules
+                for(var i=0; i<style.rules.length; ++i) {
+                    this.writeNode(node, "Rule", style.rules[i]);
+                }
+                
+                return node;
+            },
+            "Rule": function(rule) {
+                var node = this.createElementNSPlus("Rule");
+
+                // add in optional name
+                if(rule.name) {
+                    this.writeNode(node, "Name", rule.name);
+                }
+                // add in optional title
+                if(rule.title) {
+                    this.writeNode(node, "Title", rule.title);
+                }
+                // add in optional description
+                if(rule.description) {
+                    this.writeNode(node, "Abstract", rule.description);
+                }
+                
+                // add in LegendGraphic here
+                
+                // add in optional filters
+                if(rule.elseFilter) {
+                    this.writeNode(node, "ElseFilter");
+                } else if(rule.CLASS_NAME != "OpenLayers.Rule") {
+                    this.writeNode(node, "ogc:Filter", rule);
+                }
+                
+                // add in scale limits
+                if(rule.minScaleDenominator != undefined) {
+                    this.writeNode(
+                        node, "MinScaleDenominator", rule.minScaleDenominator
+                    );
+                }
+                if(rule.maxScaleDenominator != undefined) {
+                    this.writeNode(
+                        node, "MaxScaleDenominator", rule.maxScaleDenominator
+                    );
+                }
+                
+                // add in symbolizers (relies on geometry type keys)
+                var types = OpenLayers.Style.SYMBOLIZER_PREFIXES;
+                var type, symbolizer;
+                for(var i=0; i<types.length; ++i) {
+                    type = types[i];
+                    symbolizer = rule.symbolizer[type];
+                    if(symbolizer) {
+                        this.writeNode(
+                            node, type + "Symbolizer", symbolizer
+                        );
+                    }
+                }
+                return node;
+
+            },
+            "ElseFilter": function() {
+                return this.createElementNSPlus("ElseFilter");
+            },
+            "MinScaleDenominator": function(scale) {
+                return this.createElementNSPlus(
+                    "MinScaleDenominator", {value: scale}
+                );
+            },
+            "MaxScaleDenominator": function(scale) {
+                return this.createElementNSPlus(
+                    "MaxScaleDenominator", {value: scale}
+                );
+            },
+            "LineSymbolizer": function(symbolizer) {
+                var node = this.createElementNSPlus("LineSymbolizer");
+                this.writeNode(node, "Stroke", symbolizer);
+                return node;
+            },
+            "Stroke": function(symbolizer) {
+                var node = this.createElementNSPlus("Stroke");
+
+                // GraphicFill here
+                // GraphicStroke here
+
+                // add in CssParameters
+                if(symbolizer.strokeColor != undefined) {
+                    this.writeNode(
+                        node, "CssParameter",
+                        {symbolizer: symbolizer, key: "strokeColor"}
+                    );
+                }
+                if(symbolizer.strokeOpacity != undefined) {
+                    this.writeNode(
+                        node, "CssParameter",
+                        {symbolizer: symbolizer, key: "strokeOpacity"}
+                    );
+                }
+                if(symbolizer.strokeWidth != undefined) {
+                    this.writeNode(
+                        node, "CssParameter",
+                        {symbolizer: symbolizer, key: "strokeWidth"}
+                    );
+                }
+                return node;
+            },
+            "CssParameter": function(obj) {
+                // not handling ogc:expressions for now
+                return this.createElementNSPlus("CssParameter", {
+                    attributes: {name: this.getCssProperty(obj.key)},
+                    value: obj.symbolizer[obj.key]
+                });
+            },
+            "PolygonSymbolizer": function(symbolizer) {
+                var node = this.createElementNSPlus("PolygonSymbolizer");
+                this.writeNode(node, "Fill", symbolizer);
+                this.writeNode(node, "Stroke", symbolizer);
+                return node;
+            },
+            "Fill": function(symbolizer) {
+                var node = this.createElementNSPlus("Fill");
+                
+                // GraphicFill here
+                
+                // add in CssParameters
+                if(symbolizer.fillColor) {
+                    this.writeNode(
+                        node, "CssParameter",
+                        {symbolizer: symbolizer, key: "fillColor"}
+                    );
+                }
+                if(symbolizer.fillOpacity) {
+                    this.writeNode(
+                        node, "CssParameter",
+                        {symbolizer: symbolizer, key: "fillOpacity"}
+                    );
+                }
+                return node;
+            },
+            "PointSymbolizer": function(symbolizer) {
+                var node = this.createElementNSPlus("PointSymbolizer");
+                this.writeNode(node, "Graphic", symbolizer);
+                return node;
+            },
+            "Graphic": function(symbolizer) {
+                var node = this.createElementNSPlus("Graphic");
+                if(symbolizer.externalGraphic != undefined) {
+                    this.writeNode(node, "ExternalGraphic", symbolizer);
+                } else if(symbolizer.graphicName) {
+                    this.writeNode(node, "Mark", symbolizer);
+                }
+                
+                if(symbolizer.graphicOpacity != undefined) {
+                    this.writeNode(node, "Opacity", symbolizer.graphicOpacity);
+                }
+                if(symbolizer.pointRadius != undefined) {
+                    this.writeNode(node, "Size", symbolizer.pointRadius);
+                }
+                if(symbolizer.rotation != undefined) {
+                    this.writeNode(node, "Rotation", symbolizer.rotation);
+                }
+                return node;
+            },
+            "ExternalGraphic": function(symbolizer) {
+                var node = this.createElementNSPlus("ExternalGraphic");
+                this.writeNode(
+                    node, "OnlineResource", symbolizer.externalGraphic
+                );
+                var format = symbolizer.graphicFormat ||
+                             this.getGraphicFormat(symbolizer.externalGraphic);
+                this.writeNode(node, "Format", format);
+                return node;
+            },
+            "Mark": function(symbolizer) {
+                var node = this.createElementNSPlus("Mark");
+                this.writeNode(node, "WellKnownName", symbolizer.graphicName);
+                this.writeNode(node, "Fill", symbolizer);
+                this.writeNode(node, "Stroke", symbolizer);
+                return node;
+            },
+            "WellKnownName": function(name) {
+                return this.createElementNSPlus("WellKnownName", {
+                    value: name
+                });
+            },
+            "Opacity": function(value) {
+                return this.createElementNSPlus("Opacity", {
+                    value: value
+                });
+            },
+            "Size": function(value) {
+                return this.createElementNSPlus("Size", {
+                    value: value
+                });
+            },
+            "Rotation": function(value) {
+                return this.createElementNSPlus("Rotation", {
+                    value: value
+                });
+            },
+            "OnlineResource": function(href) {
+                return this.createElementNSPlus("OnlineResource", {
+                    attributes: {
+                        "xlink:type": "simple",
+                        "xlink:href": href
+                    }
+                });
+            },
+            "Format": function(format) {
+                return this.createElementNSPlus("Format", {
+                    value: format
+                });
+            }
+        },
+        "ogc": {
+            "Filter": function(rule) {
+                var node = this.createElementNSPlus("ogc:Filter");
+                var sub = rule.CLASS_NAME.split(".").pop();
+                if(sub == "FeatureId") {
+                    for(var i=0; i<rule.fids.length; ++i) {
+                        this.writeNode(node, "FeatureId", rule.fids[i]);
+                    }
+                } else {
+                    this.writeNode(node, this.getFilterType(rule), rule);
+                }
+                return node;
+            },
+            "FeatureId": function(fid) {
+                return this.createElementNSPlus("ogc:FeatureId", {
+                    attributes: {fid: fid}
+                });
+            },
+            "And": function(rule) {
+                var node = this.createElementNSPlus("ogc:And");
+                var childRule;
+                for(var i=0; i<rule.rules.length; ++i) {
+                    childRule = rule.rules[i];
+                    this.writeNode(
+                        node, this.getFilterType(childRule), childRule
+                    );
+                }
+                return node;
+            },
+            "Or": function(rule) {
+                var node = this.createElementNSPlus("ogc:Or");
+                var childRule;
+                for(var i=0; i<rule.rules.length; ++i) {
+                    childRule = rule.rules[i];
+                    this.writeNode(
+                        node, this.getFilterType(childRule), childRule
+                    );
+                }
+                return node;
+            },
+            "Not": function(rule) {
+                var node = this.createElementNSPlus("ogc:Not");
+                var childRule = rule.rules[0];
+                this.writeNode(
+                    node, this.getFilterType(childRule), childRule
+                );
+                return node;
+            },
+            "PropertyIsEqualTo": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsEqualTo");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);
+                return node;
+            },
+            "PropertyIsNotEqualTo": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);
+                return node;
+            },
+            "PropertyIsLessThan": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsLessThan");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);                
+                return node;
+            },
+            "PropertyIsGreaterThan": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsGreaterThan");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);
+                return node;
+            },
+            "PropertyIsLessThanOrEqualTo": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);
+                return node;
+            },
+            "PropertyIsGreaterThanOrEqualTo": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "Literal", rule);
+                return node;
+            },
+            "PropertyIsBetween": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsBetween");
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                this.writeNode(node, "LowerBoundary", rule);
+                this.writeNode(node, "UpperBoundary", rule);
+                return node;
+            },
+            "PropertyIsLike": function(rule) {
+                var node = this.createElementNSPlus("ogc:PropertyIsLike", {
+                    attributes: {
+                        wildCard: "*", singleChar: ".", escape: "!"
+                    }
+                });
+                // no ogc:expression handling for now
+                this.writeNode(node, "PropertyName", rule);
+                // convert regex string to ogc string
+                this.writeNode(node, "Literal", {value: rule.regex2value()});
+                return node;
+            },
+            "PropertyName": function(rule) {
+                // no ogc:expression handling for now
+                return this.createElementNSPlus("ogc:PropertyName", {
+                    value: rule.property
+                });
+            },
+            "Literal": function(rule) {
+                // no ogc:expression handling for now
+                return this.createElementNSPlus("ogc:Literal", {
+                    value: rule.value
+                });
+            },
+            "LowerBoundary": function(rule) {
+                // no ogc:expression handling for now
+                var node = this.createElementNSPlus("ogc:LowerBoundary");
+                this.writeNode(node, "Literal", rule.lowerBoundary);
+                return node;
+            },
+            "UpperBoundary": function(rule) {
+                // no ogc:expression handling for now
+                var node = this.createElementNSPlus("ogc:UpperBoundary");
+                this.writeNode(node, "Literal", rule.upperBoundary);
+                return node;
+            }
+        }
+    },
+    
+    /**
+     * Method: getFilterType
+     */
+    getFilterType: function(rule) {
+        var filterType = this.filterMap[rule.type];
+        if(!filterType) {
+            throw "SLD writing not supported for rule type: " + rule.type;
+        }
+        return filterType;
+    },
+    
+    /**
+     * Property: filterMap
+     * {Object} Contains a member for each rule type.  Values are node names
+     *     for corresponding OGC Filter child elements.
+     */
+    filterMap: {
+        "&&": "And",
+        "||": "Or",
+        "!": "Not",
+        "==": "PropertyIsEqualTo",
+        "!=": "PropertyIsNotEqualTo",
+        "<": "PropertyIsLessThan",
+        ">": "PropertyIsGreaterThan",
+        "<=": "PropertyIsLessThanOrEqualTo",
+        ">=": "PropertyIsGreaterThanOrEqualTo",
+        "..": "PropertyIsBetween",
+        "~": "PropertyIsLike"
+    },
+    
+
+    /**
+     * Methods below this point are of general use for versioned XML parsers.
+     * These are candidates for an abstract class.
+     */
+    
+    /**
+     * Method: getNamespacePrefix
+     * Get the namespace prefix for a given uri from the <namespaces> object.
+     *
+     * Returns:
+     * {String} A namespace prefix or null if none found.
+     */
+    getNamespacePrefix: function(uri) {
+        var prefix = null;
+        if(uri == null) {
+            prefix = this.namespaces[this.defaultPrefix];
+        } else {
+            var gotPrefix = false;
+            for(prefix in this.namespaces) {
+                if(this.namespaces[prefix] == uri) {
+                    gotPrefix = true;
+                    break;
+                }
+            }
+            if(!gotPrefix) {
+                prefix = null;
+            }
+        }
+        return prefix;
+    },
+
+
+    /**
+     * Method: readChildNodes
+     */
+    readChildNodes: function(node, obj) {
+        var children = node.childNodes;
+        var child, group, reader, prefix, local;
+        for(var i=0; i<children.length; ++i) {
+            child = children[i];
+            if(child.nodeType == 1) {
+                prefix = this.getNamespacePrefix(child.namespaceURI);
+                local = child.nodeName.split(":").pop();
+                group = this.readers[prefix];
+                if(group) {
+                    reader = group[local];
+                    if(reader) {
+                        reader.apply(this, [child, 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:
+     * parent - {DOMElement} Result will be appended to this node.
+     * 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.
+     * obj - {Object} Structure containing data for the writer.
+     *
+     * Returns:
+     * {DOMElement} The child node.
+     */
+    writeNode: function(parent, name, obj) {
+        var prefix, local;
+        var split = name.indexOf(":");
+        if(split > 0) {
+            prefix = name.substring(0, split);
+            local = name.substring(split + 1);
+        } else {
+            prefix = this.getNamespacePrefix(parent.namespaceURI);
+            local = name;
+        }
+        var child = this.writers[prefix][local].apply(this, [obj]);
+        parent.appendChild(child);
+        return child;
+    },
+    
+    /**
+     * 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.
+     *
+     * Returns:
+     * {Element} An element node.
+     */
+    createElementNSPlus: function(name, options) {
+        options = options || {};
+        var loc = name.indexOf(":");
+        // 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) {
+            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);
+        }
+        if(options.value) {
+            node.appendChild(this.createTextNode(options.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, loc, alias, uri;
+        for(var name in obj) {
+            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);
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Format.SLD.v1" 
+
+});
+/* ======================================================================
     OpenLayers/Geometry/Curve.js
    ====================================================================== */
 
@@ -36352,6 +38233,59 @@
     CLASS_NAME: "OpenLayers.Geometry.Curve"
 });
 /* ======================================================================
+    OpenLayers/Format/SLD/v1_0_0.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/SLD/v1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.SLD.v1_0_0
+ * Write SLD version 1.0.0.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.SLD.v1>
+ */
+OpenLayers.Format.SLD.v1_0_0 = OpenLayers.Class(
+    OpenLayers.Format.SLD.v1, {
+    
+    /**
+     * Constant: VERSION
+     * {String} 1.0.0
+     */
+    VERSION: "1.0.0",
+    
+    /**
+     * Property: schemaLocation
+     * {String} http://www.opengis.net/sld
+     *   http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd
+     */
+    schemaLocation: "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd",
+
+    /**
+     * Constructor: OpenLayers.Format.SLD.v1_0_0
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.SLD> constructor instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.SLD.v1.prototype.initialize.apply(
+            this, [options]
+        );
+    },
+
+    CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0" 
+
+});
+/* ======================================================================
     OpenLayers/Geometry/LineString.js
    ====================================================================== */
 
@@ -36494,14 +38428,14 @@
                     y1: point1.y,
                     x2: point2.x,
                     y2: point2.y
-                }
+                };
             } else {
                 segments[i] = {
                     x1: point2.x,
                     y1: point2.y,
                     x2: point1.x,
                     y2: point1.y
-                }
+                };
             }
         }
         // more efficient to define this somewhere static
@@ -39305,7 +41239,7 @@
                         var name = (child.prefix) ?
                                 child.nodeName.split(":")[1] :
                                 child.nodeName;
-                        var value = OpenLayers.Util.getXmlNodeValue(grandchild)
+                        var value = OpenLayers.Util.getXmlNodeValue(grandchild);
                         if (value) {
                             value = value.replace(this.regExes.trimSpace, "");
                             attributes[name] = value;
@@ -39972,7 +41906,7 @@
     createFeatureNodes: function(feature) {
         var nodes = [];
         var className = feature.geometry.CLASS_NAME;
-        var type = className.substring(className.lastIndexOf(".") + 1)
+        var type = className.substring(className.lastIndexOf(".") + 1);
         type = type.toLowerCase();
         var builder = this.createXML[type];
         if (builder) {



More information about the fusion-commits mailing list